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.stmt.reactor;
10 import com.google.common.base.MoreObjects;
11 import com.google.common.base.MoreObjects.ToStringHelper;
12 import com.google.common.base.Preconditions;
13 import com.google.common.collect.ImmutableCollection;
14 import com.google.common.collect.ImmutableList;
15 import com.google.common.collect.ImmutableMultimap;
16 import com.google.common.collect.ImmutableSet;
17 import com.google.common.collect.Multimap;
18 import com.google.common.collect.Multimaps;
19 import java.util.ArrayList;
20 import java.util.Collection;
21 import java.util.Collections;
22 import java.util.EnumMap;
23 import java.util.EventListener;
24 import java.util.Iterator;
25 import java.util.Map.Entry;
26 import java.util.Optional;
28 import javax.annotation.Nonnull;
29 import javax.annotation.Nullable;
30 import org.opendaylight.yangtools.util.OptionalBoolean;
31 import org.opendaylight.yangtools.yang.common.QName;
32 import org.opendaylight.yangtools.yang.common.QNameModule;
33 import org.opendaylight.yangtools.yang.model.api.YangStmtMapping;
34 import org.opendaylight.yangtools.yang.model.api.meta.DeclaredStatement;
35 import org.opendaylight.yangtools.yang.model.api.meta.EffectiveStatement;
36 import org.opendaylight.yangtools.yang.model.api.meta.IdentifierNamespace;
37 import org.opendaylight.yangtools.yang.model.api.meta.StatementDefinition;
38 import org.opendaylight.yangtools.yang.model.api.meta.StatementSource;
39 import org.opendaylight.yangtools.yang.parser.spi.meta.CopyHistory;
40 import org.opendaylight.yangtools.yang.parser.spi.meta.CopyType;
41 import org.opendaylight.yangtools.yang.parser.spi.meta.ModelActionBuilder;
42 import org.opendaylight.yangtools.yang.parser.spi.meta.ModelProcessingPhase;
43 import org.opendaylight.yangtools.yang.parser.spi.meta.NamespaceBehaviour;
44 import org.opendaylight.yangtools.yang.parser.spi.meta.NamespaceKeyCriterion;
45 import org.opendaylight.yangtools.yang.parser.spi.meta.StatementNamespace;
46 import org.opendaylight.yangtools.yang.parser.spi.meta.StatementSupport;
47 import org.opendaylight.yangtools.yang.parser.spi.meta.StmtContext;
48 import org.opendaylight.yangtools.yang.parser.spi.meta.StmtContext.Mutable;
49 import org.opendaylight.yangtools.yang.parser.spi.meta.StmtContextUtils;
50 import org.opendaylight.yangtools.yang.parser.spi.source.ImplicitSubstatement;
51 import org.opendaylight.yangtools.yang.parser.spi.source.SourceException;
52 import org.opendaylight.yangtools.yang.parser.spi.source.StatementSourceReference;
53 import org.opendaylight.yangtools.yang.parser.spi.source.SupportedFeaturesNamespace;
54 import org.opendaylight.yangtools.yang.parser.spi.source.SupportedFeaturesNamespace.SupportedFeatures;
55 import org.opendaylight.yangtools.yang.parser.stmt.reactor.NamespaceBehaviourWithListeners.KeyedValueAddedListener;
56 import org.opendaylight.yangtools.yang.parser.stmt.reactor.NamespaceBehaviourWithListeners.PredicateValueAddedListener;
57 import org.slf4j.Logger;
58 import org.slf4j.LoggerFactory;
60 public abstract class StatementContextBase<A, D extends DeclaredStatement<A>, E extends EffectiveStatement<A, D>>
61 extends NamespaceStorageSupport implements Mutable<A, D, E> {
63 * Event listener when an item is added to model namespace.
65 interface OnNamespaceItemAdded extends EventListener {
67 * Invoked whenever a new item is added to a namespace.
69 void namespaceItemAdded(StatementContextBase<?, ?, ?> context, Class<?> namespace, Object key, Object value);
73 * Event listener when a parsing {@link ModelProcessingPhase} is completed.
75 interface OnPhaseFinished extends EventListener {
77 * Invoked whenever a processing phase has finished.
79 boolean phaseFinished(StatementContextBase<?, ?, ?> context, ModelProcessingPhase phase);
83 * Interface for all mutations within an {@link ModelActionBuilder.InferenceAction}.
85 interface ContextMutation {
90 private static final Logger LOG = LoggerFactory.getLogger(StatementContextBase.class);
92 private final StatementDefinitionContext<A, D, E> definition;
93 private final StatementSourceReference statementDeclSource;
94 private final StmtContext<?, ?, ?> originalCtx;
95 private final CopyHistory copyHistory;
96 private final String rawArgument;
98 private Multimap<ModelProcessingPhase, OnPhaseFinished> phaseListeners = ImmutableMultimap.of();
99 private Multimap<ModelProcessingPhase, ContextMutation> phaseMutation = ImmutableMultimap.of();
100 private Collection<Mutable<?, ?, ?>> effective = ImmutableList.of();
101 private Collection<StmtContext<?, ?, ?>> effectOfStatement = ImmutableList.of();
102 private StatementMap substatements = StatementMap.empty();
104 private boolean isSupportedToBuildEffective = true;
105 private ModelProcessingPhase completedPhase = null;
106 private D declaredInstance;
107 private E effectiveInstance;
109 // BooleanFields value
110 private byte supportedByFeatures;
112 StatementContextBase(final StatementDefinitionContext<A, D, E> def, final StatementSourceReference ref,
113 final String rawArgument) {
114 this.definition = Preconditions.checkNotNull(def);
115 this.statementDeclSource = Preconditions.checkNotNull(ref);
116 this.rawArgument = def.internArgument(rawArgument);
117 this.copyHistory = CopyHistory.original();
118 this.originalCtx = null;
121 StatementContextBase(final StatementContextBase<A, D, E> original, final CopyType copyType) {
122 this.definition = Preconditions.checkNotNull(original.definition,
123 "Statement context definition cannot be null copying from: %s", original.getStatementSourceReference());
124 this.statementDeclSource = Preconditions.checkNotNull(original.statementDeclSource,
125 "Statement context statementDeclSource cannot be null copying from: %s",
126 original.getStatementSourceReference());
127 this.rawArgument = original.rawArgument;
128 this.copyHistory = CopyHistory.of(copyType, original.getCopyHistory());
129 this.originalCtx = original.getOriginalCtx().orElse(original);
133 public Collection<? extends StmtContext<?, ?, ?>> getEffectOfStatement() {
134 return effectOfStatement;
138 public void addAsEffectOfStatement(final StmtContext<?, ?, ?> ctx) {
139 if (effectOfStatement.isEmpty()) {
140 effectOfStatement = new ArrayList<>(1);
142 effectOfStatement.add(ctx);
146 public void addAsEffectOfStatement(final Collection<? extends StmtContext<?, ?, ?>> ctxs) {
147 if (ctxs.isEmpty()) {
151 if (effectOfStatement.isEmpty()) {
152 effectOfStatement = new ArrayList<>(ctxs.size());
154 effectOfStatement.addAll(ctxs);
158 public boolean isSupportedByFeatures() {
159 if (OptionalBoolean.isPresent(supportedByFeatures)) {
160 return OptionalBoolean.get(supportedByFeatures);
163 if (isIgnoringIfFeatures()) {
164 supportedByFeatures = OptionalBoolean.of(true);
168 final boolean isParentSupported = isParentSupportedByFeatures();
170 * If parent is not supported, then this context is also not supported.
171 * So we do not need to check if-features statements of this context and
172 * we can return false immediately.
174 if (!isParentSupported) {
175 supportedByFeatures = OptionalBoolean.of(false);
180 * If parent is supported, we need to check if-features statements of
183 // If the set of supported features has not been provided, all features are supported by default.
184 final Set<QName> supportedFeatures = getFromNamespace(SupportedFeaturesNamespace.class,
185 SupportedFeatures.SUPPORTED_FEATURES);
186 final boolean ret = supportedFeatures == null ? true
187 : StmtContextUtils.checkFeatureSupport(this, supportedFeatures);
189 supportedByFeatures = OptionalBoolean.of(ret);
193 protected abstract boolean isParentSupportedByFeatures();
195 protected abstract boolean isIgnoringIfFeatures();
197 protected abstract boolean isIgnoringConfig();
200 public boolean isSupportedToBuildEffective() {
201 return isSupportedToBuildEffective;
205 public void setIsSupportedToBuildEffective(final boolean isSupportedToBuildEffective) {
206 this.isSupportedToBuildEffective = isSupportedToBuildEffective;
210 public CopyHistory getCopyHistory() {
215 public Optional<StmtContext<?, ?, ?>> getOriginalCtx() {
216 return Optional.ofNullable(originalCtx);
220 public ModelProcessingPhase getCompletedPhase() {
221 return completedPhase;
225 public void setCompletedPhase(final ModelProcessingPhase completedPhase) {
226 this.completedPhase = completedPhase;
230 public abstract StatementContextBase<?, ?, ?> getParentContext();
233 * Returns the model root for this statement.
235 * @return root context of statement
239 public abstract RootStatementContext<?, ?, ?> getRoot();
242 * Returns the origin of the statement.
244 * @return origin of statement
248 public StatementSource getStatementSource() {
249 return statementDeclSource.getStatementSource();
253 * Returns a reference to statement source.
255 * @return reference of statement source
259 public StatementSourceReference getStatementSourceReference() {
260 return statementDeclSource;
264 public final String rawStatementArgument() {
270 public Collection<? extends StmtContext<?, ?, ?>> declaredSubstatements() {
271 return substatements.values();
276 public Collection<? extends Mutable<?, ?, ?>> mutableDeclaredSubstatements() {
277 return substatements.values();
281 public Collection<? extends StmtContext<?, ?, ?>> effectiveSubstatements() {
282 return mutableEffectiveSubstatements();
287 public Collection<? extends Mutable<?, ?, ?>> mutableEffectiveSubstatements() {
288 if (effective instanceof ImmutableCollection) {
292 return Collections.unmodifiableCollection(effective);
295 public void removeStatementsFromEffectiveSubstatements(
296 final Collection<? extends StmtContext<?, ?, ?>> substatements) {
297 if (!effective.isEmpty()) {
298 effective.removeAll(substatements);
303 private void shrinkEffective() {
304 if (effective.isEmpty()) {
305 effective = ImmutableList.of();
309 public void removeStatementFromEffectiveSubstatements(final StatementDefinition statementDef) {
310 if (effective.isEmpty()) {
314 final Iterator<? extends StmtContext<?, ?, ?>> iterator = effective.iterator();
315 while (iterator.hasNext()) {
316 final StmtContext<?, ?, ?> next = iterator.next();
317 if (statementDef.equals(next.getPublicDefinition())) {
326 * Removes a statement context from the effective substatements based on its statement definition (i.e statement
327 * keyword) and raw (in String form) statement argument. The statement context is removed only if both statement
328 * definition and statement argument match with one of the effective substatements' statement definition
332 * If the statementArg parameter is null, the statement context is removed based only on its statement definition.
334 * @param statementDef statement definition of the statement context to remove
335 * @param statementArg statement argument of the statement context to remove
337 public void removeStatementFromEffectiveSubstatements(final StatementDefinition statementDef,
338 final String statementArg) {
339 if (statementArg == null) {
340 removeStatementFromEffectiveSubstatements(statementDef);
343 if (effective.isEmpty()) {
347 final Iterator<Mutable<?, ?, ?>> iterator = effective.iterator();
348 while (iterator.hasNext()) {
349 final Mutable<?, ?, ?> next = iterator.next();
350 if (statementDef.equals(next.getPublicDefinition()) && statementArg.equals(next.rawStatementArgument())) {
359 * Adds an effective statement to collection of substatements.
361 * @param substatement substatement
362 * @throws IllegalStateException
363 * if added in declared phase
364 * @throws NullPointerException
365 * if statement parameter is null
367 public void addEffectiveSubstatement(final Mutable<?, ?, ?> substatement) {
368 beforeAddEffectiveStatement(1);
369 effective.add(substatement);
373 * Adds an effective statement to collection of substatements.
375 * @param substatements substatements
376 * @throws IllegalStateException
377 * if added in declared phase
378 * @throws NullPointerException
379 * if statement parameter is null
381 public void addEffectiveSubstatements(final Collection<? extends Mutable<?, ?, ?>> substatements) {
382 if (substatements.isEmpty()) {
386 substatements.forEach(Preconditions::checkNotNull);
387 beforeAddEffectiveStatement(substatements.size());
388 effective.addAll(substatements);
391 private void beforeAddEffectiveStatement(final int toAdd) {
392 final ModelProcessingPhase inProgressPhase = getRoot().getSourceContext().getInProgressPhase();
393 Preconditions.checkState(inProgressPhase == ModelProcessingPhase.FULL_DECLARATION
394 || inProgressPhase == ModelProcessingPhase.EFFECTIVE_MODEL,
395 "Effective statement cannot be added in declared phase at: %s", getStatementSourceReference());
397 if (effective.isEmpty()) {
398 effective = new ArrayList<>(toAdd);
403 * Create a new substatement at the specified offset.
405 * @param offset Substatement offset
406 * @param def definition context
407 * @param ref source reference
408 * @param argument statement argument
409 * @return A new substatement
411 @SuppressWarnings("checkstyle:methodTypeParameterName")
412 public final <CA, CD extends DeclaredStatement<CA>, CE extends EffectiveStatement<CA, CD>>
413 StatementContextBase<CA, CD, CE> createSubstatement(final int offset,
414 final StatementDefinitionContext<CA, CD, CE> def, final StatementSourceReference ref,
415 final String argument) {
416 final ModelProcessingPhase inProgressPhase = getRoot().getSourceContext().getInProgressPhase();
417 Preconditions.checkState(inProgressPhase != ModelProcessingPhase.EFFECTIVE_MODEL,
418 "Declared statement cannot be added in effective phase at: %s", getStatementSourceReference());
420 final Optional<StatementSupport<?, ?, ?>> implicitParent = definition.getImplicitParentFor(def.getPublicView());
421 if (implicitParent.isPresent()) {
422 return createImplicitParent(offset, implicitParent.get(), ref, argument).createSubstatement(offset, def,
426 final StatementContextBase<CA, CD, CE> ret = new SubstatementContext<>(this, def, ref, argument);
427 substatements = substatements.put(offset, ret);
428 def.onStatementAdded(ret);
432 private StatementContextBase<?, ?, ?> createImplicitParent(final int offset,
433 final StatementSupport<?, ?, ?> implicitParent, final StatementSourceReference ref, final String argument) {
434 final StatementDefinitionContext<?, ?, ?> def = new StatementDefinitionContext<>(implicitParent);
435 return createSubstatement(offset, def, ImplicitSubstatement.of(ref), argument);
439 * Lookup substatement by its offset in this statement.
441 * @param offset Substatement offset
442 * @return Substatement, or null if substatement does not exist.
444 final StatementContextBase<?, ?, ?> lookupSubstatement(final int offset) {
445 return substatements.get(offset);
449 public D buildDeclared() {
450 Preconditions.checkArgument(completedPhase == ModelProcessingPhase.FULL_DECLARATION
451 || completedPhase == ModelProcessingPhase.EFFECTIVE_MODEL);
452 if (declaredInstance == null) {
453 declaredInstance = definition().getFactory().createDeclared(this);
455 return declaredInstance;
459 public E buildEffective() {
460 if (effectiveInstance == null) {
461 effectiveInstance = definition().getFactory().createEffective(this);
463 return effectiveInstance;
467 * tries to execute current {@link ModelProcessingPhase} of source parsing.
470 * to be executed (completed)
471 * @return if phase was successfully completed
472 * @throws SourceException
473 * when an error occured in source parsing
475 boolean tryToCompletePhase(final ModelProcessingPhase phase) {
477 boolean finished = true;
478 final Collection<ContextMutation> openMutations = phaseMutation.get(phase);
479 if (!openMutations.isEmpty()) {
480 final Iterator<ContextMutation> it = openMutations.iterator();
481 while (it.hasNext()) {
482 final ContextMutation current = it.next();
483 if (current.isFinished()) {
490 if (openMutations.isEmpty()) {
491 phaseMutation.removeAll(phase);
492 if (phaseMutation.isEmpty()) {
493 phaseMutation = ImmutableMultimap.of();
498 for (final StatementContextBase<?, ?, ?> child : substatements.values()) {
499 finished &= child.tryToCompletePhase(phase);
501 for (final Mutable<?, ?, ?> child : effective) {
502 if (child instanceof StatementContextBase) {
503 finished &= ((StatementContextBase<?, ?, ?>) child).tryToCompletePhase(phase);
508 onPhaseCompleted(phase);
515 * Occurs on end of {@link ModelProcessingPhase} of source parsing.
518 * that was to be completed (finished)
519 * @throws SourceException
520 * when an error occurred in source parsing
522 private void onPhaseCompleted(final ModelProcessingPhase phase) {
523 completedPhase = phase;
525 final Collection<OnPhaseFinished> listeners = phaseListeners.get(phase);
526 if (listeners.isEmpty()) {
530 final Iterator<OnPhaseFinished> listener = listeners.iterator();
531 while (listener.hasNext()) {
532 final OnPhaseFinished next = listener.next();
533 if (next.phaseFinished(this, phase)) {
538 if (listeners.isEmpty()) {
539 phaseListeners.removeAll(phase);
540 if (phaseListeners.isEmpty()) {
541 phaseListeners = ImmutableMultimap.of();
547 * Ends declared section of current node.
549 void endDeclared(final StatementSourceReference ref, final ModelProcessingPhase phase) {
550 definition().onDeclarationFinished(this, phase);
554 * Return the context in which this statement was defined.
556 * @return statement definition
558 protected final StatementDefinitionContext<A, D, E> definition() {
563 protected void checkLocalNamespaceAllowed(final Class<? extends IdentifierNamespace<?, ?>> type) {
564 definition().checkNamespaceAllowed(type);
568 protected <K, V, N extends IdentifierNamespace<K, V>> void onNamespaceElementAdded(final Class<N> type, final K key,
570 // definition().onNamespaceElementAdded(this, type, key, value);
573 final <K, V, N extends IdentifierNamespace<K, V>> void onNamespaceItemAddedAction(final Class<N> type, final K key,
574 final OnNamespaceItemAdded listener) {
575 final Object potential = getFromNamespace(type, key);
576 if (potential != null) {
577 LOG.trace("Listener on {} key {} satisfied immediately", type, key);
578 listener.namespaceItemAdded(this, type, key, potential);
582 getBehaviour(type).addListener(new KeyedValueAddedListener<K>(this, key) {
584 void onValueAdded(final Object value) {
585 listener.namespaceItemAdded(StatementContextBase.this, type, key, value);
590 final <K, V, N extends IdentifierNamespace<K, V>> void onNamespaceItemAddedAction(final Class<N> type,
591 final ModelProcessingPhase phase, final NamespaceKeyCriterion<K> criterion,
592 final OnNamespaceItemAdded listener) {
593 final Optional<Entry<K, V>> existing = getFromNamespace(type, criterion);
594 if (existing.isPresent()) {
595 final Entry<K, V> entry = existing.get();
596 LOG.debug("Listener on {} criterion {} found a pre-existing match: {}", type, criterion, entry);
597 waitForPhase(entry.getValue(), type, phase, criterion, listener);
601 final NamespaceBehaviourWithListeners<K, V, N> behaviour = getBehaviour(type);
602 behaviour.addListener(new PredicateValueAddedListener<K, V>(this) {
604 boolean onValueAdded(final K key, final V value) {
605 if (criterion.match(key)) {
606 LOG.debug("Listener on {} criterion {} matched added key {}", type, criterion, key);
607 waitForPhase(value, type, phase, criterion, listener);
616 final <K, V, N extends IdentifierNamespace<K, V>> void selectMatch(final Class<N> type,
617 final NamespaceKeyCriterion<K> criterion, final OnNamespaceItemAdded listener) {
618 final Optional<Entry<K, V>> optMatch = getFromNamespace(type, criterion);
619 Preconditions.checkState(optMatch.isPresent(),
620 "Failed to find a match for criterion %s in namespace %s node %s", criterion, type, this);
621 final Entry<K, V> match = optMatch.get();
622 listener.namespaceItemAdded(StatementContextBase.this, type, match.getKey(), match.getValue());
625 final <K, V, N extends IdentifierNamespace<K, V>> void waitForPhase(final Object value, final Class<N> type,
626 final ModelProcessingPhase phase, final NamespaceKeyCriterion<K> criterion,
627 final OnNamespaceItemAdded listener) {
628 ((StatementContextBase<?, ? ,?>) value).addPhaseCompletedListener(phase,
629 (context, completedPhase) -> {
630 selectMatch(type, criterion, listener);
635 private <K, V, N extends IdentifierNamespace<K, V>> NamespaceBehaviourWithListeners<K, V, N> getBehaviour(
636 final Class<N> type) {
637 final NamespaceBehaviour<K, V, N> behaviour = getBehaviourRegistry().getNamespaceBehaviour(type);
638 Preconditions.checkArgument(behaviour instanceof NamespaceBehaviourWithListeners,
639 "Namespace %s does not support listeners", type);
641 return (NamespaceBehaviourWithListeners<K, V, N>) behaviour;
645 * See {@link StatementSupport#getPublicView()}.
649 public StatementDefinition getPublicDefinition() {
650 return definition().getPublicView();
654 public ModelActionBuilder newInferenceAction(final ModelProcessingPhase phase) {
655 return getRoot().getSourceContext().newInferenceAction(phase);
658 private static <T> Multimap<ModelProcessingPhase, T> newMultimap() {
659 return Multimaps.newListMultimap(new EnumMap<>(ModelProcessingPhase.class), () -> new ArrayList<>(1));
663 * Adds {@link OnPhaseFinished} listener for a {@link ModelProcessingPhase} end. If the base has already completed
664 * the listener is notified immediately.
666 * @param phase requested completion phase
667 * @param listener listener to invoke
668 * @throws NullPointerException if any of the arguments is null
670 void addPhaseCompletedListener(final ModelProcessingPhase phase, final OnPhaseFinished listener) {
671 Preconditions.checkNotNull(phase, "Statement context processing phase cannot be null at: %s",
672 getStatementSourceReference());
673 Preconditions.checkNotNull(listener, "Statement context phase listener cannot be null at: %s",
674 getStatementSourceReference());
676 ModelProcessingPhase finishedPhase = completedPhase;
677 while (finishedPhase != null) {
678 if (phase.equals(finishedPhase)) {
679 listener.phaseFinished(this, finishedPhase);
682 finishedPhase = finishedPhase.getPreviousPhase();
684 if (phaseListeners.isEmpty()) {
685 phaseListeners = newMultimap();
688 phaseListeners.put(phase, listener);
692 * Adds a {@link ContextMutation} to a {@link ModelProcessingPhase}.
694 * @throws IllegalStateException
695 * when the mutation was registered after phase was completed
697 void addMutation(final ModelProcessingPhase phase, final ContextMutation mutation) {
698 ModelProcessingPhase finishedPhase = completedPhase;
699 while (finishedPhase != null) {
700 Preconditions.checkState(!phase.equals(finishedPhase),
701 "Mutation registered after phase was completed at: %s", getStatementSourceReference());
702 finishedPhase = finishedPhase.getPreviousPhase();
705 if (phaseMutation.isEmpty()) {
706 phaseMutation = newMultimap();
708 phaseMutation.put(phase, mutation);
712 public <K, KT extends K, N extends StatementNamespace<K, ?, ?>> void addContext(final Class<N> namespace,
713 final KT key,final StmtContext<?, ?, ?> stmt) {
714 addContextToNamespace(namespace, key, stmt);
718 public <X, Y extends DeclaredStatement<X>, Z extends EffectiveStatement<X, Y>> Mutable<X, Y, Z> childCopyOf(
719 final StmtContext<X, Y, Z> stmt, final CopyType type, final QNameModule targetModule) {
720 Preconditions.checkState(stmt.getCompletedPhase() == ModelProcessingPhase.EFFECTIVE_MODEL,
721 "Attempted to copy statement %s which has completed phase %s", stmt, stmt.getCompletedPhase());
723 Preconditions.checkArgument(stmt instanceof SubstatementContext, "Unsupported statement %s", stmt);
725 final SubstatementContext<X, Y, Z> original = (SubstatementContext<X, Y, Z>)stmt;
726 final SubstatementContext<X, Y, Z> copy = new SubstatementContext<>(original, this, type, targetModule);
728 original.definition().onStatementAdded(copy);
729 original.copyTo(copy, type, targetModule);
734 final void copyTo(final StatementContextBase<?, ?, ?> target, final CopyType typeOfCopy,
735 @Nullable final QNameModule targetModule) {
736 final Collection<Mutable<?, ?, ?>> buffer = new ArrayList<>(substatements.size() + effective.size());
738 for (final Mutable<?, ?, ?> stmtContext : substatements.values()) {
739 if (stmtContext.isSupportedByFeatures()) {
740 copySubstatement(stmtContext, target, typeOfCopy, targetModule, buffer);
744 for (final Mutable<?, ?, ?> stmtContext : effective) {
745 copySubstatement(stmtContext, target, typeOfCopy, targetModule, buffer);
748 target.addEffectiveSubstatements(buffer);
751 private void copySubstatement(final Mutable<?, ?, ?> stmtContext, final Mutable<?, ?, ?> target,
752 final CopyType typeOfCopy, final QNameModule newQNameModule, final Collection<Mutable<?, ?, ?>> buffer) {
753 if (needToCopyByUses(stmtContext)) {
754 final Mutable<?, ?, ?> copy = target.childCopyOf(stmtContext, typeOfCopy, newQNameModule);
755 LOG.debug("Copying substatement {} for {} as", stmtContext, this, copy);
757 } else if (isReusedByUses(stmtContext)) {
758 LOG.debug("Reusing substatement {} for {}", stmtContext, this);
759 buffer.add(stmtContext);
761 LOG.debug("Skipping statement {}", stmtContext);
765 // FIXME: revise this, as it seems to be wrong
766 private static final Set<YangStmtMapping> NOCOPY_FROM_GROUPING_SET = ImmutableSet.of(
767 YangStmtMapping.DESCRIPTION,
768 YangStmtMapping.REFERENCE,
769 YangStmtMapping.STATUS);
770 private static final Set<YangStmtMapping> REUSED_DEF_SET = ImmutableSet.of(
771 YangStmtMapping.TYPE,
772 YangStmtMapping.TYPEDEF,
773 YangStmtMapping.USES);
775 private static boolean needToCopyByUses(final StmtContext<?, ?, ?> stmtContext) {
776 final StatementDefinition def = stmtContext.getPublicDefinition();
777 if (REUSED_DEF_SET.contains(def)) {
778 LOG.debug("Will reuse {} statement {}", def, stmtContext);
781 if (NOCOPY_FROM_GROUPING_SET.contains(def)) {
782 return !YangStmtMapping.GROUPING.equals(stmtContext.getParentContext().getPublicDefinition());
785 LOG.debug("Will copy {} statement {}", def, stmtContext);
789 private static boolean isReusedByUses(final StmtContext<?, ?, ?> stmtContext) {
790 return REUSED_DEF_SET.contains(stmtContext.getPublicDefinition());
794 public final String toString() {
795 return addToStringAttributes(MoreObjects.toStringHelper(this).omitNullValues()).toString();
798 protected ToStringHelper addToStringAttributes(final ToStringHelper toStringHelper) {
799 return toStringHelper.add("definition", definition).add("rawArgument", rawArgument);