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.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;
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();
34 for (ExtensionEffectiveStatementImpl s : stack) {
43 void push(final ExtensionEffectiveStatementImpl current) {
44 Deque<ExtensionEffectiveStatementImpl> stack = get();
46 stack = new ArrayDeque<>(1);
54 Deque<ExtensionEffectiveStatementImpl> stack = get();
56 if (stack.isEmpty()) {
62 private static final RecursionDetector TOSTRING_DETECTOR = new RecursionDetector();
64 private final @NonNull QName qname;
65 private final @Nullable String argument;
66 private final @NonNull SchemaPath schemaPath;
68 private final boolean yin;
70 private ExtensionEffectiveStatementImpl(
71 final StmtContext<QName, ExtensionStatement, ExtensionEffectiveStatement> ctx) {
73 this.qname = ctx.coerceStatementArgument();
74 this.schemaPath = ctx.getSchemaPath().get();
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();
91 * Create a new ExtensionEffectiveStatement, dealing with potential recursion.
93 * @param ctx Statement context
94 * @return A potentially under-initialized instance
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!
106 RecursiveObjectLeaker.beforeConstructor(ctx);
108 // This result is fine, we know it has been completely initialized
109 return new ExtensionEffectiveStatementImpl(ctx);
111 RecursiveObjectLeaker.afterConstructor(ctx);
116 protected Collection<? extends EffectiveStatement<?, ?>> initSubstatements(
117 final Collection<? extends StmtContext<?, ?, ?>> substatementsInit) {
118 // WARNING: this leaks an incompletely-initialized object
119 RecursiveObjectLeaker.inConstructor(this);
121 return super.initSubstatements(substatementsInit);
125 public QName getQName() {
130 public SchemaPath getPath() {
135 public String getArgument() {
140 public boolean isYinElement() {
145 public String toString() {
146 if (TOSTRING_DETECTOR.check(this)) {
147 return recursedToString();
150 TOSTRING_DETECTOR.push(this);
152 return ExtensionEffectiveStatementImpl.class.getSimpleName() + "["
153 + "argument=" + argument
155 + ", schemaPath=" + schemaPath
156 + ", extensionSchemaNodes=" + getUnknownSchemaNodes()
160 TOSTRING_DETECTOR.pop();
164 private String recursedToString() {
165 return ExtensionEffectiveStatementImpl.class.getSimpleName() + "["
166 + "argument=" + argument
168 + ", schemaPath=" + schemaPath