2 * Copyright (c) 2014 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.mdsal.binding.java.api.generator;
10 import static com.google.common.base.Preconditions.checkArgument;
11 import static org.opendaylight.mdsal.binding.spec.naming.BindingMapping.AUGMENTABLE_AUGMENTATION_NAME;
13 import com.google.common.annotations.VisibleForTesting;
14 import com.google.common.collect.ImmutableSortedSet;
15 import java.lang.reflect.Method;
16 import java.util.Collection;
17 import java.util.Collections;
18 import java.util.Comparator;
19 import java.util.LinkedHashSet;
20 import java.util.List;
22 import org.eclipse.xtext.xbase.lib.StringExtensions;
23 import org.opendaylight.mdsal.binding.model.api.CodeGenerator;
24 import org.opendaylight.mdsal.binding.model.api.GeneratedProperty;
25 import org.opendaylight.mdsal.binding.model.api.GeneratedTransferObject;
26 import org.opendaylight.mdsal.binding.model.api.GeneratedType;
27 import org.opendaylight.mdsal.binding.model.api.JavaTypeName;
28 import org.opendaylight.mdsal.binding.model.api.MethodSignature;
29 import org.opendaylight.mdsal.binding.model.api.ParameterizedType;
30 import org.opendaylight.mdsal.binding.model.api.Type;
31 import org.opendaylight.mdsal.binding.model.api.type.builder.GeneratedTOBuilder;
32 import org.opendaylight.mdsal.binding.model.api.type.builder.GeneratedTypeBuilder;
33 import org.opendaylight.mdsal.binding.model.util.ReferencedTypeImpl;
34 import org.opendaylight.mdsal.binding.model.util.Types;
35 import org.opendaylight.mdsal.binding.model.util.generated.type.builder.CodegenGeneratedTOBuilder;
36 import org.opendaylight.mdsal.binding.model.util.generated.type.builder.CodegenGeneratedTypeBuilder;
37 import org.opendaylight.mdsal.binding.spec.naming.BindingMapping;
38 import org.opendaylight.yangtools.yang.binding.Augmentable;
39 import org.opendaylight.yangtools.yang.binding.Augmentation;
43 * Transformator of the data from the virtual form to JAVA programming language.
44 * The result source code represent java class. For generation of the source
45 * code is used the template written in XTEND language.
48 public final class BuilderGenerator implements CodeGenerator {
49 private static final Comparator<MethodSignature> METHOD_COMPARATOR = new AlphabeticallyTypeMemberComparator<>();
50 private static final Type AUGMENTATION_RET_TYPE;
55 m = Augmentable.class.getDeclaredMethod(AUGMENTABLE_AUGMENTATION_NAME, Class.class);
56 } catch (NoSuchMethodException e) {
57 throw new ExceptionInInitializerError(e);
60 AUGMENTATION_RET_TYPE = new ReferencedTypeImpl(JavaTypeName.create(m.getReturnType()));
64 * Passes via list of implemented types in <code>type</code>.
67 * JAVA <code>Type</code>
68 * @return boolean value which is true if any of implemented types is of the
69 * type <code>Augmentable</code>.
72 public boolean isAcceptable(Type type) {
73 if (type instanceof GeneratedType && !(type instanceof GeneratedTransferObject)) {
74 for (Type t : ((GeneratedType) type).getImplements()) {
75 // "rpc" and "grouping" elements do not implement Augmentable
76 if (t.getFullyQualifiedName().equals(Augmentable.class.getName())) {
78 } else if (t.getFullyQualifiedName().equals(Augmentation.class.getName())) {
88 * Generates JAVA source code for generated type <code>Type</code>. The code
89 * is generated according to the template source code template which is
90 * written in XTEND language.
93 public String generate(Type type) {
94 if (type instanceof GeneratedType && !(type instanceof GeneratedTransferObject)) {
95 return templateForType((GeneratedType) type).generate();
101 public String getUnitName(Type type) {
102 return type.getName() + BuilderTemplate.BUILDER;
106 static BuilderTemplate templateForType(GeneratedType type) {
107 final GeneratedType genType = type;
108 final JavaTypeName origName = genType.getIdentifier();
110 final Set<MethodSignature> methods = new LinkedHashSet<>();
111 final Type augmentType = createMethods(genType, methods);
112 final Set<MethodSignature> sortedMethods = ImmutableSortedSet.orderedBy(METHOD_COMPARATOR)
113 .addAll(methods).build();
115 final GeneratedTypeBuilder builderTypeBuilder = new CodegenGeneratedTypeBuilder(
116 origName.createSibling(origName.simpleName() + BuilderTemplate.BUILDER));
118 final GeneratedTOBuilder implTypeBuilder = builderTypeBuilder.addEnclosingTransferObject(
119 origName.simpleName() + "Impl");
120 implTypeBuilder.addImplementsType(genType);
122 return new BuilderTemplate(builderTypeBuilder.build(), genType, propertiesFromMethods(sortedMethods),
123 augmentType, getKey(genType));
126 private static Type getKey(GeneratedType type) {
127 for (MethodSignature m : type.getMethodDefinitions()) {
128 if (BindingMapping.IDENTIFIABLE_KEY_NAME.equals(m.getName())) {
129 return m.getReturnType();
136 * Returns set of method signature instances which contains all the methods of the <code>genType</code>
137 * and all the methods of the implemented interfaces.
139 * @returns set of method signature instances
141 private static ParameterizedType createMethods(GeneratedType type, Set<MethodSignature> methods) {
142 methods.addAll(type.getMethodDefinitions());
143 return collectImplementedMethods(type, methods, type.getImplements());
147 * Adds to the <code>methods</code> set all the methods of the <code>implementedIfcs</code>
148 * and recursively their implemented interfaces.
150 * @param methods set of method signatures
151 * @param implementedIfcs list of implemented interfaces
153 private static ParameterizedType collectImplementedMethods(GeneratedType type, Set<MethodSignature> methods,
154 List<Type> implementedIfcs) {
155 if (implementedIfcs == null || implementedIfcs.isEmpty()) {
159 ParameterizedType augmentType = null;
160 for (Type implementedIfc : implementedIfcs) {
161 if (implementedIfc instanceof GeneratedType && !(implementedIfc instanceof GeneratedTransferObject)) {
162 final GeneratedType ifc = (GeneratedType) implementedIfc;
163 methods.addAll(ifc.getMethodDefinitions());
165 final ParameterizedType t = collectImplementedMethods(type, methods, ifc.getImplements());
166 if (t != null && augmentType == null) {
169 } else if (Augmentable.class.getName().equals(implementedIfc.getFullyQualifiedName())) {
170 augmentType = Types.parameterizedTypeFor(AUGMENTATION_RET_TYPE,
171 new ReferencedTypeImpl(type.getIdentifier()));
179 * Creates set of generated property instances from getter <code>methods</code>.
181 * @param set of method signature instances which should be transformed to list of properties
182 * @return set of generated property instances which represents the getter <code>methods</code>
184 private static Set<GeneratedProperty> propertiesFromMethods(Collection<MethodSignature> methods) {
185 if (methods == null || methods.isEmpty()) {
186 return Collections.emptySet();
188 final Set<GeneratedProperty> result = new LinkedHashSet<>();
189 for (MethodSignature m : methods) {
190 final GeneratedProperty createdField = propertyFromGetter(m);
191 if (createdField != null) {
192 result.add(createdField);
199 * Creates generated property instance from the getter <code>method</code> name and return type.
201 * @param method method signature from which is the method name and return type obtained
202 * @return generated property instance for the getter <code>method</code>
203 * @throws IllegalArgumentException<ul>
204 * <li>if the <code>method</code> equals <code>null</code></li>
205 * <li>if the name of the <code>method</code> equals <code>null</code></li>
206 * <li>if the name of the <code>method</code> is empty</li>
207 * <li>if the return type of the <code>method</code> equals <code>null</code></li>
210 private static GeneratedProperty propertyFromGetter(MethodSignature method) {
211 checkArgument(method != null);
212 checkArgument(method.getReturnType() != null);
213 checkArgument(method.getName() != null);
214 checkArgument(!method.getName().isEmpty());
215 final String prefix = Types.BOOLEAN.equals(method.getReturnType()) ? "is" : "get";
216 if (!method.getName().startsWith(prefix)) {
220 final String fieldName = StringExtensions.toFirstLower(method.getName().substring(prefix.length()));
221 final GeneratedTOBuilder tmpGenTO = new CodegenGeneratedTOBuilder(JavaTypeName.create("foo", "foo"));
222 tmpGenTO.addProperty(fieldName).setReturnType(method.getReturnType());
223 return tmpGenTO.build().getProperties().get(0);