Gen. Abstract*ModuleFactory with WORKING handleChangedClass()
[controller.git] / opendaylight / config / yang-jmx-generator-plugin / src / main / java / org / opendaylight / controller / config / yangjmxgenerator / plugin / gofactory / AbsFactoryGeneratedObjectFactory.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
9 package org.opendaylight.controller.config.yangjmxgenerator.plugin.gofactory;
10
11 import static java.lang.String.format;
12
13 import com.google.common.base.Optional;
14 import java.util.ArrayList;
15 import java.util.List;
16 import org.opendaylight.controller.config.api.DependencyResolver;
17 import org.opendaylight.controller.config.api.DynamicMBeanWithInstance;
18 import org.opendaylight.controller.config.api.ModuleIdentifier;
19 import org.opendaylight.controller.config.api.annotations.AbstractServiceInterface;
20 import org.opendaylight.controller.config.api.annotations.Description;
21 import org.opendaylight.controller.config.spi.Module;
22 import org.opendaylight.controller.config.spi.ModuleFactory;
23 import org.opendaylight.controller.config.yangjmxgenerator.ModuleMXBeanEntry;
24 import org.opendaylight.controller.config.yangjmxgenerator.plugin.ftl.AbstractFactoryTemplate;
25 import org.opendaylight.controller.config.yangjmxgenerator.plugin.ftl.TemplateFactory;
26 import org.opendaylight.controller.config.yangjmxgenerator.plugin.ftl.model.Annotation;
27 import org.opendaylight.controller.config.yangjmxgenerator.plugin.ftl.model.Field;
28 import org.opendaylight.controller.config.yangjmxgenerator.plugin.java.FullyQualifiedName;
29 import org.opendaylight.controller.config.yangjmxgenerator.plugin.java.GeneratedObject;
30 import org.opendaylight.controller.config.yangjmxgenerator.plugin.java.GeneratedObjectBuilder;
31 import org.opendaylight.controller.config.yangjmxgenerator.plugin.java.JavaFileInputBuilder;
32 import org.opendaylight.controller.config.yangjmxgenerator.plugin.java.TypeName;
33 import org.opendaylight.yangtools.yang.common.QName;
34
35 public class AbsFactoryGeneratedObjectFactory {
36     private static final String BUNDLE_CONTEXT = "org.osgi.framework.BundleContext";
37
38     public GeneratedObject toGeneratedObject(ModuleMXBeanEntry mbe, Optional<String> copyright) {
39         FullyQualifiedName absFactoryFQN = new FullyQualifiedName(mbe.getPackageName(), mbe.getAbstractFactoryName());
40         FullyQualifiedName moduleFQN = new FullyQualifiedName(mbe.getPackageName(), mbe.getStubModuleName());
41         Optional<String> classJavaDoc = Optional.fromNullable(mbe.getNullableDescription());
42
43         AbstractFactoryTemplate abstractFactoryTemplate = TemplateFactory.abstractFactoryTemplateFromMbe(mbe);
44         Optional<String> header = abstractFactoryTemplate.getHeaderString();
45
46         List<FullyQualifiedName> providedServices = new ArrayList<>();
47         for(String providedService: mbe.getProvidedServices().keySet()) {
48             providedServices.add(FullyQualifiedName.fromString(providedService));
49         }
50
51         return toGeneratedObject(absFactoryFQN, copyright,
52                 header, classJavaDoc, mbe.getYangModuleQName(),
53                 mbe.getGloballyUniqueName(),
54                 providedServices,
55                 moduleFQN,
56                 abstractFactoryTemplate.getFields());
57     }
58
59     public GeneratedObject toGeneratedObject(FullyQualifiedName absFactoryFQN, Optional<String> copyright,
60                                              Optional<String> header, Optional<String> classJavaDoc, QName yangModuleQName,
61                                              String globallyUniqueName,
62                                              List<FullyQualifiedName> providedServices,
63                                              FullyQualifiedName moduleFQN,
64                                              List<Field> moduleFields) {
65         JavaFileInputBuilder b = new JavaFileInputBuilder();
66
67         b.addImportFQN(new FullyQualifiedName(Module.class));
68         b.addImportFQN(new FullyQualifiedName(ModuleIdentifier.class));
69
70         Annotation moduleQNameAnnotation = Annotation.createModuleQNameANnotation(yangModuleQName);
71         b.addClassAnnotation(moduleQNameAnnotation);
72
73         b.setFqn(absFactoryFQN);
74         b.setTypeName(TypeName.absClassType);
75
76         b.setCopyright(copyright);
77         b.setHeader(header);
78         b.setClassJavaDoc(classJavaDoc);
79         b.addImplementsFQN(new FullyQualifiedName(ModuleFactory.class));
80         if (classJavaDoc.isPresent()) {
81             b.addClassAnnotation(format("@%s(value=\"%s\")", Description.class.getCanonicalName(), classJavaDoc.get()));
82         }
83
84         b.addToBody(format("public static final java.lang.String NAME = \"%s\";", globallyUniqueName));
85         b.addToBody(format("private static final java.util.Set<Class<? extends %s>> serviceIfcs;",
86                 AbstractServiceInterface.class.getCanonicalName()));
87
88         b.addToBody("@Override\n public final String getImplementationName() { \n return NAME; \n}");
89
90         b.addToBody(getServiceIfcsInitialization(providedServices));
91
92         // createModule
93         b.addToBody(format("\n"+
94             "@Override\n"+
95             "public %s createModule(String instanceName, %s dependencyResolver, %s bundleContext) {\n"+
96                 "return instantiateModule(instanceName, dependencyResolver, bundleContext);\n"+
97             "}\n",
98                 Module.class.getCanonicalName(), DependencyResolver.class.getCanonicalName(), BUNDLE_CONTEXT));
99
100         b.addToBody(getCreateModule(moduleFQN, moduleFields));
101
102         b.addToBody(format("\n"+
103             "public %s instantiateModule(String instanceName, %s dependencyResolver, %s oldModule, %s oldInstance, %s bundleContext) {\n"+
104                 "return new %s(new %s(NAME, instanceName), dependencyResolver, oldModule, oldInstance);\n"+
105             "}\n",
106                 moduleFQN, DependencyResolver.class.getCanonicalName(), moduleFQN, AutoCloseable.class.getCanonicalName(),
107                 BUNDLE_CONTEXT, moduleFQN, ModuleIdentifier.class.getCanonicalName()));
108
109         b.addToBody(format("\n"+
110             "public %s instantiateModule(String instanceName, %s dependencyResolver, %s bundleContext) {\n"+
111                 "return new %s(new %s(NAME, instanceName), dependencyResolver);\n"+
112             "}\n", moduleFQN, DependencyResolver.class.getCanonicalName(), BUNDLE_CONTEXT,
113                 moduleFQN, ModuleIdentifier.class.getCanonicalName()
114         ));
115
116         b.addToBody(format("\n"+
117                 "public %s handleChangedClass(%s dependencyResolver, %s old, %s bundleContext) throws Exception {\n" +
118                     // "// @Deprecated return handleChangedClass(old);\n" +
119                     "String instanceName = old.getModule().getIdentifier().getInstanceName();\n" +
120                     "%1$s newModule = new %1$s(new ModuleIdentifier(NAME, instanceName), dependencyResolver);\n" +
121                     "Module oldModule = old.getModule();\n" +
122                     "Class<? extends Module> oldModuleClass = oldModule.getClass();\n" +
123                     genCodeToCopyAttributes(moduleFields) +
124                     "return newModule;\n" +
125                 "}\n", moduleFQN, DependencyResolver.class.getCanonicalName(), DynamicMBeanWithInstance.class.getCanonicalName(), BUNDLE_CONTEXT));
126
127         b.addToBody(format("\n@Deprecated\n"+
128             "public %s handleChangedClass(%s old) throws Exception {\n"+
129                 "throw new UnsupportedOperationException(\"Class reloading is not supported\");\n"+
130             "}\n", moduleFQN, DynamicMBeanWithInstance.class.getCanonicalName()));
131
132         // TODO The generic specifier in HashSet<> isn't necessary, but the Eclipse AST parser used in the unit tests doesn't support this
133         b.addToBody(format("\n"+
134             "@Override\n"+
135             "public java.util.Set<%s> getDefaultModules(org.opendaylight.controller.config.api.DependencyResolverFactory dependencyResolverFactory, %s bundleContext) {\n"+
136                 "return new java.util.HashSet<%1$s>();\n"+
137             "}\n", moduleFQN, BUNDLE_CONTEXT));
138
139         return new GeneratedObjectBuilder(b.build()).toGeneratedObject();
140     }
141
142     private String genCodeToCopyAttributes(List<Field> moduleFields) {
143         StringBuilder sb = new StringBuilder("\n");
144         for (Field field : moduleFields) {
145             sb.append(format("newModule.set%1$s( (%2$s) oldModuleClass.getMethod(\"get%1$s\").invoke(oldModule));\n", field.getName(), field.getType()));
146         }
147         sb.append('\n');
148         return sb.toString();
149     }
150
151     private static String getCreateModule(FullyQualifiedName moduleFQN, List<Field> moduleFields) {
152         String result = "\n"+
153             "@Override\n"+
154             format("public %s createModule(String instanceName, %s dependencyResolver, %s old, %s bundleContext) throws Exception {\n",
155                                 Module.class.getCanonicalName(), DependencyResolver.class.getCanonicalName(),
156                                 DynamicMBeanWithInstance.class.getCanonicalName(), BUNDLE_CONTEXT)+
157                 format("%s oldModule;\n",moduleFQN)+
158                 "try {\n"+
159                     format("oldModule = (%s) old.getModule();\n", moduleFQN)+
160                 "} catch(Exception e) {\n"+
161                     "return handleChangedClass(dependencyResolver, old, bundleContext);\n"+
162                 "}\n"+
163             format("%s module = instantiateModule(instanceName, dependencyResolver, oldModule, old.getInstance(), bundleContext);\n", moduleFQN);
164
165         for(Field field: moduleFields) {
166             result += format("module.set%s(oldModule.get%1$s());\n", field.getName());
167         }
168
169         result += "\n"+
170                 "return module;\n"+
171             "}\n";
172         return result;
173     }
174
175     private static String getServiceIfcsInitialization(List<FullyQualifiedName> providedServices) {
176         String generic = format("Class<? extends %s>", AbstractServiceInterface.class.getCanonicalName());
177
178         String result = "static {\n";
179         if (!providedServices.isEmpty()) {
180             // TODO The generic specifier in HashSet<> isn't necessary, but the Eclipse AST parser used in the unit tests doesn't support this
181             result += format("java.util.Set<%1$s> serviceIfcs2 = new java.util.HashSet<%1$s>();\n", generic);
182
183             for(FullyQualifiedName fqn: providedServices) {
184                 result += format("serviceIfcs2.add(%s.class);\n", fqn);
185             }
186
187             result += "serviceIfcs = java.util.Collections.unmodifiableSet(serviceIfcs2);\n";
188         } else {
189             result += "serviceIfcs = java.util.Collections.emptySet();\n";
190         }
191         result += "}\n";
192
193         // add isModuleImplementingServiceInterface and getImplementedServiceIntefaces methods
194
195         result += format("\n"+
196             "@Override\n"+
197             "public final boolean isModuleImplementingServiceInterface(Class<? extends %1$s> serviceInterface) {\n"+
198                 "for (Class<?> ifc: serviceIfcs) {\n"+
199                     "if (serviceInterface.isAssignableFrom(ifc)){\n"+
200                         "return true;\n"+
201                     "}\n"+
202                 "}\n"+
203                 "return false;\n"+
204             "}\n"+
205             "\n"+
206             "@Override\n"+
207             "public java.util.Set<Class<? extends %1$s>> getImplementedServiceIntefaces() {\n"+
208                 "return serviceIfcs;\n"+
209             "}\n", AbstractServiceInterface.class.getCanonicalName());
210
211         return result;
212     }
213
214 }

©2013 OpenDaylight, A Linux Foundation Collaborative Project. All Rights Reserved.
OpenDaylight is a registered trademark of The OpenDaylight Project, Inc.
Linux Foundation and OpenDaylight are registered trademarks of the Linux Foundation.
Linux is a registered trademark of Linus Torvalds.