Gen. Abstract*ModuleFactory handleChangedClass() with DependencyResolver
[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         Annotation moduleQNameAnnotation = Annotation.createModuleQNameANnotation(yangModuleQName);
67         b.addClassAnnotation(moduleQNameAnnotation);
68
69         b.setFqn(absFactoryFQN);
70         b.setTypeName(TypeName.absClassType);
71
72         b.setCopyright(copyright);
73         b.setHeader(header);
74         b.setClassJavaDoc(classJavaDoc);
75         b.addImplementsFQN(new FullyQualifiedName(ModuleFactory.class));
76         if (classJavaDoc.isPresent()) {
77             b.addClassAnnotation(format("@%s(value=\"%s\")", Description.class.getCanonicalName(), classJavaDoc.get()));
78         }
79
80         b.addToBody(format("public static final java.lang.String NAME = \"%s\";", globallyUniqueName));
81         b.addToBody(format("private static final java.util.Set<Class<? extends %s>> serviceIfcs;",
82                 AbstractServiceInterface.class.getCanonicalName()));
83
84         b.addToBody("@Override\n public final String getImplementationName() { \n return NAME; \n}");
85
86         b.addToBody(getServiceIfcsInitialization(providedServices));
87
88         // createModule
89         b.addToBody(format("\n"+
90             "@Override\n"+
91             "public %s createModule(String instanceName, %s dependencyResolver, %s bundleContext) {\n"+
92                 "return instantiateModule(instanceName, dependencyResolver, bundleContext);\n"+
93             "}\n",
94                 Module.class.getCanonicalName(), DependencyResolver.class.getCanonicalName(), BUNDLE_CONTEXT));
95
96         b.addToBody(getCreateModule(moduleFQN, moduleFields));
97
98         b.addToBody(format("\n"+
99             "public %s instantiateModule(String instanceName, %s dependencyResolver, %s oldModule, %s oldInstance, %s bundleContext) {\n"+
100                 "return new %s(new %s(NAME, instanceName), dependencyResolver, oldModule, oldInstance);\n"+
101             "}\n",
102                 moduleFQN, DependencyResolver.class.getCanonicalName(), moduleFQN, AutoCloseable.class.getCanonicalName(),
103                 BUNDLE_CONTEXT, moduleFQN, ModuleIdentifier.class.getCanonicalName()));
104
105         b.addToBody(format("\n"+
106             "public %s instantiateModule(String instanceName, %s dependencyResolver, %s bundleContext) {\n"+
107                 "return new %s(new %s(NAME, instanceName), dependencyResolver);\n"+
108             "}\n", moduleFQN, DependencyResolver.class.getCanonicalName(), BUNDLE_CONTEXT,
109                 moduleFQN, ModuleIdentifier.class.getCanonicalName()
110         ));
111
112         b.addToBody(format("\n"+
113                 "public %s handleChangedClass(%s dependencyResolver, %s old, %s bundleContext) throws Exception {\n"+
114                     "return handleChangedClass(old);\n"+
115                 "}\n", moduleFQN, DependencyResolver.class.getCanonicalName(), DynamicMBeanWithInstance.class.getCanonicalName(), BUNDLE_CONTEXT));
116
117         b.addToBody(format("\n@Deprecated\n"+
118             "public %s handleChangedClass(%s old) throws Exception {\n"+
119                 "throw new UnsupportedOperationException(\"Class reloading is not supported\");\n"+
120             "}\n", moduleFQN, DynamicMBeanWithInstance.class.getCanonicalName()));
121
122         // TODO The generic specifier in HashSet<> isn't necessary, but the Eclipse AST parser used in the unit tests doesn't support this
123         b.addToBody(format("\n"+
124             "@Override\n"+
125             "public java.util.Set<%s> getDefaultModules(org.opendaylight.controller.config.api.DependencyResolverFactory dependencyResolverFactory, %s bundleContext) {\n"+
126                 "return new java.util.HashSet<%1$s>();\n"+
127             "}\n", moduleFQN, BUNDLE_CONTEXT));
128
129         return new GeneratedObjectBuilder(b.build()).toGeneratedObject();
130     }
131
132     private static String getCreateModule(FullyQualifiedName moduleFQN, List<Field> moduleFields) {
133         String result = "\n"+
134             "@Override\n"+
135             format("public %s createModule(String instanceName, %s dependencyResolver, %s old, %s bundleContext) throws Exception {\n",
136                                 Module.class.getCanonicalName(), DependencyResolver.class.getCanonicalName(),
137                                 DynamicMBeanWithInstance.class.getCanonicalName(), BUNDLE_CONTEXT)+
138                 format("%s oldModule;\n",moduleFQN)+
139                 "try {\n"+
140                     format("oldModule = (%s) old.getModule();\n", moduleFQN)+
141                 "} catch(Exception e) {\n"+
142                     "return handleChangedClass(dependencyResolver, old, bundleContext);\n"+
143                 "}\n"+
144             format("%s module = instantiateModule(instanceName, dependencyResolver, oldModule, old.getInstance(), bundleContext);\n", moduleFQN);
145
146         for(Field field: moduleFields) {
147             result += format("module.set%s(oldModule.get%1$s());\n", field.getName());
148         }
149
150         result += "\n"+
151                 "return module;\n"+
152             "}\n";
153         return result;
154     }
155
156     private static String getServiceIfcsInitialization(List<FullyQualifiedName> providedServices) {
157         String generic = format("Class<? extends %s>", AbstractServiceInterface.class.getCanonicalName());
158
159         String result = "static {\n";
160         if (!providedServices.isEmpty()) {
161             // TODO The generic specifier in HashSet<> isn't necessary, but the Eclipse AST parser used in the unit tests doesn't support this
162             result += format("java.util.Set<%1$s> serviceIfcs2 = new java.util.HashSet<%1$s>();\n", generic);
163
164             for(FullyQualifiedName fqn: providedServices) {
165                 result += format("serviceIfcs2.add(%s.class);\n", fqn);
166             }
167
168             result += "serviceIfcs = java.util.Collections.unmodifiableSet(serviceIfcs2);\n";
169         } else {
170             result += "serviceIfcs = java.util.Collections.emptySet();\n";
171         }
172         result += "}\n";
173
174         // add isModuleImplementingServiceInterface and getImplementedServiceIntefaces methods
175
176         result += format("\n"+
177             "@Override\n"+
178             "public final boolean isModuleImplementingServiceInterface(Class<? extends %1$s> serviceInterface) {\n"+
179                 "for (Class<?> ifc: serviceIfcs) {\n"+
180                     "if (serviceInterface.isAssignableFrom(ifc)){\n"+
181                         "return true;\n"+
182                     "}\n"+
183                 "}\n"+
184                 "return false;\n"+
185             "}\n"+
186             "\n"+
187             "@Override\n"+
188             "public java.util.Set<Class<? extends %1$s>> getImplementedServiceIntefaces() {\n"+
189                 "return serviceIfcs;\n"+
190             "}\n", AbstractServiceInterface.class.getCanonicalName());
191
192         return result;
193     }
194
195 }