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.ftl;
10 import static com.google.common.base.Preconditions.checkArgument;
11 import static com.google.common.base.Preconditions.checkState;
12 import static java.lang.String.format;
14 import com.google.common.annotations.VisibleForTesting;
15 import com.google.common.collect.Lists;
16 import java.io.Closeable;
17 import java.util.ArrayList;
18 import java.util.Collection;
19 import java.util.Collections;
20 import java.util.HashMap;
21 import java.util.HashSet;
22 import java.util.LinkedHashMap;
23 import java.util.List;
25 import java.util.Map.Entry;
27 import java.util.concurrent.atomic.AtomicInteger;
28 import org.opendaylight.controller.config.api.runtime.HierarchicalRuntimeBeanRegistration;
29 import org.opendaylight.controller.config.api.runtime.RootRuntimeBeanRegistrator;
30 import org.opendaylight.controller.config.yangjmxgenerator.RuntimeBeanEntry;
31 import org.opendaylight.controller.config.yangjmxgenerator.plugin.ftl.model.Annotation;
32 import org.opendaylight.controller.config.yangjmxgenerator.plugin.ftl.model.Annotation.Parameter;
33 import org.opendaylight.controller.config.yangjmxgenerator.plugin.ftl.model.Field;
34 import org.opendaylight.controller.config.yangjmxgenerator.plugin.ftl.model.MethodDefinition;
35 import org.opendaylight.controller.config.yangjmxgenerator.plugin.util.FullyQualifiedNameHelper;
37 public class RuntimeRegistratorFtlTemplate extends GeneralClassTemplate {
39 private RuntimeRegistratorFtlTemplate(RuntimeBeanEntry runtimeBeanEntry,
40 String name, List<Field> fields, List<MethodDefinition> methods) {
42 super(null, runtimeBeanEntry.getPackageName(), name, Collections
43 .<String> emptyList(), Collections.singletonList(Closeable.class
44 .getCanonicalName()), fields, methods);
47 public static RuntimeBeanEntry findRoot(
48 Collection<RuntimeBeanEntry> runtimeBeanEntries) {
49 RuntimeBeanEntry result = null;
50 for (RuntimeBeanEntry rb : runtimeBeanEntries) {
53 throw new IllegalArgumentException(
54 "More than one root runtime bean found");
62 throw new IllegalArgumentException("No root runtime bean found");
65 private static String constructConstructorBody(
66 List<Field> constructorParameters) {
67 StringBuilder constructorBody = new StringBuilder();
68 for (Field field : constructorParameters) {
69 constructorBody.append("this.");
70 constructorBody.append(field.getName());
71 constructorBody.append("=");
72 constructorBody.append(field.getName());
73 constructorBody.append(";\n");
75 return constructorBody.toString();
78 // TODO Move to factory
80 * Get registrator and n registration ftls where n is equal to total number
81 * of runtime beans in hierarchy.
83 public static Map<String, FtlTemplate> create(RuntimeBeanEntry rootRB) {
84 checkArgument(rootRB.isRoot(), "RuntimeBeanEntry must be root");
85 String registratorName = getJavaNameOfRuntimeRegistrator(rootRB);
86 List<MethodDefinition> methods = new ArrayList<>();
87 Field rootRuntimeBeanRegistratorField = new Field(
88 Lists.newArrayList("final"),
89 RootRuntimeBeanRegistrator.class.getName(),
90 "rootRuntimeBeanRegistrator");
91 List<Field> constructorParameters = Lists
92 .newArrayList(rootRuntimeBeanRegistratorField);
93 String constructorBody = constructConstructorBody(constructorParameters);
94 MethodDefinition constructor = MethodDefinition.createConstructor(
95 registratorName, constructorParameters, constructorBody);
96 methods.add(constructor);
98 LinkedHashMap<String, RuntimeRegistratorFtlTemplate> RuntimeRegistratorFtlTemplates = createRegistrationHierarchy(
99 rootRB, Collections.<String> emptySet());
100 RuntimeRegistratorFtlTemplate rootFtlFile = RuntimeRegistratorFtlTemplates
101 .values().iterator().next();
103 {// add register(rootruntimemxbean)
104 String fullyQualifiedNameOfMXBean = FullyQualifiedNameHelper
105 .getFullyQualifiedName(rootRB.getPackageName(), rootRB.getJavaNameOfRuntimeMXBean());
106 String childRegistratorFQN = rootFtlFile.getFullyQualifiedName();
107 Field rbParameter = new Field(fullyQualifiedNameOfMXBean, "rb");
108 StringBuilder registerBody = new StringBuilder();
109 registerBody.append(format("%s %s = this.%s.registerRoot(%s);\n",
110 HierarchicalRuntimeBeanRegistration.class
111 .getCanonicalName(), hierachicalRegistration
112 .getName(), rootRuntimeBeanRegistratorField
113 .getName(), rbParameter.getName()));
114 registerBody.append(format("return new %s(%s);\n",
115 rootFtlFile.getFullyQualifiedName(),
116 hierachicalRegistration.getName()));
118 MethodDefinition registerMethod = new MethodDefinition(
119 childRegistratorFQN, "register",
120 Collections.singletonList(rbParameter), registerBody.toString());
121 methods.add(registerMethod);
124 MethodDefinition closeRegistrator = createCloseMethodToCloseField(rootRuntimeBeanRegistratorField);
125 methods.add(closeRegistrator);
128 GeneralClassTemplate registrator = new GeneralClassTemplate(null,
129 rootRB.getPackageName(), registratorName,
130 Collections.<String> emptyList(), Collections.singletonList(Closeable.class
131 .getCanonicalName()), constructorParameters, methods);
133 checkState(!RuntimeRegistratorFtlTemplates.containsKey(registrator
134 .getTypeDeclaration().getName()), "Name conflict: "
135 + registrator.getTypeDeclaration().getName());
136 Map<String, FtlTemplate> result = new HashMap<>();
137 result.putAll(RuntimeRegistratorFtlTemplates);
138 result.put(registrator.getTypeDeclaration().getName(), registrator);
142 private static Field hierachicalRegistration = new Field(
143 Lists.newArrayList("final"),
144 HierarchicalRuntimeBeanRegistration.class.getCanonicalName(),
147 // TODO move to factory + RuntimeBeanEntry
149 * Create ftls representing registrations. First registration is represents
152 * @return map containing java class name as key, instance representing the
153 * java file as value.
155 private static LinkedHashMap<String, RuntimeRegistratorFtlTemplate> createRegistrationHierarchy(
156 RuntimeBeanEntry parent, Set<String> occupiedKeys) {
157 LinkedHashMap<String, RuntimeRegistratorFtlTemplate> unorderedResult = new LinkedHashMap<>();
158 List<MethodDefinition> methods = new ArrayList<>();
160 // hierarchy of ON is created as follows:
161 // root RB: <domain>, type=RuntimeBean
162 // 1st RB in hierarchy: <domain>, type=RuntimeBean, <java name of leaf
163 // list>: key or counter
164 // n-th RB in hierarchy has same ON as n-1, with added <java name of
165 // leaf list>: key or counter
166 if (occupiedKeys.contains(parent.getJavaNamePrefix())) {
167 throw new IllegalArgumentException(
168 "Name conflict in runtime bean hierarchy - java name found more than "
169 + "once. Consider using java-name extension. Conflicting name: "
170 + parent.getJavaNamePrefix());
172 Set<String> currentOccupiedKeys = new HashSet<>(occupiedKeys);
173 currentOccupiedKeys.add(parent.getJavaNamePrefix());
175 Field registratorsMapField = new Field(Collections.singletonList("final"),
176 TypeHelper.getGenericType(Map.class, String.class,
177 AtomicInteger.class), "unkeyedMap", "new "
178 + TypeHelper.getGenericType(HashMap.class,
179 String.class, AtomicInteger.class) + "()");
181 // create register methods for children
182 for (RuntimeBeanEntry child : parent.getChildren()) {
183 checkArgument(parent.getPackageName()
184 .equals(child.getPackageName()), "Invalid package name");
186 // call itself recursively to generate child
187 // registrators/registrations
188 LinkedHashMap<String, RuntimeRegistratorFtlTemplate> childRegistratorMap = createRegistrationHierarchy(
189 child, currentOccupiedKeys);
190 for (Entry<String, RuntimeRegistratorFtlTemplate> entry : childRegistratorMap
192 if (unorderedResult.containsKey(entry.getKey())) {
193 throw new IllegalStateException(
194 "Conflicting name found while generating runtime registration:"
197 unorderedResult.put(entry.getKey(), entry.getValue());
200 if (!childRegistratorMap.isEmpty()) {
201 // first entry is the direct descendant according to the create
203 RuntimeRegistratorFtlTemplate childRegistrator = childRegistratorMap
204 .values().iterator().next();
205 StringBuilder body = new StringBuilder();
207 key = child.getJavaNamePrefix();
209 "String key = \"%s\"; //TODO: check for conflicts\n",
212 if (child.getKeyJavaName().isPresent()) {
213 value = "bean.get" + child.getKeyJavaName().get() + "()";
214 value = "String.valueOf(" + value + ")";
216 body.append("java.util.concurrent.atomic.AtomicInteger counter = unkeyedMap.get(key);\n"
217 + "if (counter==null){\n"
218 + "counter = new java.util.concurrent.atomic.AtomicInteger();\n"
219 + "unkeyedMap.put(key, counter);\n" + "}\n");
220 value = "String.valueOf(counter.incrementAndGet())";
222 body.append(format("String value = %s;\n", value));
223 body.append(format("%s r = %s.register(key, value, bean);\n",
224 HierarchicalRuntimeBeanRegistration.class
225 .getCanonicalName(), hierachicalRegistration
227 body.append(format("return new %s(r);",
228 childRegistrator.getFullyQualifiedName()));
230 Field param = new Field(Lists.newArrayList("final"),
231 child.getJavaNameOfRuntimeMXBean(), "bean");
232 MethodDefinition register = new MethodDefinition(
233 Collections.singletonList("synchronized"),
234 childRegistrator.getFullyQualifiedName(), "register",
235 Collections.singletonList(param), Collections.<String> emptyList(),
236 Collections.<Annotation> emptyList(), body.toString());
237 methods.add(register);
242 // create parent registration
243 String createdName = getJavaNameOfRuntimeRegistration(parent.getJavaNamePrefix());
245 List<Field> constructorParameters = Collections.singletonList(hierachicalRegistration);
246 String constructorBody = constructConstructorBody(constructorParameters);
248 MethodDefinition constructor = MethodDefinition.createConstructor(
249 createdName, constructorParameters, constructorBody);
251 MethodDefinition closeRegistrator = createCloseMethodToCloseField(hierachicalRegistration);
252 methods.add(closeRegistrator);
253 methods.add(constructor);
254 List<Field> privateFields = Lists.newArrayList(registratorsMapField);
255 privateFields.addAll(constructorParameters);
257 RuntimeRegistratorFtlTemplate created = new RuntimeRegistratorFtlTemplate(
258 parent, createdName, privateFields, methods);
260 LinkedHashMap<String, RuntimeRegistratorFtlTemplate> result = new LinkedHashMap<>();
261 result.put(created.getTypeDeclaration().getName(), created);
262 checkState(!unorderedResult.containsKey(created.getTypeDeclaration()
263 .getName()), "Naming conflict: "
264 + created.getTypeDeclaration().getName());
265 result.putAll(unorderedResult);
269 private static MethodDefinition createCloseMethodToCloseField(Field field) {
270 String body = field.getName() + ".close();";
271 // TODO Thrown exception breaks build
272 // return new MethodDefinition(Collections.<String> emptyList(), "void",
273 // "close", Collections.<Field> emptyList(),
274 // Arrays.asList(IOException.class.getCanonicalName()),
275 // Collections.<Annotation> emptyList(), body);
276 List<Annotation> annotations = Lists.newArrayList(new Annotation(
277 "Override", Collections.<Parameter> emptyList()));
278 return new MethodDefinition(Collections.<String> emptyList(), "void",
279 "close", Collections.<Field> emptyList(),
280 Collections.<String> emptyList(), annotations, body);
284 public static String getJavaNameOfRuntimeRegistration(String javaNamePrefix) {
285 return javaNamePrefix + "RuntimeRegistration";
288 public static String getJavaNameOfRuntimeRegistrator(RuntimeBeanEntry rootRB) {
289 checkArgument(rootRB.isRoot(), "RuntimeBeanEntry must be root");
290 return rootRB.getJavaNamePrefix() + "RuntimeRegistrator";