Bug 2444 - Add missing API to Action and Notification definition 55/59655/16
authorPeter Kajsa <pkajsa@cisco.com>
Thu, 29 Jun 2017 08:34:12 +0000 (10:34 +0200)
committerRobert Varga <nite@hq.sk>
Wed, 11 Oct 2017 10:43:32 +0000 (10:43 +0000)
Since Yang 1.1, it is allowed to use notification and action
statements also in grouping and augment statements. However,
yang-model-api does not reflect this changes. This patch
adds missing methods to check the origin of notifications and
actions. Required fix of yang-model-export is included as well.

Change-Id: Iba7282e3be4361bba8e6328a57fbbe0cb115a1f5
Signed-off-by: Peter Kajsa <pkajsa@cisco.com>
yang/yang-model-api/src/main/java/org/opendaylight/yangtools/yang/model/api/ActionDefinition.java
yang/yang-model-api/src/main/java/org/opendaylight/yangtools/yang/model/api/CopyableNode.java [new file with mode: 0644]
yang/yang-model-api/src/main/java/org/opendaylight/yangtools/yang/model/api/DataSchemaNode.java
yang/yang-model-api/src/main/java/org/opendaylight/yangtools/yang/model/api/NotificationDefinition.java
yang/yang-model-export/src/main/java/org/opendaylight/yangtools/yang/model/export/SchemaContextEmitter.java
yang/yang-model-export/src/test/java/org/opendaylight/yangtools/yang/model/export/EffectiveSchemaContextEmitterTest.java [new file with mode: 0644]
yang/yang-model-export/src/test/java/org/opendaylight/yangtools/yang/model/export/test/Bug2444Test.java
yang/yang-model-export/src/test/java/org/opendaylight/yangtools/yang/model/export/test/YinExportTestUtils.java
yang/yang-model-export/src/test/resources/bugs/bug2444/yin-effective-emitter/notification@1970-01-01.yin [new file with mode: 0644]
yang/yang-parser-impl/src/main/java/org/opendaylight/yangtools/yang/parser/stmt/rfc6020/effective/NotificationEffectiveStatementImpl.java
yang/yang-parser-impl/src/main/java/org/opendaylight/yangtools/yang/parser/stmt/rfc7950/effective/ActionEffectiveStatementImpl.java

index 3940ee0db659a961f55894e96833af252818c638..f304b2d2d87ae546ddd754b73265c9d8c7ee09c2 100644 (file)
@@ -20,6 +20,5 @@ import com.google.common.annotations.Beta;
  * detailed action information.  The argument is the name of the action.
  */
 @Beta
-public interface ActionDefinition extends OperationDefinition {
-
+public interface ActionDefinition extends OperationDefinition, CopyableNode {
 }
diff --git a/yang/yang-model-api/src/main/java/org/opendaylight/yangtools/yang/model/api/CopyableNode.java b/yang/yang-model-api/src/main/java/org/opendaylight/yangtools/yang/model/api/CopyableNode.java
new file mode 100644 (file)
index 0000000..4dba5a2
--- /dev/null
@@ -0,0 +1,34 @@
+/*
+ * Copyright (c) 2017 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.model.api;
+
+import com.google.common.annotations.Beta;
+
+/**
+ * Represents a node that can be added by uses or by augmentation.
+ */
+@Beta
+public interface CopyableNode {
+    /**
+     * Returns <code>true</code> if this node was added by augmentation,
+     * otherwise returns <code>false</code>.
+     *
+     * @return <code>true</code> if this node was added by augmentation,
+     *         otherwise returns <code>false</code>
+     */
+    boolean isAugmenting();
+
+    /**
+     * Returns <code>true</code> if this node was added by uses statement,
+     * otherwise returns <code>false</code>.
+     *
+     * @return <code>true</code> if this node was added by uses statement,
+     *         otherwise returns <code>false</code>
+     */
+    boolean isAddedByUses();
+}
index 4c27eacd4760e1ffdde0ad5e9c09258c571794b6..3bf46fa6170a5d74b4458b3f451bcf04c46c8290 100644 (file)
@@ -24,25 +24,7 @@ package org.opendaylight.yangtools.yang.model.api;
  * @see AnyXmlSchemaNode
  * @see AnyDataSchemaNode
  */
-public interface DataSchemaNode extends SchemaNode {
-    /**
-     * Returns <code>true</code> if the data node was added by augmentation,
-     * otherwise returns <code>false</code>.
-     *
-     * @return <code>true</code> if the data node was added by augmentation,
-     *         otherwise returns <code>false</code>
-     */
-    boolean isAugmenting();
-
-    /**
-     * Returns <code>true</code> if the data node was added by uses statement,
-     * otherwise returns <code>false</code>.
-     *
-     * @return <code>true</code> if the data node was added by uses statement,
-     *         otherwise returns <code>false</code>
-     */
-    boolean isAddedByUses();
-
+public interface DataSchemaNode extends SchemaNode, CopyableNode {
     /**
      * Returns <code>true</code> if the data represents configuration data,
      * otherwise returns <code>false</code>.
index 06683d9612e269d0ea773f328de1ac5df5f97448..95d1dd3cb860bd21940d8dea132776d4c7d48ec3 100644 (file)
@@ -13,7 +13,7 @@ import javax.annotation.Nullable;
  * Interface describing YANG 'notification' statement. The notification
  * statement is used to define a NETCONF notification.
  */
-public interface NotificationDefinition extends SchemaNode, DataNodeContainer, AugmentationTarget {
+public interface NotificationDefinition extends SchemaNode, DataNodeContainer, AugmentationTarget, CopyableNode {
 
     /**
      * All implementations should override this method.
index 9a37e3ecfd46c775bac38fb6871d80255fd97955..ebfb5acfaf78872df49b6ba93c43128cc82df056 100644 (file)
@@ -1810,9 +1810,6 @@ abstract class SchemaContextEmitter {
 
         private void emitContainer(final ContainerSchemaNode child) {
             super.writer.startContainerNode(child.getQName());
-
-            //
-
             emitConstraints(child.getConstraints());
             // FIXME: BUG-2444: whenNode //:Optional
             // FIXME: BUG-2444: *(ifFeatureNode )
@@ -2229,8 +2226,10 @@ abstract class SchemaContextEmitter {
         }
 
         private void emitAction(final ActionDefinition action) {
-            // :FIXME add addedByUses & addedByAugmentation in API and perform
-            // check here..
+            if (!super.emitInstantiated && (action.isAddedByUses() || action.isAugmenting())) {
+                // We skip instantiated nodes.
+                return;
+            }
             super.writer.startActionNode(action.getQName());
             emitOperationBody(action);
             super.writer.endNode();
@@ -2269,8 +2268,10 @@ abstract class SchemaContextEmitter {
         }
 
         private void emitNotificationNode(final NotificationDefinition notification) {
-            // :FIXME add addedByUses & addedByAugmentation in API and perform
-            // check here..
+            if (!super.emitInstantiated && (notification.isAddedByUses() || notification.isAugmenting())) {
+                // We skip instantiated nodes.
+                return;
+            }
 
             super.writer.startNotificationNode(notification.getQName());
             // FIXME: BUG-2444: *(ifFeatureNode )
diff --git a/yang/yang-model-export/src/test/java/org/opendaylight/yangtools/yang/model/export/EffectiveSchemaContextEmitterTest.java b/yang/yang-model-export/src/test/java/org/opendaylight/yangtools/yang/model/export/EffectiveSchemaContextEmitterTest.java
new file mode 100644 (file)
index 0000000..00b7403
--- /dev/null
@@ -0,0 +1,135 @@
+/*
+ * Copyright (c) 2017 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.model.export;
+
+import static org.junit.Assert.assertNotEquals;
+import static org.junit.Assert.assertNotNull;
+
+import com.google.common.collect.BiMap;
+import com.google.common.collect.HashBiMap;
+import java.io.BufferedOutputStream;
+import java.io.ByteArrayOutputStream;
+import java.io.File;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.io.OutputStream;
+import java.net.URI;
+import java.util.Map;
+import javax.xml.stream.XMLOutputFactory;
+import javax.xml.stream.XMLStreamException;
+import javax.xml.stream.XMLStreamWriter;
+import org.custommonkey.xmlunit.Diff;
+import org.custommonkey.xmlunit.ElementNameAndAttributeQualifier;
+import org.custommonkey.xmlunit.XMLAssert;
+import org.custommonkey.xmlunit.XMLUnit;
+import org.junit.Test;
+import org.opendaylight.yangtools.yang.common.QName;
+import org.opendaylight.yangtools.yang.common.SimpleDateFormatUtil;
+import org.opendaylight.yangtools.yang.common.YangVersion;
+import org.opendaylight.yangtools.yang.model.api.Module;
+import org.opendaylight.yangtools.yang.model.api.ModuleImport;
+import org.opendaylight.yangtools.yang.model.api.SchemaContext;
+import org.opendaylight.yangtools.yang.model.api.meta.StatementDefinition;
+import org.opendaylight.yangtools.yang.model.export.SchemaContextEmitter.EffectiveSchemaContextEmitter;
+import org.opendaylight.yangtools.yang.model.export.test.YinExportTestUtils;
+import org.opendaylight.yangtools.yang.test.util.YangParserTestUtils;
+import org.w3c.dom.Document;
+import org.xml.sax.SAXException;
+
+public class EffectiveSchemaContextEmitterTest {
+    @Test
+    public void test() throws Exception {
+        final SchemaContext schema = YangParserTestUtils.parseYangResource("/bugs/bug2444/yang/notification.yang");
+        assertNotNull(schema);
+
+        final File outDir = new File("target/bug2444-export");
+        outDir.mkdirs();
+
+        for (final Module module : schema.getModules()) {
+            exportModule(schema, module, outDir);
+            final OutputStream byteArrayOutputStream = new ByteArrayOutputStream();
+            final BufferedOutputStream bufferedOutputStream = new BufferedOutputStream(byteArrayOutputStream);
+            try {
+                writeModuleToOutputStream(schema, module, bufferedOutputStream, false);
+                final String output = byteArrayOutputStream.toString();
+                assertNotNull(output);
+                assertNotEquals(0, output.length());
+
+                final Document doc = YinExportTestUtils
+                        .loadDocument(String.format("/bugs/bug2444/yin-effective-emitter/%s@%s.yin", module.getName(),
+                                SimpleDateFormatUtil.getRevisionFormat().format(module.getRevision())));
+                assertXMLEquals(doc, output);
+            } finally {
+                byteArrayOutputStream.close();
+                bufferedOutputStream.close();
+            }
+        }
+    }
+
+    private static void writeModuleToOutputStream(final SchemaContext ctx, final Module module, final OutputStream str,
+            final boolean emitInstantiated) throws XMLStreamException {
+        final XMLOutputFactory factory = XMLOutputFactory.newFactory();
+        final XMLStreamWriter xmlStreamWriter = factory.createXMLStreamWriter(str);
+        writeModuleToOutputStream(ctx, module, xmlStreamWriter, emitInstantiated);
+        xmlStreamWriter.flush();
+    }
+
+    private static void writeModuleToOutputStream(final SchemaContext ctx, final Module module,
+            final XMLStreamWriter xmlStreamWriter, final boolean emitInstantiated) {
+        final URI moduleNs = module.getNamespace();
+        final Map<String, URI> prefixToNs = prefixToNamespace(ctx, module);
+        final StatementTextWriter statementWriter = SingleModuleYinStatementWriter.create(xmlStreamWriter, moduleNs,
+                prefixToNs);
+        final YangModuleWriter yangSchemaWriter = SchemaToStatementWriterAdaptor.from(statementWriter);
+        final Map<QName, StatementDefinition> extensions = ExtensionStatement.mapFrom(ctx.getExtensions());
+        new EffectiveSchemaContextEmitter(yangSchemaWriter, extensions,
+                YangVersion.parse(module.getYangVersion()).orElse(null), emitInstantiated).emitModule(module);
+    }
+
+    private static Map<String, URI> prefixToNamespace(final SchemaContext ctx, final Module module) {
+        final BiMap<String, URI> prefixMap = HashBiMap.create(module.getImports().size() + 1);
+        prefixMap.put(module.getPrefix(), module.getNamespace());
+        for (final ModuleImport imp : module.getImports()) {
+            final String prefix = imp.getPrefix();
+            final URI namespace = getModuleNamespace(ctx, imp.getModuleName());
+            prefixMap.put(prefix, namespace);
+        }
+        return prefixMap;
+    }
+
+    private static URI getModuleNamespace(final SchemaContext ctx, final String moduleName) {
+        for (final Module module : ctx.getModules()) {
+            if (moduleName.equals(module.getName())) {
+                return module.getNamespace();
+            }
+        }
+        throw new IllegalArgumentException("Module " + moduleName + "does not exists in provided schema context");
+    }
+
+    private static File exportModule(final SchemaContext schemaContext, final Module module, final File outDir)
+            throws Exception {
+        final File outFile = new File(outDir, YinExportUtils.wellFormedYinName(module.getName(), module.getRevision()));
+        try (OutputStream output = new FileOutputStream(outFile)) {
+            writeModuleToOutputStream(schemaContext, module, output, false);
+        }
+        return outFile;
+    }
+
+    private static void assertXMLEquals(final Document expectedXMLDoc, final String output)
+            throws SAXException, IOException {
+        final String expected = YinExportTestUtils.toString(expectedXMLDoc.getDocumentElement());
+
+        XMLUnit.setIgnoreWhitespace(true);
+        XMLUnit.setNormalize(true);
+        XMLUnit.setNormalizeWhitespace(true);
+
+        final Diff diff = new Diff(expected, output);
+        diff.overrideElementQualifier(new ElementNameAndAttributeQualifier());
+        XMLAssert.assertXMLEqual(diff, true);
+    }
+}
index 34ceedb09f491b71efe969ab3ae540c6a40d3edf..d96f600146ae62dd8c67d8068890b6368825a6a3 100644 (file)
@@ -55,7 +55,7 @@ public class Bug2444Test {
         }
     }
 
-    private ImmutableSet<Module> getAllModulesAndSubmodules(final SchemaContext schema) {
+    private static ImmutableSet<Module> getAllModulesAndSubmodules(final SchemaContext schema) {
         final Builder<Module> builder = ImmutableSet.builder();
         builder.addAll(schema.getModules());
         for (final Module module : schema.getModules()) {
index 6141bcfb32dcd5a769fc1b92f2179980905ec77c..7cf35e8d798ab17c115abd8c0b2c57a099f609b7 100644 (file)
@@ -29,7 +29,7 @@ public class YinExportTestUtils {
         throw new UnsupportedOperationException("Utility class");
     }
 
-    static Document loadDocument(final String xmlPath) throws IOException, SAXException {
+    public static Document loadDocument(final String xmlPath) throws IOException, SAXException {
         final InputStream resourceAsStream = SchemaContextEmitterTest.class.getResourceAsStream(xmlPath);
         final Document currentConfigElement = readXmlToDocument(resourceAsStream);
         Preconditions.checkNotNull(currentConfigElement);
@@ -42,7 +42,7 @@ public class YinExportTestUtils {
         return doc;
     }
 
-    static String toString(final Node xml) {
+    public static String toString(final Node xml) {
         try {
             final Transformer transformer = TransformerFactory.newInstance().newTransformer();
             transformer.setOutputProperty(OutputKeys.INDENT, "yes");
diff --git a/yang/yang-model-export/src/test/resources/bugs/bug2444/yin-effective-emitter/notification@1970-01-01.yin b/yang/yang-model-export/src/test/resources/bugs/bug2444/yin-effective-emitter/notification@1970-01-01.yin
new file mode 100644 (file)
index 0000000..8b996e1
--- /dev/null
@@ -0,0 +1,51 @@
+<module xmlns="urn:ietf:params:xml:ns:yang:yin:1" xmlns:n="notification"
+    name="notification">
+    <yang-version value="1.1"></yang-version>
+    <namespace uri="notification"></namespace>
+    <prefix value="n"></prefix>
+    <revision date="1970-01-01"></revision>
+    <grouping name="grp">
+        <status value="current"></status>
+        <notification name="n5">
+            <status value="current"></status>
+        </notification>
+    </grouping>
+    <container name="r">
+        <presence value="false"></presence>
+        <config value="true"></config>
+        <status value="current"></status>
+        <notification name="n2">
+            <status value="current"></status>
+        </notification>
+    </container>
+    <list name="l">
+        <key value="id"></key>
+        <config value="true"></config>
+        <ordered-by value="system"></ordered-by>
+        <status value="current"></status>
+        <leaf name="id">
+            <type name="int16"></type>
+            <config value="true"></config>
+            <mandatory value="false"></mandatory>
+            <status value="current"></status>
+        </leaf>
+        <notification name="n3">
+            <status value="current"></status>
+        </notification>
+    </list>
+    <augment target-node="/r">
+        <status value="current"></status>
+        <uses name="grp"></uses>
+        <notification name="n4">
+            <status value="current"></status>
+        </notification>
+    </augment>
+    <notification name="n1">
+        <status value="deprecated"></status>
+        <container name="c">
+            <presence value="false"></presence>
+            <config value="true"></config>
+            <status value="current"></status>
+        </container>
+    </notification>
+</module>
\ No newline at end of file
index 3eae1c0befd65c939a96052a34d4335b4171e0d4..32dedfe635a8d088205c2cea1af92e7facce8388 100644 (file)
@@ -23,6 +23,8 @@ import org.opendaylight.yangtools.yang.model.api.SchemaPath;
 import org.opendaylight.yangtools.yang.model.api.UnknownSchemaNode;
 import org.opendaylight.yangtools.yang.model.api.meta.EffectiveStatement;
 import org.opendaylight.yangtools.yang.model.api.stmt.NotificationStatement;
+import org.opendaylight.yangtools.yang.parser.spi.meta.CopyHistory;
+import org.opendaylight.yangtools.yang.parser.spi.meta.CopyType;
 import org.opendaylight.yangtools.yang.parser.spi.meta.StmtContext;
 
 public class NotificationEffectiveStatementImpl extends
@@ -32,6 +34,8 @@ public class NotificationEffectiveStatementImpl extends
     private final ConstraintDefinition constraints;
     private final Set<AugmentationSchema> augmentations;
     private final List<UnknownSchemaNode> unknownNodes;
+    private final boolean augmenting;
+    private final boolean addedByUses;
 
     public NotificationEffectiveStatementImpl(
             final StmtContext<QName, NotificationStatement, EffectiveStatement<QName, NotificationStatement>> ctx) {
@@ -42,20 +46,29 @@ public class NotificationEffectiveStatementImpl extends
         this.constraints = EffectiveConstraintDefinitionImpl.forParent(this);
 
         // initSubstatementCollections
-        List<UnknownSchemaNode> unknownNodesInit = new ArrayList<>();
-        Set<AugmentationSchema> augmentationsInit = new LinkedHashSet<>();
-        for (EffectiveStatement<?, ?> effectiveStatement : effectiveSubstatements()) {
+        final List<UnknownSchemaNode> unknownNodesInit = new ArrayList<>();
+        final Set<AugmentationSchema> augmentationsInit = new LinkedHashSet<>();
+        for (final EffectiveStatement<?, ?> effectiveStatement : effectiveSubstatements()) {
             if (effectiveStatement instanceof UnknownSchemaNode) {
-                UnknownSchemaNode unknownNode = (UnknownSchemaNode) effectiveStatement;
+                final UnknownSchemaNode unknownNode = (UnknownSchemaNode) effectiveStatement;
                 unknownNodesInit.add(unknownNode);
             }
             if (effectiveStatement instanceof AugmentationSchema) {
-                AugmentationSchema augmentationSchema = (AugmentationSchema) effectiveStatement;
+                final AugmentationSchema augmentationSchema = (AugmentationSchema) effectiveStatement;
                 augmentationsInit.add(augmentationSchema);
             }
         }
         this.unknownNodes = ImmutableList.copyOf(unknownNodesInit);
         this.augmentations = ImmutableSet.copyOf(augmentationsInit);
+
+        // initCopyType
+        final CopyHistory copyTypesFromOriginal = ctx.getCopyHistory();
+        if (copyTypesFromOriginal.contains(CopyType.ADDED_BY_USES_AUGMENTATION)) {
+            this.addedByUses = this.augmenting = true;
+        } else {
+            this.augmenting = copyTypesFromOriginal.contains(CopyType.ADDED_BY_AUGMENTATION);
+            this.addedByUses = copyTypesFromOriginal.contains(CopyType.ADDED_BY_USES);
+        }
     }
 
     @Nonnull
@@ -86,6 +99,16 @@ public class NotificationEffectiveStatementImpl extends
         return unknownNodes;
     }
 
+    @Override
+    public boolean isAugmenting() {
+        return augmenting;
+    }
+
+    @Override
+    public boolean isAddedByUses() {
+        return addedByUses;
+    }
+
     @Override
     public int hashCode() {
         final int prime = 31;
index 1a4ee61bed80081203116dd7cd2a940fdb0206f1..18d5a02f6400333c5f3b72b41bf61f3354a6f676 100644 (file)
@@ -21,6 +21,8 @@ import org.opendaylight.yangtools.yang.model.api.GroupingDefinition;
 import org.opendaylight.yangtools.yang.model.api.TypeDefinition;
 import org.opendaylight.yangtools.yang.model.api.meta.EffectiveStatement;
 import org.opendaylight.yangtools.yang.model.api.stmt.ActionStatement;
+import org.opendaylight.yangtools.yang.parser.spi.meta.CopyHistory;
+import org.opendaylight.yangtools.yang.parser.spi.meta.CopyType;
 import org.opendaylight.yangtools.yang.parser.spi.meta.StmtContext;
 import org.opendaylight.yangtools.yang.parser.stmt.rfc6020.effective.AbstractEffectiveSchemaNode;
 import org.opendaylight.yangtools.yang.parser.stmt.rfc6020.effective.EffectiveStmtUtils;
@@ -34,6 +36,8 @@ public class ActionEffectiveStatementImpl extends AbstractEffectiveSchemaNode<Ac
     private final ContainerSchemaNode output;
     private final Set<TypeDefinition<?>> typeDefinitions;
     private final Set<GroupingDefinition> groupings;
+    private final boolean augmenting;
+    private final boolean addedByUses;
 
     public ActionEffectiveStatementImpl(
             final StmtContext<QName, ActionStatement, EffectiveStatement<QName, ActionStatement>> ctx) {
@@ -42,16 +46,16 @@ public class ActionEffectiveStatementImpl extends AbstractEffectiveSchemaNode<Ac
         this.output = firstEffective(OutputEffectiveStatementImpl.class);
 
         // initSubstatements
-        Set<GroupingDefinition> groupingsInit = new HashSet<>();
-        Set<TypeDefinition<?>> mutableTypeDefinitions = new LinkedHashSet<>();
-        for (EffectiveStatement<?, ?> effectiveStatement : effectiveSubstatements()) {
+        final Set<GroupingDefinition> groupingsInit = new HashSet<>();
+        final Set<TypeDefinition<?>> mutableTypeDefinitions = new LinkedHashSet<>();
+        for (final EffectiveStatement<?, ?> effectiveStatement : effectiveSubstatements()) {
             if (effectiveStatement instanceof GroupingDefinition) {
-                GroupingDefinition groupingDefinition = (GroupingDefinition) effectiveStatement;
+                final GroupingDefinition groupingDefinition = (GroupingDefinition) effectiveStatement;
                 groupingsInit.add(groupingDefinition);
             }
             if (effectiveStatement instanceof TypeDefEffectiveStatementImpl) {
-                TypeDefEffectiveStatementImpl typeDef = (TypeDefEffectiveStatementImpl) effectiveStatement;
-                TypeDefinition<?> type = typeDef.getTypeDefinition();
+                final TypeDefEffectiveStatementImpl typeDef = (TypeDefEffectiveStatementImpl) effectiveStatement;
+                final TypeDefinition<?> type = typeDef.getTypeDefinition();
                 if (!mutableTypeDefinitions.contains(type)) {
                     mutableTypeDefinitions.add(type);
                 } else {
@@ -61,6 +65,15 @@ public class ActionEffectiveStatementImpl extends AbstractEffectiveSchemaNode<Ac
         }
         this.groupings = ImmutableSet.copyOf(groupingsInit);
         this.typeDefinitions = ImmutableSet.copyOf(mutableTypeDefinitions);
+
+        // initCopyType
+        final CopyHistory copyTypesFromOriginal = ctx.getCopyHistory();
+        if (copyTypesFromOriginal.contains(CopyType.ADDED_BY_USES_AUGMENTATION)) {
+            this.addedByUses = this.augmenting = true;
+        } else {
+            this.augmenting = copyTypesFromOriginal.contains(CopyType.ADDED_BY_AUGMENTATION);
+            this.addedByUses = copyTypesFromOriginal.contains(CopyType.ADDED_BY_USES);
+        }
     }
 
     @Override
@@ -83,6 +96,16 @@ public class ActionEffectiveStatementImpl extends AbstractEffectiveSchemaNode<Ac
         return groupings;
     }
 
+    @Override
+    public boolean isAugmenting() {
+        return augmenting;
+    }
+
+    @Override
+    public boolean isAddedByUses() {
+        return addedByUses;
+    }
+
     @Override
     public int hashCode() {
         return Objects.hash(getQName(), getPath());