2 * Copyright (c) 2015 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.yangtools.yang.parser.rfc7950.stmt.extension;
10 import java.util.ArrayDeque;
11 import java.util.Collection;
12 import java.util.Deque;
13 import java.util.Objects;
14 import java.util.Optional;
15 import org.eclipse.jdt.annotation.NonNull;
16 import org.eclipse.jdt.annotation.Nullable;
17 import org.opendaylight.yangtools.util.RecursiveObjectLeaker;
18 import org.opendaylight.yangtools.yang.common.QName;
19 import org.opendaylight.yangtools.yang.model.api.ExtensionDefinition;
20 import org.opendaylight.yangtools.yang.model.api.SchemaPath;
21 import org.opendaylight.yangtools.yang.model.api.meta.EffectiveStatement;
22 import org.opendaylight.yangtools.yang.model.api.stmt.ArgumentEffectiveStatement;
23 import org.opendaylight.yangtools.yang.model.api.stmt.ExtensionEffectiveStatement;
24 import org.opendaylight.yangtools.yang.model.api.stmt.ExtensionStatement;
25 import org.opendaylight.yangtools.yang.model.api.stmt.YinElementEffectiveStatement;
26 import org.opendaylight.yangtools.yang.parser.rfc7950.stmt.AbstractEffectiveDocumentedNode;
27 import org.opendaylight.yangtools.yang.parser.spi.meta.StmtContext;
29 final class ExtensionEffectiveStatementImpl extends AbstractEffectiveDocumentedNode<QName, ExtensionStatement>
30 implements ExtensionDefinition, ExtensionEffectiveStatement {
31 private static final class RecursionDetector extends ThreadLocal<Deque<ExtensionEffectiveStatementImpl>> {
32 boolean check(final ExtensionEffectiveStatementImpl current) {
33 final Deque<ExtensionEffectiveStatementImpl> stack = get();
35 for (ExtensionEffectiveStatementImpl s : stack) {
44 void push(final ExtensionEffectiveStatementImpl current) {
45 Deque<ExtensionEffectiveStatementImpl> stack = get();
47 stack = new ArrayDeque<>(1);
55 Deque<ExtensionEffectiveStatementImpl> stack = get();
57 if (stack.isEmpty()) {
63 private static final RecursionDetector TOSTRING_DETECTOR = new RecursionDetector();
65 private final @NonNull QName qname;
66 private final @Nullable String argument;
67 private final @NonNull SchemaPath schemaPath;
69 private final boolean yin;
71 private ExtensionEffectiveStatementImpl(
72 final StmtContext<QName, ExtensionStatement, ExtensionEffectiveStatement> ctx) {
74 this.qname = ctx.coerceStatementArgument();
75 this.schemaPath = ctx.getSchemaPath().get();
78 final Optional<ArgumentEffectiveStatement> optArgumentSubstatement = findFirstEffectiveSubstatement(
79 ArgumentEffectiveStatement.class);
80 if (optArgumentSubstatement.isPresent()) {
81 final ArgumentEffectiveStatement argumentStatement = optArgumentSubstatement.get();
82 this.argument = argumentStatement.argument().getLocalName();
83 this.yin = argumentStatement.findFirstEffectiveSubstatement(YinElementEffectiveStatement.class)
84 .map(YinElementEffectiveStatement::argument).orElse(Boolean.FALSE).booleanValue();
92 * Create a new ExtensionEffectiveStatement, dealing with potential recursion.
94 * @param ctx Statement context
95 * @return A potentially under-initialized instance
97 static ExtensionEffectiveStatement create(
98 final StmtContext<QName, ExtensionStatement, ExtensionEffectiveStatement> ctx) {
99 // Look at the thread-local leak in case we are invoked recursively
100 final ExtensionEffectiveStatementImpl existing = RecursiveObjectLeaker.lookup(ctx,
101 ExtensionEffectiveStatementImpl.class);
102 if (existing != null) {
103 // Careful! this object is not fully initialized!
107 RecursiveObjectLeaker.beforeConstructor(ctx);
109 // This result is fine, we know it has been completely initialized
110 return new ExtensionEffectiveStatementImpl(ctx);
112 RecursiveObjectLeaker.afterConstructor(ctx);
117 protected Collection<? extends EffectiveStatement<?, ?>> initSubstatements(
118 final Collection<? extends StmtContext<?, ?, ?>> substatementsInit) {
119 // WARNING: this leaks an incompletely-initialized object
120 RecursiveObjectLeaker.inConstructor(this);
122 return super.initSubstatements(substatementsInit);
126 public QName getQName() {
131 public SchemaPath getPath() {
136 public String getArgument() {
141 public boolean isYinElement() {
146 public int hashCode() {
147 final int prime = 31;
149 result = prime * result + Objects.hashCode(qname);
150 result = prime * result + Objects.hashCode(schemaPath);
155 public boolean equals(final Object obj) {
162 if (getClass() != obj.getClass()) {
165 ExtensionEffectiveStatementImpl other = (ExtensionEffectiveStatementImpl) obj;
166 return Objects.equals(qname, other.qname) && Objects.equals(schemaPath, other.schemaPath);
170 public String toString() {
171 if (TOSTRING_DETECTOR.check(this)) {
172 return recursedToString();
175 TOSTRING_DETECTOR.push(this);
177 return ExtensionEffectiveStatementImpl.class.getSimpleName() + "["
178 + "argument=" + argument
180 + ", schemaPath=" + schemaPath
181 + ", extensionSchemaNodes=" + getUnknownSchemaNodes()
185 TOSTRING_DETECTOR.pop();
189 private String recursedToString() {
190 return ExtensionEffectiveStatementImpl.class.getSimpleName() + "["
191 + "argument=" + argument
193 + ", schemaPath=" + schemaPath