String performance and maintenability
[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         b.addToBody(format("\n"+
133             "@Override\n"+
134             "public java.util.Set<%s> getDefaultModules(org.opendaylight.controller.config.api.DependencyResolverFactory dependencyResolverFactory, %s bundleContext) {\n"+
135                 "return new java.util.HashSet<>();\n"+
136             "}\n", moduleFQN, BUNDLE_CONTEXT));
137
138         return new GeneratedObjectBuilder(b.build()).toGeneratedObject();
139     }
140
141     private String genCodeToCopyAttributes(List<Field> moduleFields) {
142         StringBuilder sb = new StringBuilder("\n");
143         for (Field field : moduleFields) {
144             sb.append(format("newModule.set%1$s( (%2$s) oldModuleClass.getMethod(\"get%1$s\").invoke(oldModule));\n", field.getName(), field.getType()));
145         }
146         sb.append('\n');
147         return sb.toString();
148     }
149
150     private static String getCreateModule(FullyQualifiedName moduleFQN, List<Field> moduleFields) {
151         StringBuilder result = new StringBuilder("\n" +
152                 "@Override\n");
153         result.append(
154                 format("public %s createModule(String instanceName, %s dependencyResolver, %s old, %s bundleContext) "
155                                 + "throws Exception {\n",
156                         Module.class.getCanonicalName(), DependencyResolver.class.getCanonicalName(),
157                         DynamicMBeanWithInstance.class.getCanonicalName(), BUNDLE_CONTEXT))
158                 .append(format("%s oldModule;\n", moduleFQN))
159                 .append("try {\n")
160                 .append(format("oldModule = (%s) old.getModule();\n", moduleFQN))
161                 .append("} catch(Exception e) {\n"
162                         + "return handleChangedClass(dependencyResolver, old, bundleContext);\n"
163                         + "}\n")
164                 .append(format("%s module = instantiateModule(instanceName, dependencyResolver, oldModule, old"
165                                 + ".getInstance(), bundleContext);\n",
166                         moduleFQN));
167
168         for (Field field : moduleFields) {
169             result.append(format("module.set%s(oldModule.get%1$s());\n", field.getName()));
170         }
171
172         result.append("\n"
173                 + "return module;\n"
174                 + "}\n");
175         return result.toString();
176     }
177
178     private static String getServiceIfcsInitialization(List<FullyQualifiedName> providedServices) {
179         String generic = format("Class<? extends %s>", AbstractServiceInterface.class.getCanonicalName());
180
181         StringBuilder result = new StringBuilder("static {\n");
182         if (!providedServices.isEmpty()) {
183             result.append(format("java.util.Set<%1$s> serviceIfcs2 = new java.util.HashSet<>();\n", generic));
184
185             for (FullyQualifiedName fqn : providedServices) {
186                 result.append(format("serviceIfcs2.add(%s.class);\n", fqn));
187             }
188
189             result.append("serviceIfcs = java.util.Collections.unmodifiableSet(serviceIfcs2);\n");
190         } else {
191             result.append("serviceIfcs = java.util.Collections.emptySet();\n");
192         }
193         result.append("}\n");
194
195         // add isModuleImplementingServiceInterface and getImplementedServiceIntefaces methods
196
197         result.append(format("\n"
198                 + "@Override\n"
199                 + "public final boolean isModuleImplementingServiceInterface(Class<? extends %1$s> serviceInterface) "
200                 + "{\n"
201                 + "for (Class<?> ifc: serviceIfcs) {\n"
202                 + "if (serviceInterface.isAssignableFrom(ifc)){\n"
203                 + "return true;\n"
204                 + "}\n"
205                 + "}\n"
206                 + "return false;\n"
207                 + "}\n"
208                 + "\n"
209                 + "@Override\n"
210                 + "public java.util.Set<Class<? extends %1$s>> getImplementedServiceIntefaces() {\n"
211                 + "return serviceIfcs;\n"
212                 + "}\n", AbstractServiceInterface.class.getCanonicalName()));
213
214         return result.toString();
215     }
216
217 }