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 java.io.Closeable;
15 import java.util.ArrayList;
16 import java.util.Arrays;
17 import java.util.Collection;
18 import java.util.Collections;
19 import java.util.HashMap;
20 import java.util.HashSet;
21 import java.util.LinkedHashMap;
22 import java.util.List;
24 import java.util.Map.Entry;
26 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 import com.google.common.annotations.VisibleForTesting;
38 import com.google.common.collect.Lists;
40 public class RuntimeRegistratorFtlTemplate extends GeneralClassTemplate {
42 private RuntimeRegistratorFtlTemplate(RuntimeBeanEntry runtimeBeanEntry,
43 String name, List<Field> fields, List<MethodDefinition> methods) {
45 super(null, runtimeBeanEntry.getPackageName(), name, Collections
46 .<String> emptyList(), Arrays.asList(Closeable.class
47 .getCanonicalName()), fields, methods);
50 public static RuntimeBeanEntry findRoot(
51 Collection<RuntimeBeanEntry> runtimeBeanEntries) {
52 RuntimeBeanEntry result = null;
53 for (RuntimeBeanEntry rb : runtimeBeanEntries) {
56 throw new IllegalArgumentException(
57 "More than one root runtime bean found");
65 throw new IllegalArgumentException("No root runtime bean found");
68 private static String constructConstructorBody(
69 List<Field> constructorParameters) {
70 StringBuffer constructorBody = new StringBuffer();
71 for (Field field : constructorParameters) {
72 constructorBody.append("this.");
73 constructorBody.append(field.getName());
74 constructorBody.append("=");
75 constructorBody.append(field.getName());
76 constructorBody.append(";\n");
78 return constructorBody.toString();
81 // TODO Move to factory
83 * Get registrator and n registration ftls where n is equal to total number
84 * of runtime beans in hierarchy.
86 public static Map<String, FtlTemplate> create(RuntimeBeanEntry rootRB) {
87 checkArgument(rootRB.isRoot(), "RuntimeBeanEntry must be root");
88 String registratorName = getJavaNameOfRuntimeRegistrator(rootRB);
89 List<MethodDefinition> methods = new ArrayList<>();
90 Field rootRuntimeBeanRegistratorField = new Field(
91 Lists.newArrayList("final"),
92 RootRuntimeBeanRegistrator.class.getName(),
93 "rootRuntimeBeanRegistrator");
94 List<Field> constructorParameters = Lists
95 .newArrayList(rootRuntimeBeanRegistratorField);
96 String constructorBody = constructConstructorBody(constructorParameters);
97 MethodDefinition constructor = MethodDefinition.createConstructor(
98 registratorName, constructorParameters, constructorBody);
99 methods.add(constructor);
101 LinkedHashMap<String, RuntimeRegistratorFtlTemplate> RuntimeRegistratorFtlTemplates = createRegistrationHierarchy(
102 rootRB, Collections.<String> emptySet());
103 RuntimeRegistratorFtlTemplate rootFtlFile = RuntimeRegistratorFtlTemplates
104 .values().iterator().next();
106 {// add register(rootruntimemxbean)
107 String fullyQualifiedNameOfMXBean = FullyQualifiedNameHelper
108 .getFullyQualifiedName(rootRB.getPackageName(), rootRB.getJavaNameOfRuntimeMXBean());
109 String childRegistratorFQN = rootFtlFile.getFullyQualifiedName();
110 Field rbParameter = new Field(fullyQualifiedNameOfMXBean, "rb");
111 StringBuilder registerBody = new StringBuilder();
112 registerBody.append(format("%s %s = this.%s.registerRoot(%s);\n",
113 HierarchicalRuntimeBeanRegistration.class
114 .getCanonicalName(), hierachchicalRegistration
115 .getName(), rootRuntimeBeanRegistratorField
116 .getName(), rbParameter.getName()));
117 registerBody.append(format("return new %s(%s);\n",
118 rootFtlFile.getFullyQualifiedName(),
119 hierachchicalRegistration.getName()));
121 MethodDefinition registerMethod = new MethodDefinition(
122 childRegistratorFQN, "register",
123 Arrays.asList(rbParameter), registerBody.toString());
124 methods.add(registerMethod);
127 MethodDefinition closeRegistrator = createCloseMethodToCloseField(rootRuntimeBeanRegistratorField);
128 methods.add(closeRegistrator);
131 GeneralClassTemplate registrator = new GeneralClassTemplate(null,
132 rootRB.getPackageName(), registratorName,
133 Collections.<String> emptyList(), Arrays.asList(Closeable.class
134 .getCanonicalName()), constructorParameters, methods);
136 checkState(RuntimeRegistratorFtlTemplates.containsKey(registrator
137 .getTypeDeclaration().getName()) == false, "Name conflict: "
138 + registrator.getTypeDeclaration().getName());
139 Map<String, FtlTemplate> result = new HashMap<>();
140 result.putAll(RuntimeRegistratorFtlTemplates);
141 result.put(registrator.getTypeDeclaration().getName(), registrator);
145 private static Field hierachchicalRegistration = new Field(
146 Lists.newArrayList("final"),
147 HierarchicalRuntimeBeanRegistration.class.getCanonicalName(),
150 // TODO move to factory + RuntimeBeanEntry
152 * Create ftls representing registrations. First registration is represents
155 * @return map containing java class name as key, instance representing the
156 * java file as value.
158 private static LinkedHashMap<String, RuntimeRegistratorFtlTemplate> createRegistrationHierarchy(
159 RuntimeBeanEntry parent, Set<String> occupiedKeys) {
160 LinkedHashMap<String, RuntimeRegistratorFtlTemplate> unorderedResult = new LinkedHashMap<>();
161 List<MethodDefinition> methods = new ArrayList<>();
163 // hierarchy of ON is created as follows:
164 // root RB: <domain>, type=RuntimeBean
165 // 1st RB in hierarchy: <domain>, type=RuntimeBean, <java name of leaf
166 // list>: key or counter
167 // n-th RB in hierarchy has same ON as n-1, with added <java name of
168 // leaf list>: key or counter
169 if (occupiedKeys.contains(parent.getJavaNamePrefix())) {
170 throw new IllegalArgumentException(
171 "Name conflict in runtime bean hierarchy - java name found more than "
172 + "once. Consider using java-name extension. Conflicting name: "
173 + parent.getJavaNamePrefix());
175 Set<String> currentOccupiedKeys = new HashSet<>(occupiedKeys);
176 currentOccupiedKeys.add(parent.getJavaNamePrefix());
178 Field registratorsMapField = new Field(Arrays.asList("final"),
179 TypeHelper.getGenericType(Map.class, String.class,
180 AtomicInteger.class), "unkeyedMap", "new "
181 + TypeHelper.getGenericType(HashMap.class,
182 String.class, AtomicInteger.class) + "()");
184 // create register methods for children
185 for (RuntimeBeanEntry child : parent.getChildren()) {
186 checkArgument(parent.getPackageName()
187 .equals(child.getPackageName()), "Invalid package name");
189 // call itself recursively to generate child
190 // registrators/registrations
191 LinkedHashMap<String, RuntimeRegistratorFtlTemplate> childRegistratorMap = createRegistrationHierarchy(
192 child, currentOccupiedKeys);
193 for (Entry<String, RuntimeRegistratorFtlTemplate> entry : childRegistratorMap
195 if (unorderedResult.containsKey(entry.getKey())) {
196 throw new IllegalStateException(
197 "Conflicting name found while generating runtime registration:"
200 unorderedResult.put(entry.getKey(), entry.getValue());
203 if (!childRegistratorMap.isEmpty()) {
204 // first entry is the direct descendant according to the create
206 RuntimeRegistratorFtlTemplate childRegistrator = childRegistratorMap
207 .values().iterator().next();
208 StringBuilder body = new StringBuilder();
210 key = child.getJavaNamePrefix();
212 "String key = \"%s\"; //TODO: check for conflicts\n",
215 if (child.getKeyJavaName().isPresent()) {
216 value = "bean.get" + child.getKeyJavaName().get() + "()";
217 value = "String.valueOf(" + value + ")";
219 body.append("java.util.concurrent.atomic.AtomicInteger counter = unkeyedMap.get(key);\n"
220 + "if (counter==null){\n"
221 + "counter = new java.util.concurrent.atomic.AtomicInteger();\n"
222 + "unkeyedMap.put(key, counter);\n" + "}\n");
223 value = "String.valueOf(counter.incrementAndGet())";
225 body.append(format("String value = %s;\n", value));
226 body.append(format("%s r = %s.register(key, value, bean);\n",
227 HierarchicalRuntimeBeanRegistration.class
228 .getCanonicalName(), hierachchicalRegistration
230 body.append(format("return new %s(r);",
231 childRegistrator.getFullyQualifiedName()));
233 Field param = new Field(Lists.newArrayList("final"),
234 child.getJavaNameOfRuntimeMXBean(), "bean");
235 MethodDefinition register = new MethodDefinition(
236 Arrays.asList("synchronized"),
237 childRegistrator.getFullyQualifiedName(), "register",
238 Arrays.asList(param), Collections.<String> emptyList(),
239 Collections.<Annotation> emptyList(), body.toString());
240 methods.add(register);
245 // create parent registration
246 String createdName = getJavaNameOfRuntimeRegistration(parent.getJavaNamePrefix());
248 List<Field> constructorParameters = Arrays
249 .asList(hierachchicalRegistration);
250 String constructorBody = constructConstructorBody(constructorParameters);
252 MethodDefinition constructor = MethodDefinition.createConstructor(
253 createdName, constructorParameters, constructorBody);
255 MethodDefinition closeRegistrator = createCloseMethodToCloseField(hierachchicalRegistration);
256 methods.add(closeRegistrator);
257 methods.add(constructor);
258 List<Field> privateFields = Lists.newArrayList(registratorsMapField);
259 privateFields.addAll(constructorParameters);
261 RuntimeRegistratorFtlTemplate created = new RuntimeRegistratorFtlTemplate(
262 parent, createdName, privateFields, methods);
264 LinkedHashMap<String, RuntimeRegistratorFtlTemplate> result = new LinkedHashMap<>();
265 result.put(created.getTypeDeclaration().getName(), created);
266 checkState(unorderedResult.containsKey(created.getTypeDeclaration()
267 .getName()) == false, "Naming conflict: "
268 + created.getTypeDeclaration().getName());
269 result.putAll(unorderedResult);
273 private static MethodDefinition createCloseMethodToCloseField(Field field) {
274 String body = field.getName() + ".close();";
275 // TODO Thrown exception breaks build
276 // return new MethodDefinition(Collections.<String> emptyList(), "void",
277 // "close", Collections.<Field> emptyList(),
278 // Arrays.asList(IOException.class.getCanonicalName()),
279 // Collections.<Annotation> emptyList(), body);
280 List<Annotation> annotations = Lists.newArrayList(new Annotation(
281 "Override", Collections.<Parameter> emptyList()));
282 return new MethodDefinition(Collections.<String> emptyList(), "void",
283 "close", Collections.<Field> emptyList(),
284 Collections.<String> emptyList(), annotations, body);
288 public static String getJavaNameOfRuntimeRegistration(String javaNamePrefix) {
289 return javaNamePrefix + "RuntimeRegistration";
292 public static String getJavaNameOfRuntimeRegistrator(RuntimeBeanEntry rootRB) {
293 checkArgument(rootRB.isRoot(), "RuntimeBeanEntry must be root");
294 return rootRB.getJavaNamePrefix() + "RuntimeRegistrator";