256848371ee5a94bf66ad97d2a92335b61c533e3
[mdsal.git] / binding / mdsal-binding-java-api-generator / src / main / java / org / opendaylight / mdsal / binding / java / api / generator / ByTypeMemberComparator.java
1 /*
2  * Copyright (c) 2020 PANTHEON.tech, s.r.o. 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 package org.opendaylight.mdsal.binding.java.api.generator;
9
10 import com.google.common.annotations.Beta;
11 import java.io.Serializable;
12 import java.util.ArrayList;
13 import java.util.Collection;
14 import java.util.Comparator;
15 import java.util.List;
16 import java.util.Set;
17 import org.eclipse.jdt.annotation.NonNull;
18 import org.opendaylight.mdsal.binding.model.api.ConcreteType;
19 import org.opendaylight.mdsal.binding.model.api.GeneratedProperty;
20 import org.opendaylight.mdsal.binding.model.api.GeneratedTransferObject;
21 import org.opendaylight.mdsal.binding.model.api.ParameterizedType;
22 import org.opendaylight.mdsal.binding.model.api.Type;
23 import org.opendaylight.mdsal.binding.model.api.TypeMember;
24 import org.opendaylight.mdsal.binding.model.ri.BaseYangTypes;
25 import org.opendaylight.mdsal.binding.model.ri.BindingTypes;
26 import org.opendaylight.mdsal.binding.model.ri.TypeConstants;
27 import org.opendaylight.mdsal.binding.model.ri.Types;
28 import org.opendaylight.yangtools.yang.model.api.TypeDefinition;
29 import org.opendaylight.yangtools.yang.model.api.type.BitsTypeDefinition;
30
31 /**
32  * By type member {@link Comparator} which provides sorting by type for members (variables)
33  * in a generated class.
34  *
35  * @param <T> TypeMember type
36  */
37 @Beta
38 final class ByTypeMemberComparator<T extends TypeMember> implements Comparator<T>, Serializable {
39     private static final long serialVersionUID = 1L;
40
41     /**
42      * Fixed-size comparison. These are all numeric types, boolean, empty, identityref.
43      */
44     private static final int RANK_FIXED_SIZE          = 0;
45     /**
46      * Variable-sized comparison across simple components. These are string, binary and bits type.
47      */
48     private static final int RANK_VARIABLE_ARRAY      = 1;
49     /**
50      * Variable-size comparison across complex components.
51      */
52     private static final int RANK_INSTANCE_IDENTIFIER = 2;
53     /**
54      * Composite structure. DataObject, OpaqueObject and similar.
55      */
56     private static final int RANK_COMPOSITE           = 3;
57
58     private static final Set<Type> FIXED_TYPES = Set.of(
59         BaseYangTypes.INT8_TYPE,
60         BaseYangTypes.INT16_TYPE,
61         BaseYangTypes.INT32_TYPE,
62         BaseYangTypes.INT64_TYPE,
63         BaseYangTypes.DECIMAL64_TYPE,
64         BaseYangTypes.UINT8_TYPE,
65         BaseYangTypes.UINT16_TYPE,
66         BaseYangTypes.UINT32_TYPE,
67         BaseYangTypes.UINT64_TYPE,
68         BaseYangTypes.BOOLEAN_TYPE,
69         BaseYangTypes.EMPTY_TYPE,
70         Types.CLASS);
71
72     /**
73      * Singleton instance.
74      */
75     private static final @NonNull ByTypeMemberComparator<?> INSTANCE = new ByTypeMemberComparator<>();
76
77     private ByTypeMemberComparator() {
78         // Hidden on purpose
79     }
80
81     /**
82      * Returns the one and only instance of this class.
83      *
84      * @return this comparator
85      */
86     @SuppressWarnings("unchecked")
87     public static <T extends TypeMember> ByTypeMemberComparator<T> getInstance() {
88         return (ByTypeMemberComparator<T>) INSTANCE;
89     }
90
91     public static <T extends TypeMember> Collection<T> sort(final Collection<T> input) {
92         if (input.size() < 2) {
93             return input;
94         }
95
96         final List<T> ret = new ArrayList<>(input);
97         ret.sort(getInstance());
98         return ret;
99     }
100
101     @Override
102     public int compare(final T member1, final T member2) {
103         final Type type1 = getConcreteType(member1.getReturnType());
104         final Type type2 = getConcreteType(member2.getReturnType());
105         if (!type1.getIdentifier().equals(type2.getIdentifier())) {
106             final int cmp = rankOf(type1) - rankOf(type2);
107             if (cmp != 0) {
108                 return cmp;
109             }
110         }
111         return member1.getName().compareTo(member2.getName());
112     }
113
114     @SuppressWarnings("static-method")
115     private Object readResolve() {
116         return INSTANCE;
117     }
118
119     private static Type getConcreteType(final Type type) {
120         if (type instanceof ConcreteType) {
121             return type;
122         } else if (type instanceof ParameterizedType) {
123             return ((ParameterizedType) type).getRawType();
124         } else if (type instanceof GeneratedTransferObject) {
125             GeneratedTransferObject rootGto = (GeneratedTransferObject) type;
126             while (rootGto.getSuperType() != null) {
127                 rootGto = rootGto.getSuperType();
128             }
129             for (GeneratedProperty s : rootGto.getProperties()) {
130                 if (TypeConstants.VALUE_PROP.equals(s.getName())) {
131                     return s.getReturnType();
132                 }
133             }
134         }
135         return type;
136     }
137
138     private static int rankOf(final Type type) {
139         if (FIXED_TYPES.contains(type)) {
140             return RANK_FIXED_SIZE;
141         }
142         if (type.equals(BaseYangTypes.STRING_TYPE) || type.equals(Types.BYTE_ARRAY)) {
143             return RANK_VARIABLE_ARRAY;
144         }
145         if (type.equals(BindingTypes.INSTANCE_IDENTIFIER) || type.equals(BindingTypes.KEYED_INSTANCE_IDENTIFIER)) {
146             return RANK_INSTANCE_IDENTIFIER;
147         }
148         if (type instanceof GeneratedTransferObject) {
149             final TypeDefinition<?> typedef = topParentTransportObject((GeneratedTransferObject) type).getBaseType();
150             if (typedef instanceof BitsTypeDefinition) {
151                 return RANK_VARIABLE_ARRAY;
152             }
153         }
154         return RANK_COMPOSITE;
155     }
156
157     private static GeneratedTransferObject topParentTransportObject(final GeneratedTransferObject type) {
158         GeneratedTransferObject ret = type;
159         GeneratedTransferObject parent = ret.getSuperType();
160         while (parent != null) {
161             ret = parent;
162             parent = ret.getSuperType();
163         }
164         return ret;
165     }
166 }