/*
 * Copyright (c) 2014 Cisco Systems, Inc. and others.  All rights reserved.
 *
 * This program and the accompanying materials are made available under the
 * terms of the Eclipse Public License v1.0 which accompanies this distribution,
 * and is available at http://www.eclipse.org/legal/epl-v10.html
 */
package org.opendaylight.yangtools.yang.data.tree.impl;

import static java.util.Objects.requireNonNull;

import com.google.common.collect.ImmutableMap;
import java.util.concurrent.atomic.AtomicReferenceFieldUpdater;
import org.eclipse.jdt.annotation.NonNull;
import org.eclipse.jdt.annotation.Nullable;
import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier.AugmentationIdentifier;
import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier.PathArgument;
import org.opendaylight.yangtools.yang.data.tree.api.DataTreeConfiguration;
import org.opendaylight.yangtools.yang.data.tree.impl.AbstractNodeContainerModificationStrategy.Visible;
import org.opendaylight.yangtools.yang.model.api.AugmentationTarget;
import org.opendaylight.yangtools.yang.model.api.DataNodeContainer;
import org.opendaylight.yangtools.yang.model.api.DocumentedNode.WithStatus;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

/**
 * Base strategy for applying changes to a ContainerNode, irrespective of its
 * actual type.
 *
 * @param <T> Type of the container node
 */
class DataNodeContainerModificationStrategy<T extends DataNodeContainer & WithStatus> extends Visible<T> {
    private static final Logger LOG = LoggerFactory.getLogger(DataNodeContainerModificationStrategy.class);

    private final @NonNull DataTreeConfiguration treeConfig;

    @SuppressWarnings("rawtypes")
    private static final AtomicReferenceFieldUpdater<DataNodeContainerModificationStrategy, ImmutableMap> UPDATER =
            AtomicReferenceFieldUpdater.newUpdater(DataNodeContainerModificationStrategy.class, ImmutableMap.class,
                "children");
    private volatile ImmutableMap<PathArgument, ModificationApplyOperation> children = ImmutableMap.of();

    DataNodeContainerModificationStrategy(final NormalizedNodeContainerSupport<?, ?> support, final T schema,
            final DataTreeConfiguration treeConfig) {
        super(support, treeConfig, schema);
        this.treeConfig = requireNonNull(treeConfig, "treeConfig");
    }

    @Override
    public final ModificationApplyOperation childByArg(final PathArgument arg) {
        final var local = children;
        final var existing = local.get(arg);
        if (existing != null) {
            return existing;
        }

        final var childOperation = resolveChild(arg);
        return childOperation != null ? appendChild(local, arg, childOperation) : null;
    }

    private ModificationApplyOperation resolveChild(final PathArgument identifier) {
        final T schema = getSchema();
        if (identifier instanceof AugmentationIdentifier && schema instanceof AugmentationTarget) {
            return SchemaAwareApplyOperation.from(schema, (AugmentationTarget) schema,
                (AugmentationIdentifier) identifier, treeConfig);
        }

        final var qname = identifier.getNodeType();
        final var child = schema.dataChildByName(qname);
        if (child == null) {
            LOG.trace("Child {} not present in container schema {} children {}", identifier, this,
                schema.getChildNodes());
            return null;
        }

        try {
            return SchemaAwareApplyOperation.from(child, treeConfig);
        } catch (ExcludedDataSchemaNodeException e) {
            LOG.trace("Failed to instantiate child {} in container schema {} children {}", identifier, this,
                schema.getChildNodes(), e);
            return null;
        }
    }

    private @Nullable ModificationApplyOperation appendChild(
            final ImmutableMap<PathArgument, ModificationApplyOperation> initial, final PathArgument identifier,
            final ModificationApplyOperation computed) {
        var previous = initial;
        while (true) {
            // Build up a new map based on observed snapshot and computed child
            final var updated = ImmutableMap
                .<PathArgument, ModificationApplyOperation>builderWithExpectedSize(previous.size() + 1)
                .putAll(previous)
                .put(identifier, computed)
                .build();

            // Attempt to install the updated map
            if (UPDATER.compareAndSet(this, previous, updated)) {
                return computed;
            }

            // We have raced, acquire a new snapshot, recheck presence and retry if needed
            previous = children;
            final var raced = previous.get(identifier);
            if (raced != null) {
                return raced;
            }
        }
    }
}

@@ -2923,16 +2923,22 @@
 ntifier 
+augId 
 && schem
@@ -2968,16 +2968,26 @@
 onTarget
+ augTarget
 ) %7B%0A    
@@ -3044,88 +3044,24 @@
 ma, 
-(AugmentationTarget) schema,%0A                (AugmentationIdentifier) identifier
+augTarget, augId
 , tr

Use instanceof pattern