package org.opendaylight.controller.config.manager.impl.osgi.mapping;
import javassist.ClassPool;
+
import org.opendaylight.controller.config.manager.impl.util.OsgiRegistrationUtil;
import org.opendaylight.yangtools.sal.binding.generator.api.ClassLoadingStrategy;
import org.opendaylight.yangtools.sal.binding.generator.impl.RuntimeGeneratedMappingServiceImpl;
private final RuntimeGeneratedMappingServiceImpl service;
private final AutoCloseable registration;
- public CodecRegistryProvider(ClassLoadingStrategy classLoadingStrategy, BundleContext context) {
- service = new RuntimeGeneratedMappingServiceImpl(classLoadingStrategy);
- service.setPool(CLASS_POOL);
- service.init();
+ public CodecRegistryProvider(final ClassLoadingStrategy classLoadingStrategy, final BundleContext context) {
+ service = new RuntimeGeneratedMappingServiceImpl(CLASS_POOL, classLoadingStrategy);
registration = OsgiRegistrationUtil.registerService(context, service,
SchemaServiceListener.class, BindingIndependentMappingService.class);
}
<plugin>
<groupId>org.apache.felix</groupId>
<artifactId>maven-bundle-plugin</artifactId>
- <version>${bundle.plugin.version}</version>
<extensions>true</extensions>
<configuration>
<instructions>
@Override
public ListenableFuture<Void> abort() {
- if (candidate != null) {
- candidate.close();
- candidate = null;
- }
-
- return Futures.<Void> immediateFuture(null);
+ candidate = null;
+ return Futures.immediateFuture(null);
}
@Override
}
}
- return Futures.<Void> immediateFuture(null);
+ return Futures.immediateFuture(null);
}
}
}
import org.opendaylight.controller.md.sal.dom.store.impl.DOMImmutableDataChangeEvent.Builder;
import org.opendaylight.controller.md.sal.dom.store.impl.DOMImmutableDataChangeEvent.SimpleEventFactory;
import org.opendaylight.controller.md.sal.dom.store.impl.tree.DataTreeCandidate;
+import org.opendaylight.controller.md.sal.dom.store.impl.tree.DataTreeCandidateNode;
import org.opendaylight.controller.md.sal.dom.store.impl.tree.ListenerTree;
import org.opendaylight.controller.md.sal.dom.store.impl.tree.ListenerTree.Node;
import org.opendaylight.controller.md.sal.dom.store.impl.tree.ListenerTree.Walker;
-import org.opendaylight.controller.md.sal.dom.store.impl.tree.data.NodeModification;
-import org.opendaylight.controller.md.sal.dom.store.impl.tree.data.StoreMetadataNode;
+import org.opendaylight.controller.md.sal.dom.store.impl.tree.ModificationType;
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;
private final ListenerTree listenerRoot;
public ResolveDataChangeEventsTask(DataTreeCandidate candidate, ListenerTree listenerTree) {
- this.candidate = Preconditions.checkNotNull(candidate);
- this.listenerRoot = Preconditions.checkNotNull(listenerTree);
- }
+ this.candidate = Preconditions.checkNotNull(candidate);
+ this.listenerRoot = Preconditions.checkNotNull(listenerTree);
+ }
/**
* Resolves and creates Notification Tasks
@Override
public Iterable<ChangeListenerNotifyTask> call() {
try (final Walker w = listenerRoot.getWalker()) {
- resolveAnyChangeEvent(candidate.getRootPath(), Collections.singleton(w.getRootNode()),
- candidate.getModificationRoot(), Optional.fromNullable(candidate.getBeforeRoot()),
- Optional.fromNullable(candidate.getAfterRoot()));
+ resolveAnyChangeEvent(candidate.getRootPath(), Collections.singleton(w.getRootNode()), candidate.getRootNode());
return createNotificationTasks();
}
}
* @return Data Change Event of this node and all it's children
*/
private DOMImmutableDataChangeEvent resolveAnyChangeEvent(final InstanceIdentifier path,
- final Collection<ListenerTree.Node> listeners, final NodeModification modification,
- final Optional<StoreMetadataNode> before, final Optional<StoreMetadataNode> after) {
- // No listeners are present in listener registration subtree
- // no before and after state is present
- if (!before.isPresent() && !after.isPresent()) {
+ final Collection<ListenerTree.Node> listeners, final DataTreeCandidateNode node) {
+
+ if (node.getModificationType() != ModificationType.UNMODIFIED &&
+ !node.getDataAfter().isPresent() && !node.getDataBefore().isPresent()) {
+ LOG.debug("Modification at {} has type {}, but no before- and after-data. Assuming unchanged.",
+ path, node.getModificationType());
return NO_CHANGE;
}
- switch (modification.getModificationType()) {
+
+ // no before and after state is present
+
+ switch (node.getModificationType()) {
case SUBTREE_MODIFIED:
- return resolveSubtreeChangeEvent(path, listeners, modification, before.get(), after.get());
+ return resolveSubtreeChangeEvent(path, listeners, node);
case MERGE:
case WRITE:
- if (before.isPresent()) {
- return resolveReplacedEvent(path, listeners, before.get().getData(), after.get().getData());
+ Preconditions.checkArgument(node.getDataAfter().isPresent(),
+ "Modification at {} has type {} but no after-data", path, node.getModificationType());
+ if (node.getDataBefore().isPresent()) {
+ return resolveReplacedEvent(path, listeners, node.getDataBefore().get(), node.getDataAfter().get());
} else {
- return resolveCreateEvent(path, listeners, after.get());
+ return resolveCreateEvent(path, listeners, node.getDataAfter().get());
}
case DELETE:
- return resolveDeleteEvent(path, listeners, before.get());
- default:
+ Preconditions.checkArgument(node.getDataBefore().isPresent(),
+ "Modification at {} has type {} but no before-data", path, node.getModificationType());
+ return resolveDeleteEvent(path, listeners, node.getDataBefore().get());
+ case UNMODIFIED:
return NO_CHANGE;
}
+ throw new IllegalStateException(String.format("Unhandled node state %s at %s", node.getModificationType(), path));
}
private DOMImmutableDataChangeEvent resolveReplacedEvent(final InstanceIdentifier path,
private DOMImmutableDataChangeEvent resolveNodeContainerReplaced(final InstanceIdentifier path,
final Collection<Node> listeners,
final NormalizedNodeContainer<?, PathArgument, NormalizedNode<PathArgument, ?>> beforeCont,
- final NormalizedNodeContainer<?, PathArgument, NormalizedNode<PathArgument, ?>> afterCont) {
+ final NormalizedNodeContainer<?, PathArgument, NormalizedNode<PathArgument, ?>> afterCont) {
final Set<PathArgument> alreadyProcessed = new HashSet<>();
final List<DOMImmutableDataChangeEvent> childChanges = new LinkedList<>();
* @return
*/
private DOMImmutableDataChangeEvent resolveCreateEvent(final InstanceIdentifier path,
- final Collection<ListenerTree.Node> listeners, final StoreMetadataNode afterState) {
+ final Collection<ListenerTree.Node> listeners, final NormalizedNode<?, ?> afterState) {
@SuppressWarnings({ "unchecked", "rawtypes" })
- final NormalizedNode<PathArgument, ?> node = (NormalizedNode) afterState.getData();
+ final NormalizedNode<PathArgument, ?> node = (NormalizedNode) afterState;
return resolveSameEventRecursivelly(path, listeners, node, DOMImmutableDataChangeEvent.getCreateEventFactory());
}
private DOMImmutableDataChangeEvent resolveDeleteEvent(final InstanceIdentifier path,
- final Collection<ListenerTree.Node> listeners, final StoreMetadataNode beforeState) {
+ final Collection<ListenerTree.Node> listeners, final NormalizedNode<?, ?> beforeState) {
@SuppressWarnings({ "unchecked", "rawtypes" })
- final NormalizedNode<PathArgument, ?> node = (NormalizedNode) beforeState.getData();
+ final NormalizedNode<PathArgument, ?> node = (NormalizedNode) beforeState;
return resolveSameEventRecursivelly(path, listeners, node, DOMImmutableDataChangeEvent.getRemoveEventFactory());
}
final DOMImmutableDataChangeEvent event = eventFactory.create(path, node);
DOMImmutableDataChangeEvent propagateEvent = event;
// We have listeners for this node or it's children, so we will try
- // to do additional processing
+ // to do additional processing
if (node instanceof NormalizedNodeContainer<?, ?, ?>) {
LOG.trace("Resolving subtree recursive event for {}, type {}", path, eventFactory);
}
private DOMImmutableDataChangeEvent resolveSubtreeChangeEvent(final InstanceIdentifier path,
- final Collection<ListenerTree.Node> listeners, final NodeModification modification,
- final StoreMetadataNode before, final StoreMetadataNode after) {
+ final Collection<ListenerTree.Node> listeners, final DataTreeCandidateNode modification) {
- Builder one = builder(DataChangeScope.ONE).setBefore(before.getData()).setAfter(after.getData());
+ Preconditions.checkArgument(modification.getDataBefore().isPresent(), "Subtree change with before-data not present at path %s", path);
+ Preconditions.checkArgument(modification.getDataAfter().isPresent(), "Subtree change with after-data not present at path %s", path);
- Builder subtree = builder(DataChangeScope.SUBTREE).setBefore(before.getData()).setAfter(after.getData());
+ Builder one = builder(DataChangeScope.ONE).
+ setBefore(modification.getDataBefore().get()).
+ setAfter(modification.getDataAfter().get());
+ Builder subtree = builder(DataChangeScope.SUBTREE).
+ setBefore(modification.getDataBefore().get()).
+ setAfter(modification.getDataAfter().get());
- for (NodeModification childMod : modification.getModifications()) {
+ for (DataTreeCandidateNode childMod : modification.getChildNodes()) {
PathArgument childId = childMod.getIdentifier();
InstanceIdentifier childPath = append(path, childId);
Collection<ListenerTree.Node> childListeners = getListenerChildrenWildcarded(listeners, childId);
- Optional<StoreMetadataNode> childBefore = before.getChild(childId);
- Optional<StoreMetadataNode> childAfter = after.getChild(childId);
-
switch (childMod.getModificationType()) {
case WRITE:
case MERGE:
case DELETE:
- one.merge(resolveAnyChangeEvent(childPath, childListeners, childMod, childBefore, childAfter));
+ one.merge(resolveAnyChangeEvent(childPath, childListeners, childMod));
break;
case SUBTREE_MODIFIED:
- subtree.merge(resolveSubtreeChangeEvent(childPath, childListeners, childMod, childBefore.get(),
- childAfter.get()));
+ subtree.merge(resolveSubtreeChangeEvent(childPath, childListeners, childMod));
break;
case UNMODIFIED:
// no-op
}
}
- public static ResolveDataChangeEventsTask create(DataTreeCandidate candidate, ListenerTree listenerTree) {
+ public static ResolveDataChangeEventsTask create(DataTreeCandidate candidate, ListenerTree listenerTree) {
return new ResolveDataChangeEventsTask(candidate, listenerTree);
- }
+ }
}
* Interface representing a data tree which can be modified in an MVCC fashion.
*/
public interface DataTree {
- /**
- * Take a read-only point-in-time snapshot of the tree.
- *
- * @return Data tree snapshot.
- */
- DataTreeSnapshot takeSnapshot();
+ /**
+ * Take a read-only point-in-time snapshot of the tree.
+ *
+ * @return Data tree snapshot.
+ */
+ DataTreeSnapshot takeSnapshot();
- /**
- * Make the data tree use a new schema context. The context will be used
- * only by subsequent operations.
- *
- * @param newSchemaContext new SchemaContext
- * @throws IllegalArgumentException if the new context is incompatible
- */
+ /**
+ * Make the data tree use a new schema context. The context will be used
+ * only by subsequent operations.
+ *
+ * @param newSchemaContext new SchemaContext
+ * @throws IllegalArgumentException if the new context is incompatible
+ */
void setSchemaContext(SchemaContext newSchemaContext);
/**
*/
package org.opendaylight.controller.md.sal.dom.store.impl.tree;
-import org.opendaylight.controller.md.sal.dom.store.impl.tree.data.NodeModification;
-import org.opendaylight.controller.md.sal.dom.store.impl.tree.data.StoreMetadataNode;
import org.opendaylight.yangtools.yang.data.api.InstanceIdentifier;
-public interface DataTreeCandidate extends AutoCloseable {
- @Override
- void close();
-
- InstanceIdentifier getRootPath();
-
- @Deprecated
- NodeModification getModificationRoot();
-
- @Deprecated
- StoreMetadataNode getBeforeRoot();
-
- @Deprecated
- StoreMetadataNode getAfterRoot();
+public interface DataTreeCandidate {
+ DataTreeCandidateNode getRootNode();
+ InstanceIdentifier getRootPath();
}
--- /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.controller.md.sal.dom.store.impl.tree;
+
+import org.opendaylight.yangtools.yang.data.api.InstanceIdentifier.PathArgument;
+import org.opendaylight.yangtools.yang.data.api.schema.NormalizedNode;
+
+import com.google.common.base.Optional;
+
+public interface DataTreeCandidateNode {
+ PathArgument getIdentifier();
+ Iterable<DataTreeCandidateNode> getChildNodes();
+
+ ModificationType getModificationType();
+ Optional<NormalizedNode<?, ?>> getDataAfter();
+ Optional<NormalizedNode<?, ?>> getDataBefore();
+}
* 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.controller.md.sal.dom.store.impl.tree.data;
+package org.opendaylight.controller.md.sal.dom.store.impl.tree;
public enum ModificationType {
import com.google.common.base.Preconditions;
abstract class AbstractDataTreeCandidate implements DataTreeCandidate {
- private final InstanceIdentifier rootPath;
- private final NodeModification modificationRoot;
+ private final InstanceIdentifier rootPath;
- protected AbstractDataTreeCandidate(final InstanceIdentifier rootPath, NodeModification modificationRoot) {
- this.rootPath = Preconditions.checkNotNull(rootPath);
- this.modificationRoot = Preconditions.checkNotNull(modificationRoot);
- }
+ protected AbstractDataTreeCandidate(final InstanceIdentifier rootPath) {
+ this.rootPath = Preconditions.checkNotNull(rootPath);
+ }
- @Override
- public final InstanceIdentifier getRootPath() {
- return rootPath;
- }
+ @Override
+ public final InstanceIdentifier getRootPath() {
+ return rootPath;
+ }
- @Override
- public final NodeModification getModificationRoot() {
- return modificationRoot;
- }
}
--- /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.controller.md.sal.dom.store.impl.tree.data;
+
+import static com.google.common.base.Preconditions.checkArgument;
+
+import java.util.HashSet;
+import java.util.Set;
+import java.util.concurrent.ExecutionException;
+
+import org.opendaylight.yangtools.yang.data.api.InstanceIdentifier.AugmentationIdentifier;
+import org.opendaylight.yangtools.yang.data.api.InstanceIdentifier.PathArgument;
+import org.opendaylight.yangtools.yang.data.api.schema.AugmentationNode;
+import org.opendaylight.yangtools.yang.data.api.schema.ContainerNode;
+import org.opendaylight.yangtools.yang.data.api.schema.MapEntryNode;
+import org.opendaylight.yangtools.yang.data.api.schema.NormalizedNode;
+import org.opendaylight.yangtools.yang.data.api.schema.UnkeyedListEntryNode;
+import org.opendaylight.yangtools.yang.data.impl.schema.builder.api.DataContainerNodeBuilder;
+import org.opendaylight.yangtools.yang.data.impl.schema.builder.impl.ImmutableAugmentationNodeBuilder;
+import org.opendaylight.yangtools.yang.data.impl.schema.builder.impl.ImmutableContainerNodeBuilder;
+import org.opendaylight.yangtools.yang.data.impl.schema.builder.impl.ImmutableMapEntryNodeBuilder;
+import org.opendaylight.yangtools.yang.data.impl.schema.builder.impl.ImmutableUnkeyedListEntryNodeBuilder;
+import org.opendaylight.yangtools.yang.data.impl.schema.transform.base.AugmentationSchemaProxy;
+import org.opendaylight.yangtools.yang.model.api.AugmentationSchema;
+import org.opendaylight.yangtools.yang.model.api.AugmentationTarget;
+import org.opendaylight.yangtools.yang.model.api.ContainerSchemaNode;
+import org.opendaylight.yangtools.yang.model.api.DataNodeContainer;
+import org.opendaylight.yangtools.yang.model.api.DataSchemaNode;
+import org.opendaylight.yangtools.yang.model.api.ListSchemaNode;
+
+import com.google.common.base.Function;
+import com.google.common.base.Optional;
+import com.google.common.cache.CacheBuilder;
+import com.google.common.cache.CacheLoader;
+import com.google.common.cache.LoadingCache;
+
+abstract class DataNodeContainerModificationStrategy<T extends DataNodeContainer> extends NormalizedNodeContainerModificationStrategy {
+
+ private final T schema;
+ private final LoadingCache<PathArgument, ModificationApplyOperation> childCache = CacheBuilder.newBuilder()
+ .build(CacheLoader.from(new Function<PathArgument, ModificationApplyOperation>() {
+
+ @Override
+ public ModificationApplyOperation apply(final PathArgument identifier) {
+ if (identifier instanceof AugmentationIdentifier && schema instanceof AugmentationTarget) {
+ return from(schema, (AugmentationTarget) schema, (AugmentationIdentifier) identifier);
+ }
+
+ DataSchemaNode child = schema.getDataChildByName(identifier.getNodeType());
+ if (child == null) {
+ return null;
+ }
+ return from(child);
+ }
+ }));
+
+ protected DataNodeContainerModificationStrategy(final T schema,
+ final Class<? extends NormalizedNode<?, ?>> nodeClass) {
+ super(nodeClass);
+ this.schema = schema;
+ }
+
+ protected T getSchema() {
+ return schema;
+ }
+
+ @Override
+ public Optional<ModificationApplyOperation> getChild(final PathArgument identifier) {
+ try {
+ return Optional.<ModificationApplyOperation> fromNullable(childCache.get(identifier));
+ } catch (ExecutionException e) {
+ return Optional.absent();
+ }
+ }
+
+ @Override
+ @SuppressWarnings("rawtypes")
+ protected abstract DataContainerNodeBuilder createBuilder(NormalizedNode<?, ?> original);
+
+ @Override
+ public String toString() {
+ return getClass().getSimpleName() + " [" + schema + "]";
+ }
+
+ public static class AugmentationModificationStrategy extends DataNodeContainerModificationStrategy<AugmentationSchema> {
+
+ protected AugmentationModificationStrategy(final AugmentationSchema schema, final DataNodeContainer resolved) {
+ super(createAugmentProxy(schema,resolved), AugmentationNode.class);
+ }
+
+ @Override
+ @SuppressWarnings("rawtypes")
+ protected DataContainerNodeBuilder createBuilder(final NormalizedNode<?, ?> original) {
+ checkArgument(original instanceof AugmentationNode);
+ return ImmutableAugmentationNodeBuilder.create((AugmentationNode) original);
+ }
+
+
+ private static AugmentationSchema createAugmentProxy(final AugmentationSchema schema, final DataNodeContainer resolved) {
+ Set<DataSchemaNode> realChildSchemas = new HashSet<>();
+ for(DataSchemaNode augChild : schema.getChildNodes()) {
+ realChildSchemas.add(resolved.getDataChildByName(augChild.getQName()));
+ }
+ return new AugmentationSchemaProxy(schema, realChildSchemas);
+ }
+ }
+
+ public static class ContainerModificationStrategy extends DataNodeContainerModificationStrategy<ContainerSchemaNode> {
+
+ public ContainerModificationStrategy(final ContainerSchemaNode schemaNode) {
+ super(schemaNode, ContainerNode.class);
+ }
+
+ @Override
+ @SuppressWarnings("rawtypes")
+ protected DataContainerNodeBuilder createBuilder(final NormalizedNode<?, ?> original) {
+ checkArgument(original instanceof ContainerNode);
+ return ImmutableContainerNodeBuilder.create((ContainerNode) original);
+ }
+ }
+
+ public static class ListEntryModificationStrategy extends DataNodeContainerModificationStrategy<ListSchemaNode> {
+
+ protected ListEntryModificationStrategy(final ListSchemaNode schema) {
+ super(schema, MapEntryNode.class);
+ }
+
+ @Override
+ @SuppressWarnings("rawtypes")
+ protected final DataContainerNodeBuilder createBuilder(final NormalizedNode<?, ?> original) {
+ checkArgument(original instanceof MapEntryNode);
+ return ImmutableMapEntryNodeBuilder.create((MapEntryNode) original);
+ }
+ }
+
+ public static class UnkeyedListItemModificationStrategy extends DataNodeContainerModificationStrategy<ListSchemaNode> {
+
+ public UnkeyedListItemModificationStrategy(final ListSchemaNode schemaNode) {
+ super(schemaNode, UnkeyedListEntryNode.class);
+ }
+
+ @Override
+ @SuppressWarnings("rawtypes")
+ protected DataContainerNodeBuilder createBuilder(final NormalizedNode<?, ?> original) {
+ checkArgument(original instanceof UnkeyedListEntryNode);
+ return ImmutableUnkeyedListEntryNodeBuilder.create((UnkeyedListEntryNode) original);
+ }
+ }
+}
\ No newline at end of file
import org.opendaylight.controller.md.sal.dom.store.impl.tree.DataTree;
import org.opendaylight.controller.md.sal.dom.store.impl.tree.DataTreeCandidate;
import org.opendaylight.controller.md.sal.dom.store.impl.tree.DataTreeModification;
+import org.opendaylight.controller.md.sal.dom.store.impl.tree.ModificationType;
import org.opendaylight.controller.md.sal.dom.store.impl.tree.StoreUtils;
import org.opendaylight.yangtools.yang.data.api.InstanceIdentifier;
import org.opendaylight.yangtools.yang.model.api.SchemaContext;
rwLock.writeLock().lock();
try {
Preconditions.checkState(c.getBeforeRoot() == rootNode,
- String.format("Store snapshot %s and transaction snapshot %s differ.", rootNode, c.getBeforeRoot()));
+ String.format("Store tree %s and candidate base %s differ.", rootNode, c.getBeforeRoot()));
this.rootNode = c.getAfterRoot();
} finally {
rwLock.writeLock().unlock();
package org.opendaylight.controller.md.sal.dom.store.impl.tree.data;
+import org.opendaylight.controller.md.sal.dom.store.impl.tree.DataTreeCandidateNode;
+import org.opendaylight.controller.md.sal.dom.store.impl.tree.ModificationType;
import org.opendaylight.yangtools.yang.data.api.InstanceIdentifier;
+import org.opendaylight.yangtools.yang.data.api.InstanceIdentifier.PathArgument;
+import org.opendaylight.yangtools.yang.data.api.schema.NormalizedNode;
+import com.google.common.base.Function;
+import com.google.common.base.Optional;
import com.google.common.base.Preconditions;
+import com.google.common.collect.Iterables;
final class InMemoryDataTreeCandidate extends AbstractDataTreeCandidate {
- private final StoreMetadataNode newRoot;
- private final StoreMetadataNode oldRoot;
-
- InMemoryDataTreeCandidate(final InstanceIdentifier rootPath, final NodeModification modificationRoot,
- final StoreMetadataNode oldRoot, final StoreMetadataNode newRoot) {
- super(rootPath, modificationRoot);
- this.newRoot = Preconditions.checkNotNull(newRoot);
- this.oldRoot = Preconditions.checkNotNull(oldRoot);
- }
-
- @Override
- public void close() {
- // FIXME: abort operation here :)
- }
-
- @Override
- public StoreMetadataNode getBeforeRoot() {
- return oldRoot;
- }
-
- @Override
- public StoreMetadataNode getAfterRoot() {
- return newRoot;
- }
+ private static abstract class AbstractNode implements DataTreeCandidateNode {
+ private final StoreMetadataNode newMeta;
+ private final StoreMetadataNode oldMeta;
+ private final NodeModification mod;
+
+ protected AbstractNode(final NodeModification mod,
+ final StoreMetadataNode oldMeta, final StoreMetadataNode newMeta) {
+ this.newMeta = newMeta;
+ this.oldMeta = oldMeta;
+ this.mod = Preconditions.checkNotNull(mod);
+ }
+
+ protected final NodeModification getMod() {
+ return mod;
+ }
+
+ protected final StoreMetadataNode getNewMeta() {
+ return newMeta;
+ }
+
+ protected final StoreMetadataNode getOldMeta() {
+ return oldMeta;
+ }
+
+ private static final StoreMetadataNode childMeta(final StoreMetadataNode parent, final PathArgument id) {
+ return parent == null ? null : parent.getChild(id).orNull();
+ }
+
+ @Override
+ public Iterable<DataTreeCandidateNode> getChildNodes() {
+ return Iterables.transform(mod.getModifications(), new Function<NodeModification, DataTreeCandidateNode>() {
+ @Override
+ public DataTreeCandidateNode apply(final NodeModification input) {
+ final PathArgument id = input.getIdentifier();
+ return new ChildNode(input, childMeta(oldMeta, id), childMeta(newMeta, id));
+ }
+ });
+ }
+
+ @Override
+ public ModificationType getModificationType() {
+ return mod.getModificationType();
+ }
+
+ private Optional<NormalizedNode<?, ?>> optionalData(StoreMetadataNode meta) {
+ if (meta == null) {
+ return Optional.absent();
+ }
+ return Optional.<NormalizedNode<?,?>>of(meta.getData());
+ }
+
+ @Override
+ public Optional<NormalizedNode<?, ?>> getDataAfter() {
+ return optionalData(newMeta);
+ }
+
+ @Override
+ public Optional<NormalizedNode<?, ?>> getDataBefore() {
+ return optionalData(oldMeta);
+ }
+ }
+
+ private static final class ChildNode extends AbstractNode {
+ public ChildNode(NodeModification mod, StoreMetadataNode oldMeta, StoreMetadataNode newMeta) {
+ super(mod, oldMeta, newMeta);
+ }
+
+ @Override
+ public PathArgument getIdentifier() {
+ return getMod().getIdentifier();
+ }
+ }
+
+ private static final class RootNode extends AbstractNode {
+ public RootNode(NodeModification mod, StoreMetadataNode oldMeta, StoreMetadataNode newMeta) {
+ super(mod, oldMeta, newMeta);
+ }
+
+ @Override
+ public PathArgument getIdentifier() {
+ throw new IllegalStateException("Attempted to get identifier of the root node");
+ }
+ }
+
+ private final RootNode root;
+
+ InMemoryDataTreeCandidate(final InstanceIdentifier rootPath, final NodeModification modificationRoot,
+ final StoreMetadataNode oldRoot, final StoreMetadataNode newRoot) {
+ super(rootPath);
+ this.root = new RootNode(modificationRoot, oldRoot, newRoot);
+ }
+
+ StoreMetadataNode getAfterRoot() {
+ return root.getNewMeta();
+ }
+
+ StoreMetadataNode getBeforeRoot() {
+ return root.getOldMeta();
+ }
+
+ @Override
+ public DataTreeCandidateNode getRootNode() {
+ return root;
+ }
}
@Override
public Optional<NormalizedNode<?, ?>> readNode(final InstanceIdentifier path) {
- Entry<InstanceIdentifier, NodeModification> modification = TreeNodeUtils.findClosestsOrFirstMatch(rootNode, path, NodeModification.IS_TERMINAL_PREDICATE);
-
- Optional<StoreMetadataNode> result = resolveSnapshot(modification);
+ /*
+ * Walk the tree from the top, looking for the first node between root and
+ * the requested path which has been modified. If no such node exists,
+ * we use the node itself.
+ */
+ final Entry<InstanceIdentifier, NodeModification> entry = TreeNodeUtils.findClosestsOrFirstMatch(rootNode, path, NodeModification.IS_TERMINAL_PREDICATE);
+ final InstanceIdentifier key = entry.getKey();
+ final NodeModification mod = entry.getValue();
+
+ final Optional<StoreMetadataNode> result = resolveSnapshot(key, mod);
if (result.isPresent()) {
NormalizedNode<?, ?> data = result.get().getData();
- return NormalizedNodeUtils.findNode(modification.getKey(), data, path);
+ return NormalizedNodeUtils.findNode(key, data, path);
+ } else {
+ return Optional.absent();
}
- return Optional.absent();
- }
-
- private Optional<StoreMetadataNode> resolveSnapshot(
- final Entry<InstanceIdentifier, NodeModification> keyModification) {
- InstanceIdentifier path = keyModification.getKey();
- NodeModification modification = keyModification.getValue();
- return resolveSnapshot(path, modification);
}
private Optional<StoreMetadataNode> resolveSnapshot(final InstanceIdentifier path,
final NodeModification modification) {
+ final Optional<Optional<StoreMetadataNode>> potentialSnapshot = modification.getSnapshotCache();
+ if(potentialSnapshot.isPresent()) {
+ return potentialSnapshot.get();
+ }
+
try {
- Optional<Optional<StoreMetadataNode>> potentialSnapshot = modification.getSnapshotCache();
- if(potentialSnapshot.isPresent()) {
- return potentialSnapshot.get();
- }
return resolveModificationStrategy(path).apply(modification, modification.getOriginal(),
StoreUtils.increase(snapshot.getRootNode().getSubtreeVersion()));
} catch (Exception e) {
import javax.annotation.concurrent.GuardedBy;
+import org.opendaylight.controller.md.sal.dom.store.impl.tree.ModificationType;
import org.opendaylight.controller.md.sal.dom.store.impl.tree.StoreTreeNode;
import org.opendaylight.yangtools.concepts.Identifiable;
import org.opendaylight.yangtools.yang.data.api.InstanceIdentifier.PathArgument;
*
* This tree is lazily created and populated via {@link #modifyChild(PathArgument)}
* and {@link StoreMetadataNode} which represents original state {@link #getOriginal()}.
- *
*/
-// FIXME: hide this class
-public class NodeModification implements StoreTreeNode<NodeModification>, Identifiable<PathArgument> {
+final class NodeModification implements StoreTreeNode<NodeModification>, Identifiable<PathArgument> {
public static final Predicate<NodeModification> IS_TERMINAL_PREDICATE = new Predicate<NodeModification>() {
@Override
*/
package org.opendaylight.controller.md.sal.dom.store.impl.tree.data;
+import java.util.Collections;
+
+import org.opendaylight.controller.md.sal.dom.store.impl.tree.DataTreeCandidateNode;
+import org.opendaylight.controller.md.sal.dom.store.impl.tree.ModificationType;
import org.opendaylight.yangtools.yang.data.api.InstanceIdentifier;
+import org.opendaylight.yangtools.yang.data.api.InstanceIdentifier.PathArgument;
+import org.opendaylight.yangtools.yang.data.api.schema.NormalizedNode;
+
+import com.google.common.base.Optional;
+import com.google.common.base.Preconditions;
final class NoopDataTreeCandidate extends AbstractDataTreeCandidate {
- protected NoopDataTreeCandidate(final InstanceIdentifier rootPath, final NodeModification modificationRoot) {
- super(rootPath, modificationRoot);
- }
-
- @Override
- public void close() {
- // NO-OP
- }
-
- @Override
- public StoreMetadataNode getBeforeRoot() {
- return null;
- }
-
- @Override
- public StoreMetadataNode getAfterRoot() {
- return null;
- }
+ private static final DataTreeCandidateNode ROOT = new DataTreeCandidateNode() {
+ @Override
+ public ModificationType getModificationType() {
+ return ModificationType.UNMODIFIED;
+ }
+
+ @Override
+ public Iterable<DataTreeCandidateNode> getChildNodes() {
+ return Collections.emptyList();
+ }
+
+ @Override
+ public PathArgument getIdentifier() {
+ throw new IllegalStateException("Attempted to read identifier of the no-operation change");
+ }
+
+ @Override
+ public Optional<NormalizedNode<?, ?>> getDataAfter() {
+ return Optional.absent();
+ }
+
+ @Override
+ public Optional<NormalizedNode<?, ?>> getDataBefore() {
+ return Optional.absent();
+ }
+ };
+
+ protected NoopDataTreeCandidate(final InstanceIdentifier rootPath, final NodeModification modificationRoot) {
+ super(rootPath);
+ Preconditions.checkArgument(modificationRoot.getModificationType() == ModificationType.UNMODIFIED);
+ }
+
+ @Override
+ public DataTreeCandidateNode getRootNode() {
+ return ROOT;
+ }
}
--- /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.controller.md.sal.dom.store.impl.tree.data;
+
+import static com.google.common.base.Preconditions.checkArgument;
+
+import java.util.Map;
+
+import org.opendaylight.controller.md.sal.dom.store.impl.tree.DataPreconditionFailedException;
+import org.opendaylight.controller.md.sal.dom.store.impl.tree.ModificationType;
+import org.opendaylight.controller.md.sal.dom.store.impl.tree.StoreUtils;
+import org.opendaylight.controller.md.sal.dom.store.impl.tree.data.DataNodeContainerModificationStrategy.ListEntryModificationStrategy;
+import org.opendaylight.controller.md.sal.dom.store.impl.tree.data.ValueNodeModificationStrategy.LeafSetEntryModificationStrategy;
+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.InstanceIdentifier.NodeWithValue;
+import org.opendaylight.yangtools.yang.data.api.InstanceIdentifier.PathArgument;
+import org.opendaylight.yangtools.yang.data.api.schema.LeafSetNode;
+import org.opendaylight.yangtools.yang.data.api.schema.MapNode;
+import org.opendaylight.yangtools.yang.data.api.schema.NormalizedNode;
+import org.opendaylight.yangtools.yang.data.api.schema.NormalizedNodeContainer;
+import org.opendaylight.yangtools.yang.data.api.schema.OrderedLeafSetNode;
+import org.opendaylight.yangtools.yang.data.api.schema.OrderedMapNode;
+import org.opendaylight.yangtools.yang.data.impl.schema.builder.api.DataContainerNodeBuilder;
+import org.opendaylight.yangtools.yang.data.impl.schema.builder.api.NormalizedNodeContainerBuilder;
+import org.opendaylight.yangtools.yang.data.impl.schema.builder.impl.ImmutableChoiceNodeBuilder;
+import org.opendaylight.yangtools.yang.data.impl.schema.builder.impl.ImmutableLeafSetNodeBuilder;
+import org.opendaylight.yangtools.yang.data.impl.schema.builder.impl.ImmutableMapNodeBuilder;
+import org.opendaylight.yangtools.yang.data.impl.schema.builder.impl.ImmutableOrderedLeafSetNodeBuilder;
+import org.opendaylight.yangtools.yang.data.impl.schema.builder.impl.ImmutableOrderedMapNodeBuilder;
+import org.opendaylight.yangtools.yang.model.api.ChoiceCaseNode;
+import org.opendaylight.yangtools.yang.model.api.ChoiceNode;
+import org.opendaylight.yangtools.yang.model.api.DataSchemaNode;
+import org.opendaylight.yangtools.yang.model.api.LeafListSchemaNode;
+import org.opendaylight.yangtools.yang.model.api.ListSchemaNode;
+
+import com.google.common.base.Optional;
+import com.google.common.collect.ImmutableMap;
+import com.google.common.primitives.UnsignedLong;
+
+abstract class NormalizedNodeContainerModificationStrategy extends SchemaAwareApplyOperation {
+
+ private final Class<? extends NormalizedNode<?, ?>> nodeClass;
+
+ protected NormalizedNodeContainerModificationStrategy(final Class<? extends NormalizedNode<?, ?>> nodeClass) {
+ this.nodeClass = nodeClass;
+ }
+
+ @Override
+ public void verifyStructure(final NodeModification modification) throws IllegalArgumentException {
+ if (modification.getModificationType() == ModificationType.WRITE) {
+
+ }
+ for (NodeModification childModification : modification.getModifications()) {
+ resolveChildOperation(childModification.getIdentifier()).verifyStructure(childModification);
+ }
+ }
+
+ @Override
+ protected void checkWriteApplicable(final InstanceIdentifier path, final NodeModification modification,
+ final Optional<StoreMetadataNode> current) throws DataPreconditionFailedException {
+ // FIXME: Implement proper write check for replacement of node container
+ // prerequisite is to have transaction chain available for clients
+ // otherwise this will break chained writes to same node.
+ }
+
+ @SuppressWarnings("rawtypes")
+ @Override
+ protected void verifyWrittenStructure(final NormalizedNode<?, ?> writtenValue) {
+ checkArgument(nodeClass.isInstance(writtenValue), "Node should must be of type %s", nodeClass);
+ checkArgument(writtenValue instanceof NormalizedNodeContainer);
+
+ NormalizedNodeContainer container = (NormalizedNodeContainer) writtenValue;
+ for (Object child : container.getValue()) {
+ checkArgument(child instanceof NormalizedNode);
+
+ /*
+ * FIXME: fail-fast semantics:
+ *
+ * We can validate the data structure here, aborting the commit
+ * before it ever progresses to being committed.
+ */
+ }
+ }
+
+ @Override
+ protected StoreMetadataNode applyWrite(final NodeModification modification,
+ final Optional<StoreMetadataNode> currentMeta, final UnsignedLong subtreeVersion) {
+
+ NormalizedNode<?, ?> newValue = modification.getWrittenValue();
+
+ final UnsignedLong nodeVersion;
+ if (currentMeta.isPresent()) {
+ nodeVersion = StoreUtils.increase(currentMeta.get().getNodeVersion());
+ } else {
+ nodeVersion = subtreeVersion;
+ }
+
+ final StoreMetadataNode newValueMeta = StoreMetadataNode.createRecursively(newValue, nodeVersion);
+ if (!modification.hasAdditionalModifications()) {
+ return newValueMeta;
+ }
+
+ @SuppressWarnings("rawtypes")
+ NormalizedNodeContainerBuilder dataBuilder = createBuilder(newValue);
+ StoreNodeCompositeBuilder builder = StoreNodeCompositeBuilder.create(nodeVersion, dataBuilder) //
+ .setSubtreeVersion(subtreeVersion);
+
+ return mutateChildren(modification.getModifications(), newValueMeta, builder, nodeVersion);
+ }
+
+ @Override
+ protected StoreMetadataNode applyMerge(final NodeModification modification, final StoreMetadataNode currentMeta,
+ final UnsignedLong subtreeVersion) {
+ // For Node Containers - merge is same as subtree change - we only replace children.
+ return applySubtreeChange(modification, currentMeta, subtreeVersion);
+ }
+
+ @Override
+ public StoreMetadataNode applySubtreeChange(final NodeModification modification,
+ final StoreMetadataNode currentMeta, final UnsignedLong subtreeVersion) {
+ // Bump subtree version to its new target
+ final UnsignedLong updatedSubtreeVersion = StoreUtils.increase(currentMeta.getSubtreeVersion());
+
+ @SuppressWarnings("rawtypes")
+ NormalizedNodeContainerBuilder dataBuilder = createBuilder(currentMeta.getData());
+ StoreNodeCompositeBuilder builder = StoreNodeCompositeBuilder.create(dataBuilder, currentMeta)
+ .setIdentifier(modification.getIdentifier())
+ .setSubtreeVersion(updatedSubtreeVersion);
+
+ return mutateChildren(modification.getModifications(), currentMeta, builder, updatedSubtreeVersion);
+ }
+
+ private StoreMetadataNode mutateChildren(final Iterable<NodeModification> modifications, final StoreMetadataNode meta,
+ final StoreNodeCompositeBuilder builder, final UnsignedLong nodeVersion) {
+
+ for (NodeModification mod : modifications) {
+ final PathArgument id = mod.getIdentifier();
+ final Optional<StoreMetadataNode> cm = meta.getChild(id);
+
+ Optional<StoreMetadataNode> result = resolveChildOperation(id).apply(mod, cm, nodeVersion);
+ if (result.isPresent()) {
+ builder.add(result.get());
+ } else {
+ builder.remove(id);
+ }
+ }
+
+ return builder.build();
+ }
+
+ @Override
+ protected void checkSubtreeModificationApplicable(final InstanceIdentifier path,final NodeModification modification,
+ final Optional<StoreMetadataNode> current) throws DataPreconditionFailedException {
+ checkDataPrecondition(path, current.isPresent(), "Node was deleted by other transaction.");
+ checkChildPreconditions(path,modification,current);
+
+ }
+
+ private void checkChildPreconditions(final InstanceIdentifier path, final NodeModification modification, final Optional<StoreMetadataNode> current) throws DataPreconditionFailedException {
+ StoreMetadataNode currentMeta = current.get();
+ for (NodeModification childMod : modification.getModifications()) {
+ PathArgument childId = childMod.getIdentifier();
+ Optional<StoreMetadataNode> childMeta = currentMeta.getChild(childId);
+ InstanceIdentifier childPath = StoreUtils.append(path, childId);
+ resolveChildOperation(childId).checkApplicable(childPath,childMod, childMeta);
+ }
+ }
+
+ @Override
+ protected void checkMergeApplicable(final InstanceIdentifier path, final NodeModification modification,
+ final Optional<StoreMetadataNode> current) throws DataPreconditionFailedException {
+ if(current.isPresent()) {
+ checkChildPreconditions(path,modification,current);
+ }
+ }
+
+ @SuppressWarnings("rawtypes")
+ protected abstract NormalizedNodeContainerBuilder createBuilder(NormalizedNode<?, ?> original);
+
+ public static class ChoiceModificationStrategy extends NormalizedNodeContainerModificationStrategy {
+
+ private final Map<PathArgument, ModificationApplyOperation> childNodes;
+
+ public ChoiceModificationStrategy(final ChoiceNode schemaNode) {
+ super(org.opendaylight.yangtools.yang.data.api.schema.ChoiceNode.class);
+ ImmutableMap.Builder<PathArgument, ModificationApplyOperation> child = ImmutableMap.builder();
+
+ for (ChoiceCaseNode caze : schemaNode.getCases()) {
+ for (DataSchemaNode cazeChild : caze.getChildNodes()) {
+ SchemaAwareApplyOperation childNode = from(cazeChild);
+ child.put(new NodeIdentifier(cazeChild.getQName()), childNode);
+ }
+ }
+ childNodes = child.build();
+ }
+
+ @Override
+ public Optional<ModificationApplyOperation> getChild(final PathArgument child) {
+ return Optional.fromNullable(childNodes.get(child));
+ }
+
+ @Override
+ @SuppressWarnings("rawtypes")
+ protected DataContainerNodeBuilder createBuilder(final NormalizedNode<?, ?> original) {
+ checkArgument(original instanceof org.opendaylight.yangtools.yang.data.api.schema.ChoiceNode);
+ return ImmutableChoiceNodeBuilder.create((org.opendaylight.yangtools.yang.data.api.schema.ChoiceNode) original);
+ }
+ }
+
+ public static class OrderedLeafSetModificationStrategy extends NormalizedNodeContainerModificationStrategy {
+
+ private final Optional<ModificationApplyOperation> entryStrategy;
+
+ @SuppressWarnings({ "unchecked", "rawtypes" })
+ protected OrderedLeafSetModificationStrategy(final LeafListSchemaNode schema) {
+ super((Class) LeafSetNode.class);
+ entryStrategy = Optional.<ModificationApplyOperation> of(new LeafSetEntryModificationStrategy(schema));
+ }
+
+ @SuppressWarnings("rawtypes")
+ @Override
+ protected NormalizedNodeContainerBuilder createBuilder(final NormalizedNode<?, ?> original) {
+ checkArgument(original instanceof OrderedLeafSetNode<?>);
+ return ImmutableOrderedLeafSetNodeBuilder.create((OrderedLeafSetNode<?>) original);
+ }
+
+ @Override
+ public Optional<ModificationApplyOperation> getChild(final PathArgument identifier) {
+ if (identifier instanceof NodeWithValue) {
+ return entryStrategy;
+ }
+ return Optional.absent();
+ }
+ }
+
+ public static class OrderedMapModificationStrategy extends NormalizedNodeContainerModificationStrategy {
+
+ private final Optional<ModificationApplyOperation> entryStrategy;
+
+ protected OrderedMapModificationStrategy(final ListSchemaNode schema) {
+ super(OrderedMapNode.class);
+ entryStrategy = Optional.<ModificationApplyOperation> of(new ListEntryModificationStrategy(schema));
+ }
+
+ @SuppressWarnings("rawtypes")
+ @Override
+ protected NormalizedNodeContainerBuilder createBuilder(final NormalizedNode<?, ?> original) {
+ checkArgument(original instanceof OrderedMapNode);
+ return ImmutableOrderedMapNodeBuilder.create((OrderedMapNode) original);
+ }
+
+ @Override
+ public Optional<ModificationApplyOperation> getChild(final PathArgument identifier) {
+ if (identifier instanceof NodeIdentifierWithPredicates) {
+ return entryStrategy;
+ }
+ return Optional.absent();
+ }
+
+ @Override
+ public String toString() {
+ return "OrderedMapModificationStrategy [entry=" + entryStrategy + "]";
+ }
+ }
+
+ public static class UnorderedLeafSetModificationStrategy extends NormalizedNodeContainerModificationStrategy {
+
+ private final Optional<ModificationApplyOperation> entryStrategy;
+
+ @SuppressWarnings({ "unchecked", "rawtypes" })
+ protected UnorderedLeafSetModificationStrategy(final LeafListSchemaNode schema) {
+ super((Class) LeafSetNode.class);
+ entryStrategy = Optional.<ModificationApplyOperation> of(new LeafSetEntryModificationStrategy(schema));
+ }
+
+ @SuppressWarnings("rawtypes")
+ @Override
+ protected NormalizedNodeContainerBuilder createBuilder(final NormalizedNode<?, ?> original) {
+ checkArgument(original instanceof LeafSetNode<?>);
+ return ImmutableLeafSetNodeBuilder.create((LeafSetNode<?>) original);
+ }
+
+ @Override
+ public Optional<ModificationApplyOperation> getChild(final PathArgument identifier) {
+ if (identifier instanceof NodeWithValue) {
+ return entryStrategy;
+ }
+ return Optional.absent();
+ }
+ }
+
+ public static class UnorderedMapModificationStrategy extends NormalizedNodeContainerModificationStrategy {
+
+ private final Optional<ModificationApplyOperation> entryStrategy;
+
+ protected UnorderedMapModificationStrategy(final ListSchemaNode schema) {
+ super(MapNode.class);
+ entryStrategy = Optional.<ModificationApplyOperation> of(new ListEntryModificationStrategy(schema));
+ }
+
+ @SuppressWarnings("rawtypes")
+ @Override
+ protected NormalizedNodeContainerBuilder createBuilder(final NormalizedNode<?, ?> original) {
+ checkArgument(original instanceof MapNode);
+ return ImmutableMapNodeBuilder.create((MapNode) original);
+ }
+
+ @Override
+ public Optional<ModificationApplyOperation> getChild(final PathArgument identifier) {
+ if (identifier instanceof NodeIdentifierWithPredicates) {
+ return entryStrategy;
+ }
+ return Optional.absent();
+ }
+
+ @Override
+ public String toString() {
+ return "UnorderedMapModificationStrategy [entry=" + entryStrategy + "]";
+ }
+ }
+}
\ No newline at end of file
import static com.google.common.base.Preconditions.checkArgument;
-import java.util.HashSet;
import java.util.List;
-import java.util.Map;
-import java.util.Set;
-import java.util.concurrent.ExecutionException;
import org.opendaylight.controller.md.sal.dom.store.impl.tree.DataPreconditionFailedException;
-import org.opendaylight.controller.md.sal.dom.store.impl.tree.StoreUtils;
+import org.opendaylight.controller.md.sal.dom.store.impl.tree.ModificationType;
+import org.opendaylight.controller.md.sal.dom.store.impl.tree.data.DataNodeContainerModificationStrategy.ContainerModificationStrategy;
+import org.opendaylight.controller.md.sal.dom.store.impl.tree.data.DataNodeContainerModificationStrategy.UnkeyedListItemModificationStrategy;
+import org.opendaylight.controller.md.sal.dom.store.impl.tree.data.NormalizedNodeContainerModificationStrategy.ChoiceModificationStrategy;
+import org.opendaylight.controller.md.sal.dom.store.impl.tree.data.NormalizedNodeContainerModificationStrategy.OrderedLeafSetModificationStrategy;
+import org.opendaylight.controller.md.sal.dom.store.impl.tree.data.NormalizedNodeContainerModificationStrategy.OrderedMapModificationStrategy;
+import org.opendaylight.controller.md.sal.dom.store.impl.tree.data.NormalizedNodeContainerModificationStrategy.UnorderedLeafSetModificationStrategy;
+import org.opendaylight.controller.md.sal.dom.store.impl.tree.data.ValueNodeModificationStrategy.LeafModificationStrategy;
import org.opendaylight.yangtools.yang.common.QName;
import org.opendaylight.yangtools.yang.data.api.InstanceIdentifier;
import org.opendaylight.yangtools.yang.data.api.InstanceIdentifier.AugmentationIdentifier;
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.InstanceIdentifier.NodeWithValue;
import org.opendaylight.yangtools.yang.data.api.InstanceIdentifier.PathArgument;
-import org.opendaylight.yangtools.yang.data.api.schema.AugmentationNode;
-import org.opendaylight.yangtools.yang.data.api.schema.ContainerNode;
-import org.opendaylight.yangtools.yang.data.api.schema.LeafNode;
-import org.opendaylight.yangtools.yang.data.api.schema.LeafSetEntryNode;
-import org.opendaylight.yangtools.yang.data.api.schema.LeafSetNode;
-import org.opendaylight.yangtools.yang.data.api.schema.MapEntryNode;
-import org.opendaylight.yangtools.yang.data.api.schema.MapNode;
import org.opendaylight.yangtools.yang.data.api.schema.NormalizedNode;
-import org.opendaylight.yangtools.yang.data.api.schema.NormalizedNodeContainer;
-import org.opendaylight.yangtools.yang.data.api.schema.OrderedLeafSetNode;
-import org.opendaylight.yangtools.yang.data.api.schema.OrderedMapNode;
-import org.opendaylight.yangtools.yang.data.api.schema.UnkeyedListEntryNode;
-import org.opendaylight.yangtools.yang.data.impl.schema.builder.api.DataContainerNodeBuilder;
-import org.opendaylight.yangtools.yang.data.impl.schema.builder.api.NormalizedNodeContainerBuilder;
-import org.opendaylight.yangtools.yang.data.impl.schema.builder.impl.ImmutableAugmentationNodeBuilder;
-import org.opendaylight.yangtools.yang.data.impl.schema.builder.impl.ImmutableChoiceNodeBuilder;
-import org.opendaylight.yangtools.yang.data.impl.schema.builder.impl.ImmutableContainerNodeBuilder;
-import org.opendaylight.yangtools.yang.data.impl.schema.builder.impl.ImmutableLeafSetNodeBuilder;
-import org.opendaylight.yangtools.yang.data.impl.schema.builder.impl.ImmutableMapEntryNodeBuilder;
-import org.opendaylight.yangtools.yang.data.impl.schema.builder.impl.ImmutableMapNodeBuilder;
-import org.opendaylight.yangtools.yang.data.impl.schema.builder.impl.ImmutableOrderedLeafSetNodeBuilder;
-import org.opendaylight.yangtools.yang.data.impl.schema.builder.impl.ImmutableOrderedMapNodeBuilder;
-import org.opendaylight.yangtools.yang.data.impl.schema.builder.impl.ImmutableUnkeyedListEntryNodeBuilder;
-import org.opendaylight.yangtools.yang.data.impl.schema.transform.base.AugmentationSchemaProxy;
import org.opendaylight.yangtools.yang.model.api.AugmentationSchema;
import org.opendaylight.yangtools.yang.model.api.AugmentationTarget;
-import org.opendaylight.yangtools.yang.model.api.ChoiceCaseNode;
import org.opendaylight.yangtools.yang.model.api.ChoiceNode;
import org.opendaylight.yangtools.yang.model.api.ContainerSchemaNode;
import org.opendaylight.yangtools.yang.model.api.DataNodeContainer;
import org.opendaylight.yangtools.yang.model.api.LeafListSchemaNode;
import org.opendaylight.yangtools.yang.model.api.LeafSchemaNode;
import org.opendaylight.yangtools.yang.model.api.ListSchemaNode;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
-import com.google.common.base.Function;
import com.google.common.base.Optional;
import com.google.common.base.Preconditions;
-import com.google.common.cache.CacheBuilder;
-import com.google.common.cache.CacheLoader;
-import com.google.common.cache.LoadingCache;
-import com.google.common.collect.ImmutableMap;
import com.google.common.primitives.UnsignedLong;
abstract class SchemaAwareApplyOperation implements ModificationApplyOperation {
+ private static final Logger LOG = LoggerFactory.getLogger(SchemaAwareApplyOperation.class);
public static SchemaAwareApplyOperation from(final DataSchemaNode schemaNode) {
if (schemaNode instanceof ContainerSchemaNode) {
throw new IllegalArgumentException("Not supported schema node type for " + schemaNode.getClass());
}
+ public static SchemaAwareApplyOperation from(final DataNodeContainer resolvedTree,
+ final AugmentationTarget augSchemas, final AugmentationIdentifier identifier) {
+ AugmentationSchema augSchema = null;
+
+ allAugments:
+ for (AugmentationSchema potential : augSchemas.getAvailableAugmentations()) {
+ for (DataSchemaNode child : potential.getChildNodes()) {
+ if (identifier.getPossibleChildNames().contains(child.getQName())) {
+ augSchema = potential;
+ break allAugments;
+ }
+ }
+ }
+
+ if (augSchema != null) {
+ return new DataNodeContainerModificationStrategy.AugmentationModificationStrategy(augSchema, resolvedTree);
+ }
+ return null;
+ }
+
private static SchemaAwareApplyOperation fromListSchemaNode(final ListSchemaNode schemaNode) {
List<QName> keyDefinition = schemaNode.getKeyDefinition();
if (keyDefinition == null || keyDefinition.isEmpty()) {
return new OrderedMapModificationStrategy(schemaNode);
}
- return new UnorderedMapModificationStrategy(schemaNode);
+ return new NormalizedNodeContainerModificationStrategy.UnorderedMapModificationStrategy(schemaNode);
}
private static SchemaAwareApplyOperation fromLeafListSchemaNode(final LeafListSchemaNode schemaNode) {
}
}
-
- public static SchemaAwareApplyOperation from(final DataNodeContainer resolvedTree,
- final AugmentationTarget augSchemas, final AugmentationIdentifier identifier) {
- AugmentationSchema augSchema = null;
-
- allAugments:
- for (AugmentationSchema potential : augSchemas.getAvailableAugmentations()) {
- for (DataSchemaNode child : potential.getChildNodes()) {
- if (identifier.getPossibleChildNames().contains(child.getQName())) {
- augSchema = potential;
- break allAugments;
- }
- }
- }
-
- if (augSchema != null) {
- return new AugmentationModificationStrategy(augSchema, resolvedTree);
- }
- return null;
+ private static final void checkNotConflicting(final InstanceIdentifier path,final StoreMetadataNode original, final StoreMetadataNode current) throws DataPreconditionFailedException {
+ checkDataPrecondition(path, original.getNodeVersion().equals(current.getNodeVersion()),"Node was replaced by other transaction.");
+ checkDataPrecondition(path,original.getSubtreeVersion().equals(current.getSubtreeVersion()), "Node children was modified by other transaction");
}
protected final ModificationApplyOperation resolveChildOperation(final PathArgument child) {
}
}
- protected abstract void verifyWrittenStructure(NormalizedNode<?, ?> writtenValue);
-
@Override
public void checkApplicable(final InstanceIdentifier path,final NodeModification modification, final Optional<StoreMetadataNode> current) throws DataPreconditionFailedException {
switch (modification.getModificationType()) {
}
}
- protected static final void checkNotConflicting(final InstanceIdentifier path,final StoreMetadataNode original, final StoreMetadataNode current) throws DataPreconditionFailedException {
- checkDataPrecondition(path, original.getNodeVersion().equals(current.getNodeVersion()),"Node was replaced by other transaction.");
- checkDataPrecondition(path,original.getSubtreeVersion().equals(current.getSubtreeVersion()), "Node children was modified by other transaction");
- }
-
- protected abstract void checkSubtreeModificationApplicable(InstanceIdentifier path,final NodeModification modification,
- final Optional<StoreMetadataNode> current) throws DataPreconditionFailedException;
-
private void checkDeleteApplicable(final NodeModification modification, final Optional<StoreMetadataNode> current) {
+ // Delete is always applicable, we do not expose it to subclasses
+ if (current.isPresent()) {
+ LOG.trace("Delete operation turned to no-op on missing node {}", modification);
+ }
}
@Override
protected abstract StoreMetadataNode applySubtreeChange(NodeModification modification,
StoreMetadataNode currentMeta, UnsignedLong subtreeVersion);
- public static abstract class ValueNodeModificationStrategy<T extends DataSchemaNode> extends SchemaAwareApplyOperation {
-
- private final T schema;
- private final Class<? extends NormalizedNode<?, ?>> nodeClass;
-
- protected ValueNodeModificationStrategy(final T schema, final Class<? extends NormalizedNode<?, ?>> nodeClass) {
- super();
- this.schema = schema;
- this.nodeClass = nodeClass;
- }
-
- @Override
- protected void verifyWrittenStructure(final NormalizedNode<?, ?> writtenValue) {
- checkArgument(nodeClass.isInstance(writtenValue), "Node should must be of type %s", nodeClass);
- }
-
- @Override
- public Optional<ModificationApplyOperation> getChild(final PathArgument child) {
- throw new UnsupportedOperationException("Node " + schema.getPath()
- + "is leaf type node. Child nodes not allowed");
- }
-
- @Override
- protected StoreMetadataNode applySubtreeChange(final NodeModification modification,
- final StoreMetadataNode currentMeta, final UnsignedLong subtreeVersion) {
- throw new UnsupportedOperationException("Node " + schema.getPath()
- + "is leaf type node. Subtree change is not allowed.");
- }
-
- @Override
- protected StoreMetadataNode applyMerge(final NodeModification modification, final StoreMetadataNode currentMeta,
- final UnsignedLong subtreeVersion) {
- return applyWrite(modification, Optional.of(currentMeta), subtreeVersion);
- }
-
- @Override
- protected StoreMetadataNode applyWrite(final NodeModification modification,
- final Optional<StoreMetadataNode> currentMeta, final UnsignedLong subtreeVersion) {
- UnsignedLong nodeVersion = subtreeVersion;
- return StoreMetadataNode.builder().setNodeVersion(nodeVersion).setSubtreeVersion(subtreeVersion)
- .setData(modification.getWrittenValue()).build();
- }
-
- @Override
- protected void checkSubtreeModificationApplicable(final InstanceIdentifier path,final NodeModification modification,
- final Optional<StoreMetadataNode> current) throws DataPreconditionFailedException {
- throw new DataPreconditionFailedException(path, "Subtree modification is not allowed.");
- }
-
- }
-
- public static class LeafSetEntryModificationStrategy extends ValueNodeModificationStrategy<LeafListSchemaNode> {
-
- @SuppressWarnings({ "unchecked", "rawtypes" })
- protected LeafSetEntryModificationStrategy(final LeafListSchemaNode schema) {
- super(schema, (Class) LeafSetEntryNode.class);
- }
- }
-
- public static class LeafModificationStrategy extends ValueNodeModificationStrategy<LeafSchemaNode> {
-
- @SuppressWarnings({ "unchecked", "rawtypes" })
- protected LeafModificationStrategy(final LeafSchemaNode schema) {
- super(schema, (Class) LeafNode.class);
- }
- }
-
- public static abstract class NormalizedNodeContainerModificationStrategy extends SchemaAwareApplyOperation {
-
- private final Class<? extends NormalizedNode<?, ?>> nodeClass;
-
- protected NormalizedNodeContainerModificationStrategy(final Class<? extends NormalizedNode<?, ?>> nodeClass) {
- this.nodeClass = nodeClass;
- }
-
- @Override
- public void verifyStructure(final NodeModification modification) throws IllegalArgumentException {
- if (modification.getModificationType() == ModificationType.WRITE) {
-
- }
- for (NodeModification childModification : modification.getModifications()) {
- resolveChildOperation(childModification.getIdentifier()).verifyStructure(childModification);
- }
- }
-
- @Override
- protected void checkWriteApplicable(final InstanceIdentifier path, final NodeModification modification,
- final Optional<StoreMetadataNode> current) throws DataPreconditionFailedException {
- // FIXME: Implement proper write check for replacement of node container
- // prerequisite is to have transaction chain available for clients
- // otherwise this will break chained writes to same node.
- }
-
- @SuppressWarnings("rawtypes")
- @Override
- protected void verifyWrittenStructure(final NormalizedNode<?, ?> writtenValue) {
- checkArgument(nodeClass.isInstance(writtenValue), "Node should must be of type %s", nodeClass);
- checkArgument(writtenValue instanceof NormalizedNodeContainer);
-
- NormalizedNodeContainer container = (NormalizedNodeContainer) writtenValue;
- for (Object child : container.getValue()) {
- checkArgument(child instanceof NormalizedNode);
-
- /*
- * FIXME: fail-fast semantics:
- *
- * We can validate the data structure here, aborting the commit
- * before it ever progresses to being committed.
- */
- }
- }
-
- @Override
- protected StoreMetadataNode applyWrite(final NodeModification modification,
- final Optional<StoreMetadataNode> currentMeta, final UnsignedLong subtreeVersion) {
-
- NormalizedNode<?, ?> newValue = modification.getWrittenValue();
-
- final UnsignedLong nodeVersion;
- if (currentMeta.isPresent()) {
- nodeVersion = StoreUtils.increase(currentMeta.get().getNodeVersion());
- } else {
- nodeVersion = subtreeVersion;
- }
-
- final StoreMetadataNode newValueMeta = StoreMetadataNode.createRecursively(newValue, nodeVersion, nodeVersion);
- if (!modification.hasAdditionalModifications()) {
- return newValueMeta;
- }
-
- @SuppressWarnings("rawtypes")
- NormalizedNodeContainerBuilder dataBuilder = createBuilder(newValue);
- StoreNodeCompositeBuilder builder = StoreNodeCompositeBuilder.from(dataBuilder) //
- .setNodeVersion(nodeVersion) //
- .setSubtreeVersion(subtreeVersion);
-
- return mutateChildren(modification.getModifications(), newValueMeta, builder, nodeVersion);
- }
-
- @Override
- protected StoreMetadataNode applyMerge(final NodeModification modification, final StoreMetadataNode currentMeta,
- final UnsignedLong subtreeVersion) {
- // For Node Containers - merge is same as subtree change - we only replace children.
- return applySubtreeChange(modification, currentMeta, subtreeVersion);
- }
-
- @Override
- public StoreMetadataNode applySubtreeChange(final NodeModification modification,
- final StoreMetadataNode currentMeta, final UnsignedLong subtreeVersion) {
- // Bump subtree version to its new target
- final UnsignedLong updatedSubtreeVersion = StoreUtils.increase(currentMeta.getSubtreeVersion());
-
- @SuppressWarnings("rawtypes")
- NormalizedNodeContainerBuilder dataBuilder = createBuilder(currentMeta.getData());
- StoreNodeCompositeBuilder builder = StoreNodeCompositeBuilder.from(dataBuilder, currentMeta)
- .setIdentifier(modification.getIdentifier()).setNodeVersion(currentMeta.getNodeVersion())
- .setSubtreeVersion(updatedSubtreeVersion);
-
- return mutateChildren(modification.getModifications(), currentMeta, builder, updatedSubtreeVersion);
- }
-
- private StoreMetadataNode mutateChildren(final Iterable<NodeModification> modifications, final StoreMetadataNode meta,
- final StoreNodeCompositeBuilder builder, final UnsignedLong nodeVersion) {
-
- for (NodeModification mod : modifications) {
- final PathArgument id = mod.getIdentifier();
- final Optional<StoreMetadataNode> cm = meta.getChild(id);
-
- Optional<StoreMetadataNode> result = resolveChildOperation(id).apply(mod, cm, nodeVersion);
- if (result.isPresent()) {
- builder.add(result.get());
- } else {
- builder.remove(id);
- }
- }
-
- return builder.build();
- }
-
- @Override
- protected void checkSubtreeModificationApplicable(final InstanceIdentifier path,final NodeModification modification,
- final Optional<StoreMetadataNode> current) throws DataPreconditionFailedException {
- checkDataPrecondition(path, current.isPresent(), "Node was deleted by other transaction.");
- checkChildPreconditions(path,modification,current);
-
- }
-
- private void checkChildPreconditions(final InstanceIdentifier path, final NodeModification modification, final Optional<StoreMetadataNode> current) throws DataPreconditionFailedException {
- StoreMetadataNode currentMeta = current.get();
- for (NodeModification childMod : modification.getModifications()) {
- PathArgument childId = childMod.getIdentifier();
- Optional<StoreMetadataNode> childMeta = currentMeta.getChild(childId);
- InstanceIdentifier childPath = StoreUtils.append(path, childId);
- resolveChildOperation(childId).checkApplicable(childPath,childMod, childMeta);
- }
- }
-
- @Override
- protected void checkMergeApplicable(final InstanceIdentifier path, final NodeModification modification,
- final Optional<StoreMetadataNode> current) throws DataPreconditionFailedException {
- if(current.isPresent()) {
- checkChildPreconditions(path,modification,current);
- }
- }
-
- @SuppressWarnings("rawtypes")
- protected abstract NormalizedNodeContainerBuilder createBuilder(NormalizedNode<?, ?> original);
- }
-
- public static abstract class DataNodeContainerModificationStrategy<T extends DataNodeContainer> extends NormalizedNodeContainerModificationStrategy {
-
- private final T schema;
- private final LoadingCache<PathArgument, ModificationApplyOperation> childCache = CacheBuilder.newBuilder()
- .build(CacheLoader.from(new Function<PathArgument, ModificationApplyOperation>() {
-
- @Override
- public ModificationApplyOperation apply(final PathArgument identifier) {
- if (identifier instanceof AugmentationIdentifier && schema instanceof AugmentationTarget) {
- return from(schema, (AugmentationTarget) schema, (AugmentationIdentifier) identifier);
- }
-
- DataSchemaNode child = schema.getDataChildByName(identifier.getNodeType());
- if (child == null) {
- return null;
- }
- return from(child);
- }
- }));
-
- protected DataNodeContainerModificationStrategy(final T schema,
- final Class<? extends NormalizedNode<?, ?>> nodeClass) {
- super(nodeClass);
- this.schema = schema;
- }
-
- protected T getSchema() {
- return schema;
- }
-
- @Override
- public Optional<ModificationApplyOperation> getChild(final PathArgument identifier) {
- try {
- return Optional.<ModificationApplyOperation> fromNullable(childCache.get(identifier));
- } catch (ExecutionException e) {
- return Optional.absent();
- }
- }
-
- @Override
- @SuppressWarnings("rawtypes")
- protected abstract DataContainerNodeBuilder createBuilder(NormalizedNode<?, ?> original);
-
- @Override
- public String toString() {
- return getClass().getSimpleName() + " [" + schema + "]";
- }
-
- }
-
- public static class ContainerModificationStrategy extends DataNodeContainerModificationStrategy<ContainerSchemaNode> {
-
- public ContainerModificationStrategy(final ContainerSchemaNode schemaNode) {
- super(schemaNode, ContainerNode.class);
- }
-
- @Override
- @SuppressWarnings("rawtypes")
- protected DataContainerNodeBuilder createBuilder(final NormalizedNode<?, ?> original) {
- checkArgument(original instanceof ContainerNode);
- return ImmutableContainerNodeBuilder.create((ContainerNode) original);
- }
- }
-
- public static class UnkeyedListItemModificationStrategy extends DataNodeContainerModificationStrategy<ListSchemaNode> {
-
- public UnkeyedListItemModificationStrategy(final ListSchemaNode schemaNode) {
- super(schemaNode, UnkeyedListEntryNode.class);
- }
-
- @Override
- @SuppressWarnings("rawtypes")
- protected DataContainerNodeBuilder createBuilder(final NormalizedNode<?, ?> original) {
- checkArgument(original instanceof UnkeyedListEntryNode);
- return ImmutableUnkeyedListEntryNodeBuilder.create((UnkeyedListEntryNode) original);
- }
- }
-
- public static class AugmentationModificationStrategy extends DataNodeContainerModificationStrategy<AugmentationSchema> {
-
- protected AugmentationModificationStrategy(final AugmentationSchema schema, final DataNodeContainer resolved) {
- super(createAugmentProxy(schema,resolved), AugmentationNode.class);
- }
-
- @Override
- @SuppressWarnings("rawtypes")
- protected DataContainerNodeBuilder createBuilder(final NormalizedNode<?, ?> original) {
- checkArgument(original instanceof AugmentationNode);
- return ImmutableAugmentationNodeBuilder.create((AugmentationNode) original);
- }
- }
-
- public static class ChoiceModificationStrategy extends NormalizedNodeContainerModificationStrategy {
-
- private final Map<PathArgument, ModificationApplyOperation> childNodes;
-
- public ChoiceModificationStrategy(final ChoiceNode schemaNode) {
- super(org.opendaylight.yangtools.yang.data.api.schema.ChoiceNode.class);
- ImmutableMap.Builder<PathArgument, ModificationApplyOperation> child = ImmutableMap.builder();
-
- for (ChoiceCaseNode caze : schemaNode.getCases()) {
- for (DataSchemaNode cazeChild : caze.getChildNodes()) {
- SchemaAwareApplyOperation childNode = from(cazeChild);
- child.put(new NodeIdentifier(cazeChild.getQName()), childNode);
- }
- }
- childNodes = child.build();
- }
-
- @Override
- public Optional<ModificationApplyOperation> getChild(final PathArgument child) {
- return Optional.fromNullable(childNodes.get(child));
- }
-
- @Override
- @SuppressWarnings("rawtypes")
- protected DataContainerNodeBuilder createBuilder(final NormalizedNode<?, ?> original) {
- checkArgument(original instanceof org.opendaylight.yangtools.yang.data.api.schema.ChoiceNode);
- return ImmutableChoiceNodeBuilder.create((org.opendaylight.yangtools.yang.data.api.schema.ChoiceNode) original);
- }
- }
-
- public static class ListEntryModificationStrategy extends DataNodeContainerModificationStrategy<ListSchemaNode> {
-
- protected ListEntryModificationStrategy(final ListSchemaNode schema) {
- super(schema, MapEntryNode.class);
- }
-
- @Override
- @SuppressWarnings("rawtypes")
- protected final DataContainerNodeBuilder createBuilder(final NormalizedNode<?, ?> original) {
- checkArgument(original instanceof MapEntryNode);
- return ImmutableMapEntryNodeBuilder.create((MapEntryNode) original);
- }
- }
-
- public static class UnorderedLeafSetModificationStrategy extends NormalizedNodeContainerModificationStrategy {
-
- private final Optional<ModificationApplyOperation> entryStrategy;
-
- @SuppressWarnings({ "unchecked", "rawtypes" })
- protected UnorderedLeafSetModificationStrategy(final LeafListSchemaNode schema) {
- super((Class) LeafSetNode.class);
- entryStrategy = Optional.<ModificationApplyOperation> of(new LeafSetEntryModificationStrategy(schema));
- }
-
- @SuppressWarnings("rawtypes")
- @Override
- protected NormalizedNodeContainerBuilder createBuilder(final NormalizedNode<?, ?> original) {
- checkArgument(original instanceof LeafSetNode<?>);
- return ImmutableLeafSetNodeBuilder.create((LeafSetNode<?>) original);
- }
-
- @Override
- public Optional<ModificationApplyOperation> getChild(final PathArgument identifier) {
- if (identifier instanceof NodeWithValue) {
- return entryStrategy;
- }
- return Optional.absent();
- }
- }
-
- public static class OrderedLeafSetModificationStrategy extends NormalizedNodeContainerModificationStrategy {
-
- private final Optional<ModificationApplyOperation> entryStrategy;
-
- @SuppressWarnings({ "unchecked", "rawtypes" })
- protected OrderedLeafSetModificationStrategy(final LeafListSchemaNode schema) {
- super((Class) LeafSetNode.class);
- entryStrategy = Optional.<ModificationApplyOperation> of(new LeafSetEntryModificationStrategy(schema));
- }
-
- @SuppressWarnings("rawtypes")
- @Override
- protected NormalizedNodeContainerBuilder createBuilder(final NormalizedNode<?, ?> original) {
- checkArgument(original instanceof OrderedLeafSetNode<?>);
- return ImmutableOrderedLeafSetNodeBuilder.create((OrderedLeafSetNode<?>) original);
- }
+ protected abstract void checkSubtreeModificationApplicable(InstanceIdentifier path,final NodeModification modification,
+ final Optional<StoreMetadataNode> current) throws DataPreconditionFailedException;
- @Override
- public Optional<ModificationApplyOperation> getChild(final PathArgument identifier) {
- if (identifier instanceof NodeWithValue) {
- return entryStrategy;
- }
- return Optional.absent();
- }
- }
+ protected abstract void verifyWrittenStructure(NormalizedNode<?, ?> writtenValue);
public static class UnkeyedListModificationStrategy extends SchemaAwareApplyOperation {
final Optional<StoreMetadataNode> current) throws DataPreconditionFailedException {
throw new DataPreconditionFailedException(path, "Subtree modification is not allowed.");
}
-
- }
-
- public static class UnorderedMapModificationStrategy extends NormalizedNodeContainerModificationStrategy {
-
- private final Optional<ModificationApplyOperation> entryStrategy;
-
- protected UnorderedMapModificationStrategy(final ListSchemaNode schema) {
- super(MapNode.class);
- entryStrategy = Optional.<ModificationApplyOperation> of(new ListEntryModificationStrategy(schema));
- }
-
- @SuppressWarnings("rawtypes")
- @Override
- protected NormalizedNodeContainerBuilder createBuilder(final NormalizedNode<?, ?> original) {
- checkArgument(original instanceof MapNode);
- return ImmutableMapNodeBuilder.create((MapNode) original);
- }
-
- @Override
- public Optional<ModificationApplyOperation> getChild(final PathArgument identifier) {
- if (identifier instanceof NodeIdentifierWithPredicates) {
- return entryStrategy;
- }
- return Optional.absent();
- }
-
- @Override
- public String toString() {
- return "UnorderedMapModificationStrategy [entry=" + entryStrategy + "]";
- }
- }
-
- public static class OrderedMapModificationStrategy extends NormalizedNodeContainerModificationStrategy {
-
- private final Optional<ModificationApplyOperation> entryStrategy;
-
- protected OrderedMapModificationStrategy(final ListSchemaNode schema) {
- super(OrderedMapNode.class);
- entryStrategy = Optional.<ModificationApplyOperation> of(new ListEntryModificationStrategy(schema));
- }
-
- @SuppressWarnings("rawtypes")
- @Override
- protected NormalizedNodeContainerBuilder createBuilder(final NormalizedNode<?, ?> original) {
- checkArgument(original instanceof OrderedMapNode);
- return ImmutableOrderedMapNodeBuilder.create((OrderedMapNode) original);
- }
-
- @Override
- public Optional<ModificationApplyOperation> getChild(final PathArgument identifier) {
- if (identifier instanceof NodeIdentifierWithPredicates) {
- return entryStrategy;
- }
- return Optional.absent();
- }
-
- @Override
- public String toString() {
- return "OrderedMapModificationStrategy [entry=" + entryStrategy + "]";
- }
- }
-
- public static AugmentationSchema createAugmentProxy(final AugmentationSchema schema, final DataNodeContainer resolved) {
- Set<DataSchemaNode> realChildSchemas = new HashSet<>();
- for(DataSchemaNode augChild : schema.getChildNodes()) {
- realChildSchemas.add(resolved.getDataChildByName(augChild.getQName()));
- }
- return new AugmentationSchemaProxy(schema, realChildSchemas);
}
public static boolean checkDataPrecondition(final InstanceIdentifier path, final boolean condition, final String message) throws DataPreconditionFailedException {
import java.util.HashMap;
import java.util.Map;
-import org.opendaylight.controller.md.sal.dom.store.impl.tree.StoreTreeNode;
import org.opendaylight.yangtools.concepts.Identifiable;
import org.opendaylight.yangtools.concepts.Immutable;
import org.opendaylight.yangtools.yang.data.api.InstanceIdentifier.PathArgument;
import com.google.common.base.Preconditions;
import com.google.common.primitives.UnsignedLong;
-// FIXME: this should not be public
-public class StoreMetadataNode implements Immutable, Identifiable<PathArgument>, StoreTreeNode<StoreMetadataNode> {
-
+class StoreMetadataNode implements Immutable, Identifiable<PathArgument> {
+ private final Map<PathArgument, StoreMetadataNode> children;
private final UnsignedLong nodeVersion;
private final UnsignedLong subtreeVersion;
private final NormalizedNode<?, ?> data;
- private final Map<PathArgument, StoreMetadataNode> children;
-
/**
*
* @param data
* @param subtreeVersion
* @param children Map of children, must not be modified externally
*/
- protected StoreMetadataNode(final NormalizedNode<?, ?> data, final UnsignedLong nodeVersion,
+ private StoreMetadataNode(final NormalizedNode<?, ?> data, final UnsignedLong nodeVersion,
final UnsignedLong subtreeVersion, final Map<PathArgument, StoreMetadataNode> children) {
- this.nodeVersion = nodeVersion;
- this.subtreeVersion = subtreeVersion;
- this.data = data;
+ this.nodeVersion = Preconditions.checkNotNull(nodeVersion);
+ this.subtreeVersion = Preconditions.checkNotNull(subtreeVersion);
+ this.data = Preconditions.checkNotNull(data);
this.children = Preconditions.checkNotNull(children);
}
Collections.<PathArgument, StoreMetadataNode>emptyMap());
}
- public StoreMetadataNode(final NormalizedNode<?, ?> data, final UnsignedLong nodeVersion,
- final UnsignedLong subtreeVersion) {
- this(data, nodeVersion, subtreeVersion, Collections.<PathArgument, StoreMetadataNode>emptyMap());
- }
-
- public static Builder builder() {
- return new Builder();
+ public static Builder builder(final UnsignedLong version) {
+ return new Builder(version);
}
- public static Builder builder(StoreMetadataNode node) {
+ public static Builder builder(final StoreMetadataNode node) {
return new Builder(node);
}
return this.data;
}
- @Override
- public Optional<StoreMetadataNode> getChild(final PathArgument key) {
+ Optional<StoreMetadataNode> getChild(final PathArgument key) {
return Optional.fromNullable(children.get(key));
}
return "StoreMetadataNode [identifier=" + getIdentifier() + ", nodeVersion=" + nodeVersion + "]";
}
- public static Optional<UnsignedLong> getVersion(final Optional<StoreMetadataNode> currentMetadata) {
- if (currentMetadata.isPresent()) {
- return Optional.of(currentMetadata.get().getNodeVersion());
- }
- return Optional.absent();
- }
-
- public static Optional<StoreMetadataNode> getChild(final Optional<StoreMetadataNode> parent,
- final PathArgument child) {
- if (parent.isPresent()) {
- return parent.get().getChild(child);
- }
- return Optional.absent();
- }
-
public static final StoreMetadataNode createRecursively(final NormalizedNode<?, ?> node,
- final UnsignedLong nodeVersion, final UnsignedLong subtreeVersion) {
- Builder builder = builder() //
- .setNodeVersion(nodeVersion) //
- .setSubtreeVersion(subtreeVersion) //
+ final UnsignedLong version) {
+ Builder builder = builder(version) //
+ .setSubtreeVersion(version) //
.setData(node);
if (node instanceof NormalizedNodeContainer<?, ?, ?>) {
@SuppressWarnings("unchecked")
NormalizedNodeContainer<?, ?, NormalizedNode<?, ?>> nodeContainer = (NormalizedNodeContainer<?, ?, NormalizedNode<?, ?>>) node;
for (NormalizedNode<?, ?> subNode : nodeContainer.getValue()) {
- builder.add(createRecursively(subNode, nodeVersion, subtreeVersion));
+ builder.add(createRecursively(subNode, version));
}
}
return builder.build();
public static class Builder {
- private UnsignedLong nodeVersion;
+ private final UnsignedLong nodeVersion;
private UnsignedLong subtreeVersion;
private NormalizedNode<?, ?> data;
private Map<PathArgument, StoreMetadataNode> children;
private boolean dirty = false;
- private Builder() {
+ private Builder(final UnsignedLong version) {
+ this.nodeVersion = Preconditions.checkNotNull(version);
children = new HashMap<>();
}
- public Builder(StoreMetadataNode node) {
+ private Builder(final StoreMetadataNode node) {
+ this.nodeVersion = node.getNodeVersion();
children = new HashMap<>(node.children);
}
- public UnsignedLong getVersion() {
- return nodeVersion;
-
- }
-
- public Builder setNodeVersion(final UnsignedLong version) {
- this.nodeVersion = version;
- return this;
- }
-
public Builder setSubtreeVersion(final UnsignedLong version) {
this.subtreeVersion = version;
return this;
}
}
- public static StoreMetadataNode createRecursively(final NormalizedNode<?, ?> node, final UnsignedLong version) {
- return createRecursively(node, version, version);
- }
}
private final NormalizedNodeContainerBuilder data;
- private StoreNodeCompositeBuilder(final NormalizedNodeContainerBuilder nodeBuilder) {
- this.metadata = StoreMetadataNode.builder();
+ private StoreNodeCompositeBuilder(final UnsignedLong version, final NormalizedNodeContainerBuilder nodeBuilder) {
+ this.metadata = StoreMetadataNode.builder(version);
this.data = Preconditions.checkNotNull(nodeBuilder);
}
- public StoreNodeCompositeBuilder(NormalizedNodeContainerBuilder nodeBuilder, StoreMetadataNode currentMeta) {
+ private StoreNodeCompositeBuilder(final NormalizedNodeContainerBuilder nodeBuilder, final StoreMetadataNode currentMeta) {
this.metadata = StoreMetadataNode.builder(currentMeta);
this.data = Preconditions.checkNotNull(nodeBuilder);
}
}
@SuppressWarnings("unchecked")
- public StoreNodeCompositeBuilder remove(PathArgument id) {
+ public StoreNodeCompositeBuilder remove(final PathArgument id) {
metadata.remove(id);
data.removeChild(id);
return this;
return metadata.setData(data.build()).build();
}
- public static StoreNodeCompositeBuilder from(final NormalizedNodeContainerBuilder nodeBuilder) {
- return new StoreNodeCompositeBuilder(nodeBuilder);
+ public static StoreNodeCompositeBuilder create(final UnsignedLong version, final NormalizedNodeContainerBuilder nodeBuilder) {
+ return new StoreNodeCompositeBuilder(version, nodeBuilder);
}
- public static StoreNodeCompositeBuilder from(final NormalizedNodeContainerBuilder nodeBuilder, StoreMetadataNode currentMeta) {
+ public static StoreNodeCompositeBuilder create(final NormalizedNodeContainerBuilder nodeBuilder, final StoreMetadataNode currentMeta) {
return new StoreNodeCompositeBuilder(nodeBuilder, currentMeta);
}
return this;
}
- public StoreNodeCompositeBuilder setNodeVersion(final UnsignedLong nodeVersion) {
- metadata.setNodeVersion(nodeVersion);
- return this;
- }
-
public StoreNodeCompositeBuilder setSubtreeVersion(final UnsignedLong updatedSubtreeVersion) {
metadata.setSubtreeVersion(updatedSubtreeVersion);
return this;
--- /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.controller.md.sal.dom.store.impl.tree.data;
+
+ import static com.google.common.base.Preconditions.checkArgument;
+
+import org.opendaylight.controller.md.sal.dom.store.impl.tree.DataPreconditionFailedException;
+ import org.opendaylight.yangtools.yang.data.api.InstanceIdentifier;
+ import org.opendaylight.yangtools.yang.data.api.InstanceIdentifier.PathArgument;
+ import org.opendaylight.yangtools.yang.data.api.schema.LeafNode;
+ import org.opendaylight.yangtools.yang.data.api.schema.LeafSetEntryNode;
+ import org.opendaylight.yangtools.yang.data.api.schema.NormalizedNode;
+ import org.opendaylight.yangtools.yang.model.api.DataSchemaNode;
+ import org.opendaylight.yangtools.yang.model.api.LeafListSchemaNode;
+ import org.opendaylight.yangtools.yang.model.api.LeafSchemaNode;
+
+import com.google.common.base.Optional;
+ import com.google.common.primitives.UnsignedLong;
+
+ abstract class ValueNodeModificationStrategy<T extends DataSchemaNode> extends SchemaAwareApplyOperation {
+
+ private final T schema;
+ private final Class<? extends NormalizedNode<?, ?>> nodeClass;
+
+ protected ValueNodeModificationStrategy(final T schema, final Class<? extends NormalizedNode<?, ?>> nodeClass) {
+ super();
+ this.schema = schema;
+ this.nodeClass = nodeClass;
+ }
+
+ @Override
+ protected void verifyWrittenStructure(final NormalizedNode<?, ?> writtenValue) {
+ checkArgument(nodeClass.isInstance(writtenValue), "Node should must be of type %s", nodeClass);
+ }
+
+ @Override
+ public Optional<ModificationApplyOperation> getChild(final PathArgument child) {
+ throw new UnsupportedOperationException("Node " + schema.getPath()
+ + "is leaf type node. Child nodes not allowed");
+ }
+
+ @Override
+ protected StoreMetadataNode applySubtreeChange(final NodeModification modification,
+ final StoreMetadataNode currentMeta, final UnsignedLong subtreeVersion) {
+ throw new UnsupportedOperationException("Node " + schema.getPath()
+ + "is leaf type node. Subtree change is not allowed.");
+ }
+
+ @Override
+ protected StoreMetadataNode applyMerge(final NodeModification modification, final StoreMetadataNode currentMeta,
+ final UnsignedLong subtreeVersion) {
+ return applyWrite(modification, Optional.of(currentMeta), subtreeVersion);
+ }
+
+ @Override
+ protected StoreMetadataNode applyWrite(final NodeModification modification,
+ final Optional<StoreMetadataNode> currentMeta, final UnsignedLong subtreeVersion) {
+ return StoreMetadataNode.builder(subtreeVersion).setSubtreeVersion(subtreeVersion)
+ .setData(modification.getWrittenValue()).build();
+ }
+
+ @Override
+ protected void checkSubtreeModificationApplicable(final InstanceIdentifier path,final NodeModification modification,
+ final Optional<StoreMetadataNode> current) throws DataPreconditionFailedException {
+ throw new DataPreconditionFailedException(path, "Subtree modification is not allowed.");
+ }
+
+ public static class LeafSetEntryModificationStrategy extends ValueNodeModificationStrategy<LeafListSchemaNode> {
+ @SuppressWarnings({ "unchecked", "rawtypes" })
+ protected LeafSetEntryModificationStrategy(final LeafListSchemaNode schema) {
+ super(schema, (Class) LeafSetEntryNode.class);
+ }
+ }
+
+ public static class LeafModificationStrategy extends ValueNodeModificationStrategy<LeafSchemaNode> {
+ @SuppressWarnings({ "unchecked", "rawtypes" })
+ protected LeafModificationStrategy(final LeafSchemaNode schema) {
+ super(schema, (Class) LeafNode.class);
+ }
+ }
+ }
\ No newline at end of file
import org.opendaylight.yangtools.yang.model.api.ContainerSchemaNode;
import org.opendaylight.yangtools.yang.model.api.SchemaContext;
-public class SchemaAwareApplyOperationRoot extends SchemaAwareApplyOperation.DataNodeContainerModificationStrategy<ContainerSchemaNode> {
+public class SchemaAwareApplyOperationRoot extends DataNodeContainerModificationStrategy<ContainerSchemaNode> {
private final SchemaContext context;
public SchemaAwareApplyOperationRoot(final SchemaContext context) {
<version>1.1-SNAPSHOT</version>
</parent>
- <groupId>org.opendaylight.controller</groupId>
<artifactId>sal-rest-docgen</artifactId>
<packaging>bundle</packaging>
<plugin>
<groupId>org.apache.felix</groupId>
<artifactId>maven-bundle-plugin</artifactId>
- <version>2.4.0</version>
<extensions>true</extensions>
<configuration>
import java.util.List;
import org.opendaylight.controller.netconf.api.NetconfDocumentedException;
import org.opendaylight.controller.netconf.util.xml.XmlElement;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
public class SimpleAttributeReadingStrategy extends AbstractAttributeReadingStrategy {
- private static final Logger logger = LoggerFactory.getLogger(SimpleAttributeReadingStrategy.class);
-
-
public SimpleAttributeReadingStrategy(String nullableDefault) {
super(nullableDefault);
}
Preconditions.checkState(configNodes.size() == 1, "This element should be present only once " + xmlElement
+ " but was " + configNodes.size());
- String textContent = "";
- try{
- textContent = readElementContent(xmlElement);
- }catch(IllegalStateException | NullPointerException e) {
- // yuma sends <attribute /> for empty value instead of <attribute></attribute>
- logger.warn("Ignoring exception caused by failure to read text element", e);
- }
-
- if (null == textContent){
- throw new NetconfDocumentedException(String.format("This element should contain text %s", xmlElement),
- NetconfDocumentedException.ErrorType.application,
- NetconfDocumentedException.ErrorTag.invalid_value,
- NetconfDocumentedException.ErrorSeverity.error);
- }
+ String textContent = readElementContent(xmlElement);
return AttributeConfigElement.create(postprocessNullableDefault(getNullableDefault()),
postprocessParsedValue(textContent));
}
String refName = ((ObjectNameAttributeMappingStrategy.MappedDependency) value).getRefName();
String namespaceForType = ((ObjectNameAttributeMappingStrategy.MappedDependency) value).getNamespace();
- Element typeElement = XmlUtil.createPrefixedTextElement(document, XmlUtil.createPrefixedValue(XmlNetconfConstants.PREFIX, XmlNetconfConstants.TYPE_KEY), XmlNetconfConstants.PREFIX,
- moduleName, Optional.<String>of(namespaceForType));
+ Element typeElement = XmlUtil.createTextElementWithNamespacedContent(document, XmlNetconfConstants.TYPE_KEY, XmlNetconfConstants.PREFIX,
+ namespaceForType, moduleName);
+
innerNode.appendChild(typeElement);
final Element nameElement = XmlUtil.createTextElement(document, XmlNetconfConstants.NAME_KEY, refName, Optional.<String>absent());
@Override
protected Element createElement(Document doc, String key, String value, Optional<String> namespace) {
QName qName = QName.create(value);
- String identity = qName.getLocalName();
+ String identityValue = qName.getLocalName();
String identityNamespace = qName.getNamespace().toString();
- Element element = XmlUtil.createPrefixedTextElement(doc, XmlUtil.createPrefixedValue(PREFIX, key), PREFIX, identity, Optional.<String>of(identityNamespace));
- return element;
+ return XmlUtil.createTextElementWithNamespacedContent(doc, key, PREFIX, identityNamespace, identityValue);
}
}
public Element toXml(ObjectName instanceON, ServiceRegistryWrapper depTracker, Document document, String namespace) {
Element root = XmlUtil.createElement(document, XmlNetconfConstants.MODULE_KEY, Optional.<String>absent());
- // Xml.addNamespaceAttr(document, root, namespace);
- final String prefix = getPrefix();
- Element typeElement = XmlUtil.createPrefixedTextElement(document, XmlUtil.createPrefixedValue(prefix, XmlNetconfConstants.TYPE_KEY), prefix,
- moduleName, Optional.<String>of(namespace));
- // Xml.addNamespaceAttr(document, typeElement,
- // XMLUtil.URN_OPENDAYLIGHT_PARAMS_XML_NS_YANG_CONTROLLER_CONFIG);
+ // type belongs to config.yang namespace, but needs to be <type prefix:moduleNS>prefix:moduleName</type>
+
+ Element typeElement = XmlUtil.createTextElementWithNamespacedContent(document, XmlNetconfConstants.TYPE_KEY,
+ XmlNetconfConstants.PREFIX, namespace, moduleName);
+
root.appendChild(typeElement);
+ // name belongs to config.yang namespace
+ String instanceName = ObjectNameUtil.getInstanceName(instanceON);
+ Element nameElement = XmlUtil.createTextElement(document, XmlNetconfConstants.NAME_KEY, instanceName, Optional.<String>absent());
- Element nameElement = XmlUtil.createTextElement(document, XmlUtil.createPrefixedValue(prefix, XmlNetconfConstants.NAME_KEY),
- ObjectNameUtil.getInstanceName(instanceON), Optional.<String>of(namespace));
- // Xml.addNamespaceAttr(document, nameElement,
- // XMLUtil.URN_OPENDAYLIGHT_PARAMS_XML_NS_YANG_CONTROLLER_CONFIG);
root.appendChild(nameElement);
root = instanceConfig.toXml(instanceON, depTracker, namespace, document, root);
return root;
}
- private String getPrefix() {
- return XmlNetconfConstants.PREFIX;
- }
-
public ModuleElementResolved fromXml(XmlElement moduleElement, ServiceRegistryWrapper depTracker, String instanceName,
String moduleNamespace, EditStrategyType defaultStrategy, Map<String, Map<Date,EditConfig.IdentityMapping>> identityMap) throws NetconfDocumentedException {
for (String namespace : mappedServices.keySet()) {
for (Entry<String, Map<String, String>> serviceEntry : mappedServices.get(namespace).entrySet()) {
+ // service belongs to config.yang namespace
Element serviceElement = XmlUtil.createElement(document, SERVICE_KEY, Optional.<String>absent());
root.appendChild(serviceElement);
- Element typeElement = XmlUtil.createPrefixedTextElement(document, XmlUtil.createPrefixedValue(XmlNetconfConstants.PREFIX, TYPE_KEY), XmlNetconfConstants.PREFIX,
- serviceEntry.getKey(), Optional.of(namespace));
+ // type belongs to config.yang namespace
+ String serviceType = serviceEntry.getKey();
+ Element typeElement = XmlUtil.createTextElementWithNamespacedContent(document, XmlNetconfConstants.TYPE_KEY,
+ XmlNetconfConstants.PREFIX, namespace, serviceType);
+
serviceElement.appendChild(typeElement);
for (Entry<String, String> instanceEntry : serviceEntry.getValue().entrySet()) {
package org.opendaylight.controller.netconf.confignetconfconnector;
+import static org.custommonkey.xmlunit.XMLAssert.assertXMLEqual;
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertThat;
+import static org.junit.Assert.assertTrue;
+import static org.junit.Assert.fail;
+import static org.mockito.Mockito.doNothing;
+import static org.mockito.Mockito.doReturn;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.verifyNoMoreInteractions;
+import static org.opendaylight.controller.netconf.util.test.XmlUnitUtil.assertContainsElement;
+import static org.opendaylight.controller.netconf.util.test.XmlUnitUtil.assertContainsElementWithText;
+import static org.opendaylight.controller.netconf.util.xml.XmlUtil.readXmlToElement;
+
import com.google.common.base.Optional;
import com.google.common.base.Preconditions;
import com.google.common.collect.Lists;
import com.google.common.collect.Maps;
import com.google.common.collect.Sets;
+import java.io.FileNotFoundException;
+import java.io.IOException;
+import java.io.InputStream;
+import java.math.BigInteger;
+import java.net.URISyntaxException;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+import javax.management.InstanceAlreadyExistsException;
+import javax.management.InstanceNotFoundException;
+import javax.management.ObjectName;
+import javax.xml.parsers.ParserConfigurationException;
import org.custommonkey.xmlunit.AbstractNodeTester;
import org.custommonkey.xmlunit.NodeTest;
import org.custommonkey.xmlunit.NodeTestException;
import org.w3c.dom.traversal.DocumentTraversal;
import org.xml.sax.SAXException;
-import javax.management.InstanceAlreadyExistsException;
-import javax.management.InstanceNotFoundException;
-import javax.management.ObjectName;
-import javax.xml.parsers.ParserConfigurationException;
-import java.io.FileNotFoundException;
-import java.io.IOException;
-import java.io.InputStream;
-import java.math.BigInteger;
-import java.net.URISyntaxException;
-import java.util.ArrayList;
-import java.util.Arrays;
-import java.util.Collection;
-import java.util.Collections;
-import java.util.HashSet;
-import java.util.List;
-import java.util.Map;
-import java.util.Set;
-
-import static org.custommonkey.xmlunit.XMLAssert.assertXMLEqual;
-import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertThat;
-import static org.junit.Assert.assertTrue;
-import static org.junit.Assert.fail;
-import static org.mockito.Mockito.doNothing;
-import static org.mockito.Mockito.doReturn;
-import static org.mockito.Mockito.mock;
-import static org.mockito.Mockito.verify;
-import static org.mockito.Mockito.verifyNoMoreInteractions;
-import static org.opendaylight.controller.netconf.util.test.XmlUnitUtil.assertContainsElement;
-import static org.opendaylight.controller.netconf.util.test.XmlUnitUtil.assertContainsElementWithText;
-import static org.opendaylight.controller.netconf.util.xml.XmlUtil.readXmlToElement;
-
public class NetconfMappingTest extends AbstractConfigTest {
private static final Logger logger = LoggerFactory.getLogger(NetconfMappingTest.class);
String enumContent = "TWO";
for (XmlElement moduleElement : modulesElement.getChildElements("module")) {
- String name = moduleElement.getOnlyChildElement("prefix:name").getTextContent();
+ String name = moduleElement.getOnlyChildElement("name").getTextContent();
if(name.equals(INSTANCE_NAME)) {
XmlElement enumAttr = moduleElement.getOnlyChildElement(enumName);
assertEquals(enumContent, enumAttr.getTextContent());
for (XmlElement moduleElement : modulesElement.getChildElements("module")) {
for (XmlElement type : moduleElement.getChildElements("type")) {
- if (type.getNamespace() != null) {
+ if (type.getNamespaceOptionally().isPresent()) {
configAttributeType.add(type.getTextContent());
}
}
NetconfMessage response = netconfClient.sendMessage(getConfig);
- assertThat(XmlUtil.toString(response.getDocument()), JUnitMatchers.containsString("<prefix:afi xmlns:prefix=\"urn:opendaylight:params:xml:ns:yang:controller:config:test:types\">prefix:test-identity1</prefix:afi>"));
- assertThat(XmlUtil.toString(response.getDocument()), JUnitMatchers.containsString("<prefix:afi xmlns:prefix=\"urn:opendaylight:params:xml:ns:yang:controller:config:test:types\">prefix:test-identity2</prefix:afi>"));
- assertThat(XmlUtil.toString(response.getDocument()), JUnitMatchers.containsString("<prefix:safi xmlns:prefix=\"urn:opendaylight:params:xml:ns:yang:controller:config:test:types\">prefix:test-identity2</prefix:safi>"));
- assertThat(XmlUtil.toString(response.getDocument()), JUnitMatchers.containsString("<prefix:safi xmlns:prefix=\"urn:opendaylight:params:xml:ns:yang:controller:config:test:types\">prefix:test-identity1</prefix:safi>"));
+ assertThat(XmlUtil.toString(response.getDocument()), JUnitMatchers.containsString("<afi xmlns:prefix=\"urn:opendaylight:params:xml:ns:yang:controller:config:test:types\">prefix:test-identity1</afi>"));
+ assertThat(XmlUtil.toString(response.getDocument()), JUnitMatchers.containsString("<afi xmlns:prefix=\"urn:opendaylight:params:xml:ns:yang:controller:config:test:types\">prefix:test-identity2</afi>"));
+ assertThat(XmlUtil.toString(response.getDocument()), JUnitMatchers.containsString("<safi xmlns:prefix=\"urn:opendaylight:params:xml:ns:yang:controller:config:test:types\">prefix:test-identity2</safi>"));
+ assertThat(XmlUtil.toString(response.getDocument()), JUnitMatchers.containsString("<safi xmlns:prefix=\"urn:opendaylight:params:xml:ns:yang:controller:config:test:types\">prefix:test-identity1</safi>"));
} catch (Exception e) {
fail(Throwables.getStackTraceAsString(e));
import com.google.common.base.Optional;
import com.google.common.base.Predicate;
+import com.google.common.base.Strings;
import com.google.common.collect.Collections2;
import com.google.common.collect.Lists;
import com.google.common.collect.Maps;
+import java.io.IOException;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import javax.annotation.Nullable;
import org.opendaylight.controller.netconf.api.NetconfDocumentedException;
import org.opendaylight.controller.netconf.util.exception.MissingNameSpaceException;
import org.opendaylight.controller.netconf.util.exception.UnexpectedElementException;
import org.w3c.dom.Text;
import org.xml.sax.SAXException;
-import javax.annotation.Nullable;
-import java.io.IOException;
-import java.util.ArrayList;
-import java.util.Collections;
-import java.util.HashMap;
-import java.util.List;
-import java.util.Map;
-
public final class XmlElement {
private final Element element;
public void checkNamespaceAttribute(String expectedNamespace) throws UnexpectedNamespaceException, MissingNameSpaceException {
if (!getNamespaceAttribute().equals(expectedNamespace))
{
- throw new UnexpectedNamespaceException(String.format("Unexpected namespace %s for element %s, should be %s",
+ throw new UnexpectedNamespaceException(String.format("Unexpected namespace %s should be %s",
getNamespaceAttribute(),
expectedNamespace),
NetconfDocumentedException.ErrorType.application,
public void checkNamespace(String expectedNamespace) throws UnexpectedNamespaceException, MissingNameSpaceException {
if (!getNamespace().equals(expectedNamespace))
{
- throw new UnexpectedNamespaceException(String.format("Unexpected namespace %s for element %s, should be %s",
+ throw new UnexpectedNamespaceException(String.format("Unexpected namespace %s should be %s",
getNamespace(),
expectedNamespace),
NetconfDocumentedException.ErrorType.application,
}
public String getTextContent() throws NetconfDocumentedException {
- Node textChild = element.getFirstChild();
- if (null == textChild){
- throw new NetconfDocumentedException(String.format( "Child node expected, got null for " + getName() + " : " + element),
- NetconfDocumentedException.ErrorType.application,
- NetconfDocumentedException.ErrorTag.invalid_value,
- NetconfDocumentedException.ErrorSeverity.error);
+ NodeList childNodes = element.getChildNodes();
+ if (childNodes.getLength() == 0) {
+ return "";
}
- if (!(textChild instanceof Text)){
- throw new NetconfDocumentedException(String.format(getName() + " should contain text." +
- Text.class.getName() + " expected, got " + textChild),
- NetconfDocumentedException.ErrorType.application,
- NetconfDocumentedException.ErrorTag.invalid_value,
- NetconfDocumentedException.ErrorSeverity.error);
+ for(int i = 0; i < childNodes.getLength(); i++) {
+ Node textChild = childNodes.item(i);
+ if (textChild instanceof Text) {
+ String content = textChild.getTextContent();
+ return content.trim();
+ }
}
- String content = textChild.getTextContent();
- // Trim needed
- return content.trim();
+ throw new NetconfDocumentedException(getName() + " should contain text.",
+ NetconfDocumentedException.ErrorType.application,
+ NetconfDocumentedException.ErrorTag.invalid_value,
+ NetconfDocumentedException.ErrorSeverity.error
+ );
}
public String getNamespaceAttribute() throws MissingNameSpaceException {
return attribute;
}
- public String getNamespace() throws MissingNameSpaceException {
+ public Optional<String> getNamespaceOptionally() {
String namespaceURI = element.getNamespaceURI();
- if (namespaceURI == null || namespaceURI.equals("")){
+ if (Strings.isNullOrEmpty(namespaceURI)) {
+ return Optional.absent();
+ } else {
+ return Optional.of(namespaceURI);
+ }
+ }
+
+ public String getNamespace() throws MissingNameSpaceException {
+ Optional<String> namespaceURI = getNamespaceOptionally();
+ if (namespaceURI.isPresent() == false){
throw new MissingNameSpaceException(String.format("No namespace defined for %s", this),
NetconfDocumentedException.ErrorType.application,
NetconfDocumentedException.ErrorTag.operation_failed,
NetconfDocumentedException.ErrorSeverity.error);
}
- return namespaceURI;
+ return namespaceURI.get();
}
@Override
import com.google.common.base.Charsets;
import com.google.common.base.Optional;
-import org.w3c.dom.Document;
-import org.w3c.dom.Element;
-import org.w3c.dom.Node;
-import org.xml.sax.SAXException;
-
+import java.io.ByteArrayInputStream;
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.StringWriter;
import javax.xml.XMLConstants;
import javax.xml.namespace.QName;
import javax.xml.parsers.DocumentBuilder;
import javax.xml.validation.SchemaFactory;
import javax.xml.xpath.XPathExpression;
import javax.xml.xpath.XPathExpressionException;
-import java.io.ByteArrayInputStream;
-import java.io.File;
-import java.io.FileInputStream;
-import java.io.IOException;
-import java.io.InputStream;
-import java.io.StringWriter;
+import org.w3c.dom.Document;
+import org.w3c.dom.Element;
+import org.w3c.dom.Node;
+import org.xml.sax.SAXException;
public final class XmlUtil {
public static final String XMLNS_ATTRIBUTE_KEY = "xmlns";
- private static final String XMLNS_URI = "http://www.w3.org/2000/xmlns/";
+ public static final String XMLNS_URI = "http://www.w3.org/2000/xmlns/";
private static final DocumentBuilderFactory BUILDERFACTORY;
static {
return typeElement;
}
- public static Element createPrefixedTextElement(Document document, String qName, String prefix, String content, Optional<String> namespace) {
- return createTextElement(document, qName, createPrefixedValue(prefix, content), namespace);
+ public static Element createTextElementWithNamespacedContent(Document document, String qName, String prefix,
+ String namespace, String contentWithoutPrefix) {
+
+ String content = createPrefixedValue(XmlNetconfConstants.PREFIX, contentWithoutPrefix);
+ Element element = createTextElement(document, qName, content, Optional.<String>absent());
+ String prefixedNamespaceAttr = createPrefixedValue(XMLNS_ATTRIBUTE_KEY, prefix);
+ element.setAttributeNS(XMLNS_URI, prefixedNamespaceAttr, namespace);
+ return element;
}
public static String createPrefixedValue(String prefix, String value) {
if (portInterface.macInUse(singleton.getMacAddress())) {
throw new ResourceConflictException("MAC Address is in use.");
}
- Object[] instances = ServiceHelper.getGlobalInstances(INeutronPortAware.class, this, null);
- if (instances != null) {
- for (Object instance : instances) {
- INeutronPortAware service = (INeutronPortAware) instance;
- int status = service.canCreatePort(singleton);
- if (status < 200 || status > 299) {
- return Response.status(status).build();
- }
- }
- }
/*
* if fixed IPs are specified, each one has to have an existing subnet ID
* that is in the same scoping network as the port. In addition, if an IP
}
}
+ Object[] instances = ServiceHelper.getGlobalInstances(INeutronPortAware.class, this, null);
+ if (instances != null) {
+ for (Object instance : instances) {
+ INeutronPortAware service = (INeutronPortAware) instance;
+ int status = service.canCreatePort(singleton);
+ if (status < 200 || status > 299) {
+ return Response.status(status).build();
+ }
+ }
+ }
+
+
// add the port to the cache
portInterface.addPort(singleton);
if (instances != null) {
if (portInterface.macInUse(test.getMacAddress())) {
throw new ResourceConflictException("MAC address in use");
}
- if (instances != null) {
- for (Object instance : instances) {
- INeutronPortAware service = (INeutronPortAware) instance;
- int status = service.canCreatePort(test);
- if (status < 200 || status > 299) {
- return Response.status(status).build();
- }
- }
- }
+
/*
* if fixed IPs are specified, each one has to have an existing subnet ID
* that is in the same scoping network as the port. In addition, if an IP
}
}
}
+ if (instances != null) {
+ for (Object instance : instances) {
+ INeutronPortAware service = (INeutronPortAware) instance;
+ int status = service.canCreatePort(test);
+ if (status < 200 || status > 299) {
+ return Response.status(status).build();
+ }
+ }
+ }
}
//once everything has passed, then we can add to the cache