Remove hashCode()/equals() from SchemaNode implementations
[yangtools.git] / yang / yang-parser-rfc7950 / src / main / java / org / opendaylight / yangtools / yang / parser / rfc7950 / stmt / extension / ExtensionEffectiveStatementImpl.java
1 /*
2  * Copyright (c) 2015 Cisco Systems, Inc. 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.yangtools.yang.parser.rfc7950.stmt.extension;
9
10 import java.util.ArrayDeque;
11 import java.util.Collection;
12 import java.util.Deque;
13 import java.util.Optional;
14 import org.eclipse.jdt.annotation.NonNull;
15 import org.eclipse.jdt.annotation.Nullable;
16 import org.opendaylight.yangtools.util.RecursiveObjectLeaker;
17 import org.opendaylight.yangtools.yang.common.QName;
18 import org.opendaylight.yangtools.yang.model.api.ExtensionDefinition;
19 import org.opendaylight.yangtools.yang.model.api.SchemaPath;
20 import org.opendaylight.yangtools.yang.model.api.meta.EffectiveStatement;
21 import org.opendaylight.yangtools.yang.model.api.stmt.ArgumentEffectiveStatement;
22 import org.opendaylight.yangtools.yang.model.api.stmt.ExtensionEffectiveStatement;
23 import org.opendaylight.yangtools.yang.model.api.stmt.ExtensionStatement;
24 import org.opendaylight.yangtools.yang.model.api.stmt.YinElementEffectiveStatement;
25 import org.opendaylight.yangtools.yang.parser.rfc7950.stmt.AbstractEffectiveDocumentedNode;
26 import org.opendaylight.yangtools.yang.parser.spi.meta.StmtContext;
27
28 final class ExtensionEffectiveStatementImpl extends AbstractEffectiveDocumentedNode<QName, ExtensionStatement>
29         implements ExtensionDefinition, ExtensionEffectiveStatement {
30     private static final class RecursionDetector extends ThreadLocal<Deque<ExtensionEffectiveStatementImpl>> {
31         boolean check(final ExtensionEffectiveStatementImpl current) {
32             final Deque<ExtensionEffectiveStatementImpl> stack = get();
33             if (stack != null) {
34                 for (ExtensionEffectiveStatementImpl s : stack) {
35                     if (s == current) {
36                         return true;
37                     }
38                 }
39             }
40             return false;
41         }
42
43         void push(final ExtensionEffectiveStatementImpl current) {
44             Deque<ExtensionEffectiveStatementImpl> stack = get();
45             if (stack == null) {
46                 stack = new ArrayDeque<>(1);
47                 set(stack);
48             }
49
50             stack.push(current);
51         }
52
53         void pop() {
54             Deque<ExtensionEffectiveStatementImpl> stack = get();
55             stack.pop();
56             if (stack.isEmpty()) {
57                 remove();
58             }
59         }
60     }
61
62     private static final RecursionDetector TOSTRING_DETECTOR = new RecursionDetector();
63
64     private final @NonNull QName qname;
65     private final @Nullable String argument;
66     private final @NonNull SchemaPath schemaPath;
67
68     private final boolean yin;
69
70     private ExtensionEffectiveStatementImpl(
71             final StmtContext<QName, ExtensionStatement, ExtensionEffectiveStatement> ctx) {
72         super(ctx);
73         this.qname = ctx.coerceStatementArgument();
74         this.schemaPath = ctx.getSchemaPath().get();
75
76         // initFields
77         final Optional<ArgumentEffectiveStatement> optArgumentSubstatement = findFirstEffectiveSubstatement(
78             ArgumentEffectiveStatement.class);
79         if (optArgumentSubstatement.isPresent()) {
80             final ArgumentEffectiveStatement argumentStatement = optArgumentSubstatement.get();
81             this.argument = argumentStatement.argument().getLocalName();
82             this.yin = argumentStatement.findFirstEffectiveSubstatement(YinElementEffectiveStatement.class)
83                     .map(YinElementEffectiveStatement::argument).orElse(Boolean.FALSE).booleanValue();
84         } else {
85             this.argument = null;
86             this.yin = false;
87         }
88     }
89
90     /**
91      * Create a new ExtensionEffectiveStatement, dealing with potential recursion.
92      *
93      * @param ctx Statement context
94      * @return A potentially under-initialized instance
95      */
96     static ExtensionEffectiveStatement create(
97             final StmtContext<QName, ExtensionStatement, ExtensionEffectiveStatement> ctx) {
98         // Look at the thread-local leak in case we are invoked recursively
99         final ExtensionEffectiveStatementImpl existing = RecursiveObjectLeaker.lookup(ctx,
100             ExtensionEffectiveStatementImpl.class);
101         if (existing != null) {
102             // Careful! this object is not fully initialized!
103             return existing;
104         }
105
106         RecursiveObjectLeaker.beforeConstructor(ctx);
107         try {
108             // This result is fine, we know it has been completely initialized
109             return new ExtensionEffectiveStatementImpl(ctx);
110         } finally {
111             RecursiveObjectLeaker.afterConstructor(ctx);
112         }
113     }
114
115     @Override
116     protected Collection<? extends EffectiveStatement<?, ?>> initSubstatements(
117             final Collection<? extends StmtContext<?, ?, ?>> substatementsInit) {
118         // WARNING: this leaks an incompletely-initialized object
119         RecursiveObjectLeaker.inConstructor(this);
120
121         return super.initSubstatements(substatementsInit);
122     }
123
124     @Override
125     public QName getQName() {
126         return qname;
127     }
128
129     @Override
130     public SchemaPath getPath() {
131         return schemaPath;
132     }
133
134     @Override
135     public String getArgument() {
136         return argument;
137     }
138
139     @Override
140     public boolean isYinElement() {
141         return yin;
142     }
143
144     @Override
145     public String toString() {
146         if (TOSTRING_DETECTOR.check(this)) {
147             return recursedToString();
148         }
149
150         TOSTRING_DETECTOR.push(this);
151         try {
152             return ExtensionEffectiveStatementImpl.class.getSimpleName() + "["
153                     + "argument=" + argument
154                     + ", qname=" + qname
155                     + ", schemaPath=" + schemaPath
156                     + ", extensionSchemaNodes=" + getUnknownSchemaNodes()
157                     + ", yin=" + yin
158                     + "]";
159         } finally {
160             TOSTRING_DETECTOR.pop();
161         }
162     }
163
164     private String recursedToString() {
165         return ExtensionEffectiveStatementImpl.class.getSimpleName() + "["
166                 + "argument=" + argument
167                 + ", qname=" + qname
168                 + ", schemaPath=" + schemaPath
169                 + ", yin=" + yin
170                 + " <RECURSIVE> ]";
171     }
172 }