Introduced new checked exception ModifiedNodeDoesNotExists.
This exception is thrown when node which has subtree
modification did not exist at time of transaction allocation
and also do not exist when allocation was processed
to be commited.
Change-Id: I54f040034b43bfaf4bdda089ad9d2378ddd6ab09
Signed-off-by: Tony Tkacik <ttkacik@cisco.com>
--- /dev/null
+/*
+ * 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.api.schema.tree;
+
+import org.opendaylight.yangtools.yang.data.api.InstanceIdentifier;
+
+/**
+ * Exception thrown when a proposed change fails validation before being
+ * applied into the Data Tree because tree node which child nodes are
+ * modified or written did not exist when transaction started
+ * and still does not exists when transaction is processed.
+ *
+ * Note if node existed in first place and was removed by other transaction,
+ * thrown exception should be {@link ConflictingModificationAppliedException}.
+ *
+ *
+ */
+public class ModifiedNodeDoesNotExistException extends DataValidationFailedException {
+
+ /**
+ *
+ */
+ private static final long serialVersionUID = 1L;
+
+ public ModifiedNodeDoesNotExistException(final InstanceIdentifier path, final String message, final Throwable cause) {
+ super(path, message, cause);
+ }
+
+ public ModifiedNodeDoesNotExistException(final InstanceIdentifier path, final String message) {
+ super(path, message);
+ }
+
+}
*/
package org.opendaylight.yangtools.yang.data.impl.schema.tree;
-import com.google.common.base.Optional;
-import com.google.common.collect.ImmutableMap;
-import com.google.common.collect.Iterables;
+import static com.google.common.base.Preconditions.checkArgument;
+
+import java.util.Map;
+
import org.opendaylight.yangtools.yang.data.api.InstanceIdentifier;
import org.opendaylight.yangtools.yang.data.api.InstanceIdentifier.NodeIdentifier;
import org.opendaylight.yangtools.yang.data.api.InstanceIdentifier.NodeIdentifierWithPredicates;
import org.opendaylight.yangtools.yang.data.api.schema.OrderedMapNode;
import org.opendaylight.yangtools.yang.data.api.schema.tree.DataValidationFailedException;
import org.opendaylight.yangtools.yang.data.api.schema.tree.ModificationType;
+import org.opendaylight.yangtools.yang.data.api.schema.tree.ModifiedNodeDoesNotExistException;
import org.opendaylight.yangtools.yang.data.api.schema.tree.spi.MutableTreeNode;
import org.opendaylight.yangtools.yang.data.api.schema.tree.spi.TreeNode;
import org.opendaylight.yangtools.yang.data.api.schema.tree.spi.TreeNodeFactory;
import org.opendaylight.yangtools.yang.model.api.LeafListSchemaNode;
import org.opendaylight.yangtools.yang.model.api.ListSchemaNode;
-import java.util.Map;
-
-import static com.google.common.base.Preconditions.checkArgument;
+import com.google.common.base.Optional;
+import com.google.common.collect.ImmutableMap;
+import com.google.common.collect.Iterables;
abstract class NormalizedNodeContainerModificationStrategy extends SchemaAwareApplyOperation {
@Override
protected void checkSubtreeModificationApplicable(final InstanceIdentifier path, final NodeModification modification,
final Optional<TreeNode> current) throws DataValidationFailedException {
+ checkDoesNotExists(path, modification.getOriginal().isPresent() || current.isPresent(), "Node does not exist. Could not modify its children.");
SchemaAwareApplyOperation.checkConflicting(path, current.isPresent(), "Node was deleted by other transaction.");
checkChildPreconditions(path, modification, current);
}
+ private static void checkDoesNotExists(final InstanceIdentifier path, final boolean condition, final String message) throws DataValidationFailedException {
+ if(!condition) {
+ throw new ModifiedNodeDoesNotExistException(path,message);
+ }
+ }
+
private void checkChildPreconditions(final InstanceIdentifier path, final NodeModification modification, final Optional<TreeNode> current) throws DataValidationFailedException {
final TreeNode currentMeta = current.get();
for (NodeModification childMod : modification.getChildren()) {
--- /dev/null
+/*
+ * 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.impl.schema.tree;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.fail;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.opendaylight.yangtools.yang.data.api.schema.tree.ConflictingModificationAppliedException;
+import org.opendaylight.yangtools.yang.data.api.schema.tree.DataValidationFailedException;
+import org.opendaylight.yangtools.yang.data.api.schema.tree.ModifiedNodeDoesNotExistException;
+import org.opendaylight.yangtools.yang.data.impl.schema.ImmutableNodes;
+
+public class ErrorReportingTest {
+
+ private InMemoryDataTree tree;
+
+ @Before
+ public void setup() {
+ tree = InMemoryDataTreeFactory.getInstance().create();
+ tree.setSchemaContext(TestModel.createTestContext());
+ }
+
+ @Test
+ public void writeWithoutParentExisting() {
+ InMemoryDataTreeModification modification = tree.takeSnapshot().newModification();
+ // We write node without creating parent
+ modification.write(TestModel.OUTER_LIST_PATH, ImmutableNodes.mapNodeBuilder(TestModel.OUTER_LIST_QNAME).build());
+ modification.ready();
+ try {
+ tree.validate(modification);
+ fail("ModifiedNodeDoesNotExistException should be raised");
+ } catch (ModifiedNodeDoesNotExistException e) {
+ assertEquals(TestModel.TEST_PATH, e.getPath());
+ } catch (DataValidationFailedException e) {
+ fail("ModifiedNodeDoesNotExistException expected");
+ }
+ }
+
+ @Test
+ public void parentConcurrentlyDeletedExisting() {
+ InMemoryDataTreeModification initial = tree.takeSnapshot().newModification();
+ // We write node without creating parent
+ initial.write(TestModel.TEST_PATH, ImmutableNodes.containerNode(TestModel.TEST_QNAME));
+ initial.ready();
+ // We commit transaction
+ tree.commit(tree.prepare(initial));
+
+ InMemoryDataTreeModification writeTx = tree.takeSnapshot().newModification();
+ InMemoryDataTreeModification deleteTx = tree.takeSnapshot().newModification();
+ deleteTx.delete(TestModel.TEST_PATH);
+ deleteTx.ready();
+ // We commit delete modification
+ tree.commit(tree.prepare(deleteTx));
+
+ writeTx.write(TestModel.OUTER_LIST_PATH, ImmutableNodes.mapNodeBuilder(TestModel.OUTER_LIST_QNAME).build());
+ try {
+ tree.validate(writeTx);
+ fail("ConflictingModificationAppliedException should be raised");
+ } catch (ConflictingModificationAppliedException e) {
+ assertEquals(TestModel.TEST_PATH, e.getPath());
+ } catch (DataValidationFailedException e) {
+ fail("ConflictingModificationAppliedException expected");
+ }
+
+ }
+
+}