Speed up AbstractBuilderTemplate.removeProperty()
[mdsal.git] / binding / mdsal-binding-java-api-generator / src / main / java / org / opendaylight / mdsal / binding / java / api / generator / NestedJavaGeneratedType.java
1 /*
2  * Copyright (c) 2018 Pantheon Technologies, 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 static com.google.common.base.Verify.verify;
11 import static java.util.Objects.requireNonNull;
12
13 import com.google.common.collect.ImmutableList;
14 import java.util.ArrayDeque;
15 import java.util.Deque;
16 import java.util.Iterator;
17 import java.util.List;
18 import java.util.Optional;
19 import org.eclipse.jdt.annotation.NonNullByDefault;
20 import org.eclipse.jdt.annotation.Nullable;
21 import org.opendaylight.mdsal.binding.model.api.GeneratedType;
22 import org.opendaylight.mdsal.binding.model.api.JavaTypeName;
23
24 /**
25  * A type which is nested inside some other type. It defers import decisions to its enclosing type, eventually arriving
26  * at a {@link TopLevelJavaGeneratedType}.
27  *
28  * @author Robert Varga
29  */
30 @NonNullByDefault
31 final class NestedJavaGeneratedType extends AbstractJavaGeneratedType {
32     private final AbstractJavaGeneratedType enclosingType;
33
34     NestedJavaGeneratedType(final AbstractJavaGeneratedType enclosingType, final GeneratedType genType) {
35         super(genType);
36         this.enclosingType = requireNonNull(enclosingType);
37     }
38
39     @Override
40     boolean importCheckedType(final JavaTypeName type) {
41         // Defer to enclosing type, which needs to re-run its checks
42         return enclosingType.checkAndImportType(type);
43     }
44
45     @Override
46     String localTypeName(final JavaTypeName type) {
47         // Check if the type is a reference to our immediately-enclosing type
48         if (enclosingType.getName().equals(type)) {
49             return enclosingType.getSimpleName();
50         }
51
52         final @Nullable List<String> descendant = findDescandantPath(type);
53         if (descendant == null) {
54             // The type is not present in our hierarchy, defer to our immediately-enclosing type, which may be able
55             // to find the target.
56             return enclosingType.localTypeName(type);
57         }
58
59         // Target type is a declared as a enclosed type of us and we have the path where it lurks.
60         final Iterator<String> it = descendant.iterator();
61         final StringBuilder sb = new StringBuilder().append(it.next());
62         while (it.hasNext()) {
63             sb.append('.').append(it.next());
64         }
65         return sb.toString();
66     }
67
68     private @Nullable List<String> findDescandantPath(final JavaTypeName type) {
69         Optional<JavaTypeName> optEnclosing = type.immediatelyEnclosingClass();
70         verify(optEnclosing.isPresent());
71
72         final Deque<String> queue = new ArrayDeque<>();
73         queue.addFirst(type.simpleName());
74         while (optEnclosing.isPresent()) {
75             final JavaTypeName enclosing = optEnclosing.get();
76             if (enclosing.equals(getName())) {
77                 return ImmutableList.copyOf(queue);
78             }
79
80             queue.addFirst(enclosing.simpleName());
81             optEnclosing = enclosing.immediatelyEnclosingClass();
82         }
83
84         return null;
85     }
86 }