out/
.externalToolBuilders
maven-eclipse.xml
+.DS_STORE
+.metadata
<aopalliance.version>1.0.0</aopalliance.version>
<appauth.version>0.4.2-SNAPSHOT</appauth.version>
<!-- Controller Modules Versions -->
- <arphandler.version>0.5.2-SNAPSHOT</arphandler.version>
<aries.util.version>1.1.0</aries.util.version>
+ <arphandler.version>0.5.2-SNAPSHOT</arphandler.version>
<asm.version>4.1</asm.version>
<!-- Plugin Versions -->
<bouncycastle.version>1.50</bouncycastle.version>
<artifactId>netconf-netty-util</artifactId>
<version>${netconf.version}</version>
</dependency>
- <dependency>
- <groupId>org.opendaylight.controller</groupId>
- <artifactId>netconf-netty-util</artifactId>
- <version>${netconf.version}</version>
- <type>test-jar</type>
- </dependency>
<dependency>
<groupId>ch.qos.logback</groupId>
<artifactId>logback-classic</artifactId>
<artifactId>netconf-monitoring</artifactId>
<version>${netconf.version}</version>
</dependency>
+ <dependency>
+ <groupId>org.opendaylight.controller</groupId>
+ <artifactId>netconf-netty-util</artifactId>
+ <version>${netconf.version}</version>
+ <type>test-jar</type>
+ </dependency>
<dependency>
<groupId>org.opendaylight.controller</groupId>
<artifactId>netconf-ssh</artifactId>
<artifactId>concepts</artifactId>
<version>${yangtools.version}</version>
</dependency>
+ <dependency>
+ <groupId>org.opendaylight.yangtools</groupId>
+ <artifactId>object-cache-api</artifactId>
+ <version>${yangtools.version}</version>
+ </dependency>
+ <dependency>
+ <groupId>org.opendaylight.yangtools</groupId>
+ <artifactId>object-cache-guava</artifactId>
+ <version>${yangtools.version}</version>
+ </dependency>
<dependency>
<groupId>org.opendaylight.yangtools</groupId>
<artifactId>restconf-client-api</artifactId>
<version>${karaf.version}</version>
<type>kar</type>
</dependency>
- <dependency>
- <groupId>org.opendaylight.controller</groupId>
- <artifactId>config-features</artifactId>
- <version>${config.version}</version>
- <classifier>features</classifier>
- <type>xml</type>
- <scope>runtime</scope>
- </dependency>
<!-- scope is runtime so the feature repo is listed in the features
service config file, and features may be installed using the
karaf-maven-plugin configuration -->
<type>kar</type>
<scope>runtime</scope>
</dependency>
+ <dependency>
+ <groupId>org.opendaylight.controller</groupId>
+ <artifactId>config-features</artifactId>
+ <version>${config.version}</version>
+ <classifier>features</classifier>
+ <type>xml</type>
+ <scope>runtime</scope>
+ </dependency>
<!--<dependency>
<groupId>org.opendaylight.controller</groupId>
<artifactId>base-features</artifactId>
<groupId>org.opendaylight.yangtools</groupId>
<artifactId>concepts</artifactId>
</dependency>
+ <dependency>
+ <groupId>org.opendaylight.yangtools</groupId>
+ <artifactId>object-cache-api</artifactId>
+ </dependency>
+ <dependency>
+ <groupId>org.opendaylight.yangtools</groupId>
+ <artifactId>object-cache-guava</artifactId>
+ </dependency>
<dependency>
<groupId>org.opendaylight.yangtools</groupId>
<artifactId>restconf-client-api</artifactId>
<plugin>
<groupId>org.apache.felix</groupId>
<artifactId>maven-bundle-plugin</artifactId>
- <version>${bundle.plugin.version}</version>
<extensions>true</extensions>
<configuration>
<instructions>
import java.util.Dictionary
import java.util.Hashtable
import org.apache.felix.dm.Component
+import org.opendaylight.controller.clustering.services.IClusterGlobalServices
import org.opendaylight.controller.sal.binding.api.BindingAwareBroker
import org.opendaylight.controller.sal.binding.api.BindingAwareBroker.ConsumerContext
-import org.opendaylight.controller.sal.binding.api.BindingAwareConsumer
+import org.opendaylight.controller.sal.binding.api.BindingAwareBroker.ProviderContext
+import org.opendaylight.controller.sal.binding.api.BindingAwareProvider
import org.opendaylight.controller.sal.binding.api.NotificationService
import org.opendaylight.controller.sal.binding.api.data.DataBrokerService
import org.opendaylight.controller.sal.binding.api.data.DataProviderService
+import org.opendaylight.controller.sal.compatibility.adsal.DataPacketServiceAdapter
import org.opendaylight.controller.sal.compatibility.topology.TopologyAdapter
+import org.opendaylight.controller.sal.compatibility.topology.TopologyProvider
import org.opendaylight.controller.sal.core.ComponentActivatorAbstractBase
import org.opendaylight.controller.sal.core.Node
import org.opendaylight.controller.sal.core.NodeConnector
import org.opendaylight.controller.sal.flowprogrammer.IPluginOutFlowProgrammerService
import org.opendaylight.controller.sal.inventory.IPluginInInventoryService
import org.opendaylight.controller.sal.inventory.IPluginOutInventoryService
+import org.opendaylight.controller.sal.packet.IPluginInDataPacketService
import org.opendaylight.controller.sal.packet.IPluginOutDataPacketService
import org.opendaylight.controller.sal.reader.IPluginInReadService
import org.opendaylight.controller.sal.reader.IPluginOutReadService
import org.opendaylight.controller.sal.utils.GlobalConstants
import org.opendaylight.controller.sal.utils.INodeConnectorFactory
import org.opendaylight.controller.sal.utils.INodeFactory
-import org.opendaylight.controller.clustering.services.IClusterGlobalServices
-import org.opendaylight.controller.sal.packet.IPluginInDataPacketService
-
import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.service.rev130819.SalFlowService
-import org.opendaylight.yang.gen.v1.urn.opendaylight.packet.service.rev130709.PacketProcessingService
import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.statistics.rev130819.OpendaylightFlowStatisticsService
import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.table.statistics.rev131215.OpendaylightFlowTableStatisticsService
import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.topology.discovery.rev130819.FlowTopologyDiscoveryService
+import org.opendaylight.yang.gen.v1.urn.opendaylight.packet.service.rev130709.PacketProcessingService
import org.opendaylight.yang.gen.v1.urn.opendaylight.port.statistics.rev131214.OpendaylightPortStatisticsService
import org.osgi.framework.BundleContext
import static org.opendaylight.controller.sal.compatibility.NodeMapping.*
-import org.opendaylight.controller.sal.compatibility.topology.TopologyProvider
-import org.opendaylight.controller.sal.compatibility.adsal.DataPacketServiceAdapter
-import org.opendaylight.controller.sal.binding.api.BindingAwareProvider
-import org.opendaylight.controller.sal.binding.api.BindingAwareBroker.ProviderContext
class ComponentActivator extends ComponentActivatorAbstractBase {
import java.util.ArrayList
import java.util.Collections
import java.util.List
+import java.util.Map
import java.util.Set
-import java.util.ArrayList;
-import java.util.concurrent.locks.ReentrantLock;
-import java.util.concurrent.locks.Lock;
-import java.util.concurrent.CopyOnWriteArrayList;
+import java.util.concurrent.ConcurrentHashMap
+import java.util.concurrent.CopyOnWriteArrayList
+import java.util.concurrent.locks.Lock
+import java.util.concurrent.locks.ReentrantLock
+import org.opendaylight.controller.md.sal.binding.util.TypeSafeDataReader
import org.opendaylight.controller.sal.binding.api.data.DataBrokerService
import org.opendaylight.controller.sal.binding.api.data.DataProviderService
import org.opendaylight.controller.sal.core.Edge
import static extension org.opendaylight.controller.sal.common.util.Arguments.*
import static extension org.opendaylight.controller.sal.compatibility.NodeMapping.*
-import org.opendaylight.controller.md.sal.binding.util.TypeSafeDataReader
-import java.util.concurrent.ConcurrentHashMap
-import java.util.Map
-import java.util.HashMap
class InventoryAndReadAdapter implements IPluginInReadService,
IPluginInInventoryService,
package org.opendaylight.controller.sal.compatibility.topology
import com.google.common.collect.FluentIterable
-import java.util.Collections
import java.util.List
import java.util.concurrent.CopyOnWriteArrayList
+import org.opendaylight.controller.md.sal.binding.util.TypeSafeDataReader
import org.opendaylight.controller.sal.core.ConstructionException
import org.opendaylight.controller.sal.core.Edge
import org.opendaylight.controller.sal.core.Node
import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.TpId
import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.Topology
import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.topology.Link
+import org.opendaylight.yangtools.yang.binding.InstanceIdentifier
+import org.slf4j.LoggerFactory
import static com.google.common.base.Preconditions.*
+
import static extension org.opendaylight.controller.sal.compatibility.NodeMapping.*
-import org.opendaylight.controller.md.sal.binding.util.TypeSafeDataReader
-import org.opendaylight.yangtools.yang.binding.InstanceIdentifier
-import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.FlowCapableNodeConnector
-import org.slf4j.LoggerFactory
class TopologyMapping {
private static val LOG = LoggerFactory.getLogger(TopologyMapping);
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertTrue;
-import static org.opendaylight.controller.sal.compatibility.ProtocolConstants.ETHERNET_ARP;
import static org.opendaylight.controller.sal.compatibility.ProtocolConstants.CRUDP;
+import static org.opendaylight.controller.sal.compatibility.ProtocolConstants.ETHERNET_ARP;
import static org.opendaylight.controller.sal.compatibility.ProtocolConstants.TCP;
import static org.opendaylight.controller.sal.compatibility.ProtocolConstants.UDP;
import java.util.List;
import org.junit.Test;
-import org.opendaylight.controller.sal.action.*;
+import org.opendaylight.controller.sal.action.Action;
+import org.opendaylight.controller.sal.action.Flood;
+import org.opendaylight.controller.sal.action.FloodAll;
+import org.opendaylight.controller.sal.action.HwPath;
+import org.opendaylight.controller.sal.action.Loopback;
+import org.opendaylight.controller.sal.action.PopVlan;
+import org.opendaylight.controller.sal.action.PushVlan;
+import org.opendaylight.controller.sal.action.SetDlDst;
+import org.opendaylight.controller.sal.action.SetDlSrc;
+import org.opendaylight.controller.sal.action.SetDlType;
+import org.opendaylight.controller.sal.action.SetNextHop;
+import org.opendaylight.controller.sal.action.SetNwDst;
+import org.opendaylight.controller.sal.action.SetNwSrc;
+import org.opendaylight.controller.sal.action.SetNwTos;
+import org.opendaylight.controller.sal.action.SetTpDst;
+import org.opendaylight.controller.sal.action.SetTpSrc;
+import org.opendaylight.controller.sal.action.SetVlanCfi;
+import org.opendaylight.controller.sal.action.SetVlanId;
+import org.opendaylight.controller.sal.action.SetVlanPcp;
+import org.opendaylight.controller.sal.action.SwPath;
import org.opendaylight.controller.sal.compatibility.MDFlowMapping;
import org.opendaylight.controller.sal.compatibility.ToSalConversionsUtils;
import org.opendaylight.controller.sal.flowprogrammer.Flow;
import org.opendaylight.controller.sal.match.Match;
import org.opendaylight.controller.sal.match.MatchType;
-import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.service.rev130819.NodeFlow;
-import org.opendaylight.yang.gen.v1.urn.opendaylight.action.types.rev131112.action.action.*;
-import org.opendaylight.yang.gen.v1.urn.opendaylight.action.types.rev131112.action.action.pop.vlan.action._case.PopVlanAction;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.action.types.rev131112.action.action.FloodActionCase;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.action.types.rev131112.action.action.FloodAllActionCase;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.action.types.rev131112.action.action.HwPathActionCase;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.action.types.rev131112.action.action.LoopbackActionCase;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.action.types.rev131112.action.action.PopVlanActionCase;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.action.types.rev131112.action.action.PushVlanActionCase;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.action.types.rev131112.action.action.SetDlDstActionCase;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.action.types.rev131112.action.action.SetDlSrcActionCase;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.action.types.rev131112.action.action.SetDlTypeActionCase;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.action.types.rev131112.action.action.SetNextHopActionCase;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.action.types.rev131112.action.action.SetNwDstActionCase;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.action.types.rev131112.action.action.SetNwSrcActionCase;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.action.types.rev131112.action.action.SetNwTosActionCase;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.action.types.rev131112.action.action.SetTpDstActionCase;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.action.types.rev131112.action.action.SetTpSrcActionCase;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.action.types.rev131112.action.action.SetVlanCfiActionCase;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.action.types.rev131112.action.action.SetVlanIdActionCase;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.action.types.rev131112.action.action.SetVlanPcpActionCase;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.action.types.rev131112.action.action.SwPathActionCase;
import org.opendaylight.yang.gen.v1.urn.opendaylight.action.types.rev131112.address.Address;
import org.opendaylight.yang.gen.v1.urn.opendaylight.action.types.rev131112.address.address.Ipv4;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.service.rev130819.NodeFlow;
import org.opendaylight.yang.gen.v1.urn.opendaylight.model.match.types.rev131026.match.Layer3Match;
import org.opendaylight.yang.gen.v1.urn.opendaylight.model.match.types.rev131026.match.Layer4Match;
import org.opendaylight.yang.gen.v1.urn.opendaylight.model.match.types.rev131026.match.layer._3.match.ArpMatch;
if (layer4Match instanceof SctpMatch) {
assertEquals("Sctp source port is incorrect.", 0xffff, (int) ((SctpMatch) layer4Match)
.getSctpSourcePort().getValue());
- assertEquals("Sctp dest port is incorrect.", (int) 0xfffe, (int) ((SctpMatch) layer4Match)
+ assertEquals("Sctp dest port is incorrect.", 0xfffe, (int) ((SctpMatch) layer4Match)
.getSctpDestinationPort().getValue());
sctpFound = true;
}
assertEquals("Wrong protocol", TCP, match.getIpMatch().getIpProtocol().byteValue());
layer4Match = match.getLayer4Match();
if (layer4Match instanceof TcpMatch) {
- assertEquals("Tcp source port is incorrect.", (int) 0xabcd, (int) ((TcpMatch) layer4Match)
+ assertEquals("Tcp source port is incorrect.", 0xabcd, (int) ((TcpMatch) layer4Match)
.getTcpSourcePort().getValue());
- assertEquals("Tcp dest port is incorrect.", (int) 0xdcba, (int) ((TcpMatch) layer4Match)
+ assertEquals("Tcp dest port is incorrect.", 0xdcba, (int) ((TcpMatch) layer4Match)
.getTcpDestinationPort().getValue());
sctpFound = true;
}
assertEquals("Wrong protocol", UDP, match.getIpMatch().getIpProtocol().byteValue());
layer4Match = match.getLayer4Match();
if (layer4Match instanceof UdpMatch) {
- assertEquals("Udp source port is incorrect.", (int) 0xcdef, (int) ((UdpMatch) layer4Match)
+ assertEquals("Udp source port is incorrect.", 0xcdef, (int) ((UdpMatch) layer4Match)
.getUdpSourcePort().getValue());
- assertEquals("Udp dest port is incorrect.", (int) 0xfedc, (int) ((UdpMatch) layer4Match)
+ assertEquals("Udp dest port is incorrect.", 0xfedc, (int) ((UdpMatch) layer4Match)
.getUdpDestinationPort().getValue());
sctpFound = true;
}
assertEquals("Wrong value of vlad ID in PushVlanAction.", (Integer) 4095,
((PushVlanActionCase) innerAction).getPushVlanAction().getVlanId().getValue());
} else if (innerAction instanceof SetDlDstActionCase) {
- assertEquals("Wrong MAC destination address in SetDlDstAction.", "ff:ee:dd:cc:bb:aa",
+ assertEquals("Wrong MAC destination address in SetDlDstAction.", "ff:ee:dd:cc:bb:aa",
((SetDlDstActionCase) innerAction).getSetDlDstAction().getAddress().getValue());
} else if (innerAction instanceof SetDlSrcActionCase) {
- assertEquals("Wrong MAC source address in SetDlDstAction.", "ff:ee:dd:cc:bb:aa",
+ assertEquals("Wrong MAC source address in SetDlDstAction.", "ff:ee:dd:cc:bb:aa",
((SetDlSrcActionCase) innerAction).getSetDlSrcAction().getAddress().getValue());
} else if (innerAction instanceof SetDlTypeActionCase) {
- assertEquals("Wrong data link type in SetDlTypeAction.", (long) 513,
+ assertEquals("Wrong data link type in SetDlTypeAction.", 513,
(long) ((SetDlTypeActionCase) innerAction).getSetDlTypeAction().getDlType().getValue());
} else if (innerAction instanceof SetNextHopActionCase) {
Address address = ((SetNextHopActionCase) innerAction).getSetNextHopAction().getAddress();
import java.util.LinkedList;
import java.util.List;
import java.util.Map.Entry;
-import java.util.concurrent.Callable;
import org.opendaylight.controller.md.sal.common.impl.util.compat.DataNormalizationException;
import org.opendaylight.controller.md.sal.common.impl.util.compat.DataNormalizationOperation;
import org.opendaylight.controller.md.sal.common.impl.util.compat.DataNormalizer;
-import org.opendaylight.yangtools.concepts.util.ClassLoaderUtils;
import org.opendaylight.yangtools.yang.binding.Augmentation;
import org.opendaylight.yangtools.yang.binding.DataContainer;
import org.opendaylight.yangtools.yang.binding.DataObject;
import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
import org.opendaylight.yangtools.yang.binding.InstanceIdentifier.Item;
import org.opendaylight.yangtools.yang.binding.util.BindingReflections;
+import org.opendaylight.yangtools.yang.binding.util.ClassLoaderUtils;
import org.opendaylight.yangtools.yang.common.QName;
import org.opendaylight.yangtools.yang.data.api.CompositeNode;
import org.opendaylight.yangtools.yang.data.api.InstanceIdentifier.AugmentationIdentifier;
import org.slf4j.LoggerFactory;
import com.google.common.base.Optional;
+import com.google.common.base.Supplier;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.Iterables;
} else if (List.class.isAssignableFrom(returnType)) {
try {
return ClassLoaderUtils.withClassLoader(method.getDeclaringClass().getClassLoader(),
- new Callable<Class>() {
+ new Supplier<Class>() {
@Override
- public Class call() {
+ public Class get() {
Type listResult = ClassLoaderUtils.getFirstGenericParameter(method
.getGenericReturnType());
if (listResult instanceof Class
}
private static class BackwardsCompatibleConfigurationDataChangeInvoker implements BindingDataChangeListener, Delegator<DataChangeListener> {
-
-
- @SuppressWarnings("rawtypes")
private final org.opendaylight.controller.md.sal.common.api.data.DataChangeListener<?,?> delegate;
public BackwardsCompatibleConfigurationDataChangeInvoker(final DataChangeListener listener) {
import org.opendaylight.controller.sal.core.api.notify.NotificationPublishService;
import org.opendaylight.yangtools.concepts.ListenerRegistration;
import org.opendaylight.yangtools.concepts.Registration;
-import org.opendaylight.yangtools.concepts.util.ClassLoaderUtils;
import org.opendaylight.yangtools.yang.binding.Augmentable;
import org.opendaylight.yangtools.yang.binding.Augmentation;
import org.opendaylight.yangtools.yang.binding.BaseIdentity;
import org.opendaylight.yangtools.yang.binding.Notification;
import org.opendaylight.yangtools.yang.binding.RpcService;
import org.opendaylight.yangtools.yang.binding.util.BindingReflections;
+import org.opendaylight.yangtools.yang.binding.util.ClassLoaderUtils;
import org.opendaylight.yangtools.yang.common.QName;
import org.opendaylight.yangtools.yang.common.RpcError;
import org.opendaylight.yangtools.yang.common.RpcResult;
import org.opendaylight.yangtools.yang.data.api.CompositeNode;
-import org.opendaylight.yangtools.yang.data.api.Node;
-import org.opendaylight.yangtools.yang.data.impl.ImmutableCompositeNode;
import org.opendaylight.yangtools.yang.data.impl.codec.BindingIndependentMappingService;
import org.opendaylight.yangtools.yang.data.impl.codec.DeserializationException;
import org.slf4j.Logger;
import com.google.common.base.Function;
import com.google.common.base.Optional;
import com.google.common.collect.FluentIterable;
-import com.google.common.collect.ImmutableList;
import com.google.common.collect.ImmutableSet;
import com.google.common.collect.ImmutableSet.Builder;
import com.google.common.util.concurrent.Futures;
}
}
checkState(targetMethod != null, "Rpc method not found");
- Optional<Class<?>> outputClass = BindingReflections.resolveRpcOutputClass(targetMethod);
- Optional<Class<? extends DataContainer>> inputClass = BindingReflections
- .resolveRpcInputClass(targetMethod);
-
- RpcInvocationStrategy strategy = null;
- if (outputClass.isPresent()) {
- if (inputClass.isPresent()) {
- strategy = new DefaultInvocationStrategy(rpc, targetMethod, outputClass.get(), inputClass
- .get());
- } else {
- strategy = new NoInputInvocationStrategy(rpc, targetMethod, outputClass.get());
- }
- } else if (inputClass.isPresent()) {
- strategy = new NoOutputInvocationStrategy(rpc, targetMethod, inputClass.get());
- } else {
- strategy = new NoInputNoOutputInvocationStrategy(rpc, targetMethod);
- }
- return strategy;
+ return new RpcInvocationStrategy(rpc,targetMethod, mappingService, biRpcRegistry);
}
});
}
}
- private abstract class RpcInvocationStrategy {
-
- protected final Method targetMethod;
- protected final QName rpc;
-
- public RpcInvocationStrategy(final QName rpc, final Method targetMethod) {
- this.targetMethod = targetMethod;
- this.rpc = rpc;
- }
-
- public abstract Future<RpcResult<?>> forwardToDomBroker(DataObject input);
-
- public abstract RpcResult<CompositeNode> uncheckedInvoke(RpcService rpcService, CompositeNode domInput)
- throws Exception;
-
- public RpcResult<CompositeNode> invokeOn(final RpcService rpcService, final CompositeNode domInput)
- throws Exception {
- return uncheckedInvoke(rpcService, domInput);
- }
- }
-
- private class DefaultInvocationStrategy extends RpcInvocationStrategy {
-
- @SuppressWarnings("rawtypes")
- private final WeakReference<Class> inputClass;
-
- @SuppressWarnings("rawtypes")
- private final WeakReference<Class> outputClass;
-
- @SuppressWarnings({ "rawtypes", "unchecked" })
- public DefaultInvocationStrategy(final QName rpc, final Method targetMethod, final Class<?> outputClass,
- final Class<? extends DataContainer> inputClass) {
- super(rpc, targetMethod);
- this.outputClass = new WeakReference(outputClass);
- this.inputClass = new WeakReference(inputClass);
- }
-
- @SuppressWarnings("unchecked")
- @Override
- public RpcResult<CompositeNode> uncheckedInvoke(final RpcService rpcService, final CompositeNode domInput)
- throws Exception {
- DataContainer bindingInput = mappingService.dataObjectFromDataDom(inputClass.get(), domInput);
- Future<RpcResult<?>> futureResult = (Future<RpcResult<?>>) targetMethod.invoke(rpcService, bindingInput);
- if (futureResult == null) {
- return Rpcs.getRpcResult(false);
- }
- RpcResult<?> bindingResult = futureResult.get();
- final Object resultObj = bindingResult.getResult();
- if (resultObj instanceof DataObject) {
- final CompositeNode output = mappingService.toDataDom((DataObject) resultObj);
- return Rpcs.getRpcResult(true, output, Collections.<RpcError> emptySet());
- }
- return Rpcs.getRpcResult(true);
- }
-
- @Override
- public ListenableFuture<RpcResult<?>> forwardToDomBroker(final DataObject input) {
- if (biRpcRegistry == null) {
- return Futures.<RpcResult<?>> immediateFuture(Rpcs.getRpcResult(false));
- }
-
- CompositeNode xml = mappingService.toDataDom(input);
- CompositeNode wrappedXml = ImmutableCompositeNode.create(rpc, ImmutableList.<Node<?>> of(xml));
-
- return Futures.transform(biRpcRegistry.invokeRpc(rpc, wrappedXml),
- new Function<RpcResult<CompositeNode>, RpcResult<?>>() {
- @Override
- public RpcResult<?> apply(final RpcResult<CompositeNode> input) {
- Object baResultValue = null;
- if (input.getResult() != null) {
- baResultValue = mappingService.dataObjectFromDataDom(outputClass.get(),
- input.getResult());
- }
- return Rpcs.getRpcResult(input.isSuccessful(), baResultValue, input.getErrors());
- }
- });
- }
- }
-
- private class NoInputInvocationStrategy extends RpcInvocationStrategy {
-
- @SuppressWarnings("rawtypes")
- private final WeakReference<Class> outputClass;
-
- @SuppressWarnings({ "rawtypes", "unchecked" })
- public NoInputInvocationStrategy(final QName rpc, final Method targetMethod, final Class<?> outputClass) {
- super(rpc, targetMethod);
- this.outputClass = new WeakReference(outputClass);
- }
-
- @SuppressWarnings("unchecked")
- @Override
- public RpcResult<CompositeNode> uncheckedInvoke(final RpcService rpcService, final CompositeNode domInput)
- throws Exception {
- Future<RpcResult<?>> futureResult = (Future<RpcResult<?>>) targetMethod.invoke(rpcService);
- if (futureResult == null) {
- return Rpcs.getRpcResult(false);
- }
- RpcResult<?> bindingResult = futureResult.get();
- final Object resultObj = bindingResult.getResult();
- if (resultObj instanceof DataObject) {
- final CompositeNode output = mappingService.toDataDom((DataObject) resultObj);
- return Rpcs.getRpcResult(true, output, Collections.<RpcError> emptySet());
- }
- return Rpcs.getRpcResult(true);
- }
-
- @Override
- public Future<RpcResult<?>> forwardToDomBroker(final DataObject input) {
- if (biRpcRegistry != null) {
- CompositeNode xml = mappingService.toDataDom(input);
- CompositeNode wrappedXml = ImmutableCompositeNode.create(rpc, ImmutableList.<Node<?>> of(xml));
- return Futures.transform(biRpcRegistry.invokeRpc(rpc, wrappedXml),
- new Function<RpcResult<CompositeNode>, RpcResult<?>>() {
- @Override
- public RpcResult<?> apply(final RpcResult<CompositeNode> input) {
- Object baResultValue = null;
- if (input.getResult() != null) {
- baResultValue = mappingService.dataObjectFromDataDom(outputClass.get(),
- input.getResult());
- }
- return Rpcs.getRpcResult(input.isSuccessful(), baResultValue, input.getErrors());
- }
- });
- } else {
- return Futures.<RpcResult<?>> immediateFuture(Rpcs.getRpcResult(false));
- }
- }
- }
-
- private class NoInputNoOutputInvocationStrategy extends RpcInvocationStrategy {
-
- public NoInputNoOutputInvocationStrategy(final QName rpc, final Method targetMethod) {
- super(rpc, targetMethod);
- }
-
- @Override
- public RpcResult<CompositeNode> uncheckedInvoke(final RpcService rpcService, final CompositeNode domInput)
- throws Exception {
- @SuppressWarnings("unchecked")
- Future<RpcResult<Void>> result = (Future<RpcResult<Void>>) targetMethod.invoke(rpcService);
- RpcResult<Void> bindingResult = result.get();
- return Rpcs.getRpcResult(bindingResult.isSuccessful(), bindingResult.getErrors());
- }
-
- @Override
- public Future<RpcResult<?>> forwardToDomBroker(final DataObject input) {
- return Futures.immediateFuture(null);
- }
- }
-
- private class NoOutputInvocationStrategy extends RpcInvocationStrategy {
-
- @SuppressWarnings("rawtypes")
- private final WeakReference<Class> inputClass;
-
- @SuppressWarnings({ "rawtypes", "unchecked" })
- public NoOutputInvocationStrategy(final QName rpc, final Method targetMethod,
- final Class<? extends DataContainer> inputClass) {
- super(rpc, targetMethod);
- this.inputClass = new WeakReference(inputClass);
- }
-
- @Override
- public RpcResult<CompositeNode> uncheckedInvoke(final RpcService rpcService, final CompositeNode domInput)
- throws Exception {
- DataContainer bindingInput = mappingService.dataObjectFromDataDom(inputClass.get(), domInput);
- Future<RpcResult<?>> result = (Future<RpcResult<?>>) targetMethod.invoke(rpcService, bindingInput);
- if (result == null) {
- return Rpcs.getRpcResult(false);
- }
- RpcResult<?> bindingResult = result.get();
- return Rpcs.getRpcResult(true);
- }
-
- @Override
- public ListenableFuture<RpcResult<?>> forwardToDomBroker(final DataObject input) {
- if (biRpcRegistry == null) {
- return Futures.<RpcResult<?>> immediateFuture(Rpcs.getRpcResult(false));
- }
-
- CompositeNode xml = mappingService.toDataDom(input);
- CompositeNode wrappedXml = ImmutableCompositeNode.create(rpc, ImmutableList.<Node<?>> of(xml));
-
- return Futures.transform(biRpcRegistry.invokeRpc(rpc, wrappedXml),
- new Function<RpcResult<CompositeNode>, RpcResult<?>>() {
- @Override
- public RpcResult<?> apply(final RpcResult<CompositeNode> input) {
- return Rpcs.<Void> getRpcResult(input.isSuccessful(), null, input.getErrors());
- }
- });
- }
- }
-
public boolean isRpcForwarding() {
return rpcForwarding;
}
--- /dev/null
+/*
+ ** Copyright (c) 2014 Brocade Communications 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.sal.binding.impl.connect.dom;
+
+import java.lang.ref.WeakReference;
+import java.lang.reflect.Method;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.concurrent.Future;
+
+import org.opendaylight.controller.sal.common.util.Rpcs;
+import org.opendaylight.controller.sal.core.api.RpcProvisionRegistry;
+import org.opendaylight.yangtools.yang.binding.DataContainer;
+import org.opendaylight.yangtools.yang.binding.DataObject;
+import org.opendaylight.yangtools.yang.binding.RpcService;
+import org.opendaylight.yangtools.yang.binding.util.BindingReflections;
+import org.opendaylight.yangtools.yang.common.QName;
+import org.opendaylight.yangtools.yang.common.RpcError;
+import org.opendaylight.yangtools.yang.common.RpcResult;
+import org.opendaylight.yangtools.yang.data.api.CompositeNode;
+import org.opendaylight.yangtools.yang.data.api.Node;
+import org.opendaylight.yangtools.yang.data.impl.ImmutableCompositeNode;
+import org.opendaylight.yangtools.yang.data.impl.codec.BindingIndependentMappingService;
+
+import com.google.common.base.Function;
+import com.google.common.base.Optional;
+import com.google.common.collect.ImmutableList;
+import com.google.common.util.concurrent.Futures;
+import com.google.common.util.concurrent.ListenableFuture;
+
+/*
+ * RPC's can have both input, output, one or the other, or neither.
+ *
+ * This class handles the permutations and provides two means of invocation:
+ * 1. forwardToDomBroker
+ * 2.
+ *
+ * Weak References to the input and output classes are used to allow these classes to
+ * be from another OSGi bundle/class loader which may come and go.
+ *
+ */
+public class RpcInvocationStrategy {
+
+ private final BindingIndependentMappingService mappingService;
+ private final RpcProvisionRegistry biRpcRegistry;
+ protected final Method targetMethod;
+ protected final QName rpc;
+
+ @SuppressWarnings("rawtypes")
+ private final WeakReference<Class> inputClass;
+
+ @SuppressWarnings("rawtypes")
+ private final WeakReference<Class> outputClass;
+
+ @SuppressWarnings({ "rawtypes" })
+ public RpcInvocationStrategy(final QName rpc,
+ final Method targetMethod,
+ final BindingIndependentMappingService mappingService,
+ final RpcProvisionRegistry biRpcRegistry ) {
+
+ this.targetMethod = targetMethod;
+ this.rpc = rpc;
+
+ Optional<Class<?>> outputClassOption = BindingReflections.resolveRpcOutputClass(targetMethod);
+ Optional<Class<? extends DataContainer>> inputClassOption = BindingReflections.resolveRpcInputClass(targetMethod);
+
+ if ( outputClassOption != null && outputClassOption.isPresent() ) {
+ this.outputClass = new WeakReference(outputClassOption.get() ) ;
+ } else {
+ this.outputClass = null ;
+ }
+ if ( inputClassOption != null && inputClassOption.isPresent() ) {
+ this.inputClass = new WeakReference(inputClassOption.get() ) ;
+ } else {
+ this.inputClass = null ;
+ }
+
+ this.mappingService = mappingService;
+ this.biRpcRegistry = biRpcRegistry;
+ }
+
+ @SuppressWarnings({ "unchecked" })
+ public ListenableFuture<RpcResult<?>> forwardToDomBroker(final DataObject input) {
+
+ if(biRpcRegistry == null) {
+ return Futures.<RpcResult<?>> immediateFuture(Rpcs.getRpcResult(false));
+ }
+
+ CompositeNode inputXml = null;
+ if( input != null ) {
+ CompositeNode xml = mappingService.toDataDom(input);
+ inputXml = ImmutableCompositeNode.create(rpc, ImmutableList.<Node<?>> of(xml));
+ } else {
+ inputXml = ImmutableCompositeNode.create( rpc, Collections.<Node<?>>emptyList() );
+ }
+
+ Function<RpcResult<CompositeNode>, RpcResult<?>> transformationFunction =
+ new Function<RpcResult<CompositeNode>, RpcResult<?>>() {
+ @Override
+ public RpcResult<?> apply(RpcResult<CompositeNode> result) {
+
+ Object output = null;
+
+ if( getOutputClass() != null ) {
+ if (result.getResult() != null) {
+ output = mappingService.dataObjectFromDataDom(getOutputClass().get(),
+ result.getResult());
+ }
+ }
+
+ return Rpcs.getRpcResult(result.isSuccessful(), output, result.getErrors());
+ }
+ };
+
+ return Futures.transform(biRpcRegistry.invokeRpc(rpc, inputXml), transformationFunction);
+ }
+
+ @SuppressWarnings("unchecked")
+ private RpcResult<CompositeNode> uncheckedInvoke(final RpcService rpcService, final CompositeNode domInput) throws Exception {
+
+ Future<RpcResult<?>> futureResult = null;
+
+ if( inputClass != null ){
+ DataContainer bindingInput = mappingService.dataObjectFromDataDom(inputClass.get(), domInput);
+ futureResult = (Future<RpcResult<?>>) targetMethod.invoke(rpcService, bindingInput);
+
+ } else {
+ futureResult = (Future<RpcResult<?>>) targetMethod.invoke(rpcService);
+ }
+
+ if (futureResult == null) {
+ return Rpcs.getRpcResult(false);
+ }
+
+ RpcResult<?> bindingResult = futureResult.get();
+
+ Collection<RpcError> errors = bindingResult.getErrors();
+ if( errors == null ) {
+ errors = Collections.<RpcError>emptySet();
+ }
+
+ final Object resultObj = bindingResult.getResult();
+ CompositeNode output = null;
+ if (resultObj instanceof DataObject) {
+ output = mappingService.toDataDom((DataObject)resultObj);
+ }
+ return Rpcs.getRpcResult( bindingResult.isSuccessful(), output, errors);
+ }
+
+ public RpcResult<CompositeNode> invokeOn(final RpcService rpcService, final CompositeNode domInput) throws Exception {
+ return uncheckedInvoke(rpcService, domInput);
+ }
+
+ @SuppressWarnings("rawtypes")
+ public WeakReference<Class> getOutputClass() {
+ return outputClass;
+ }
+}
--- /dev/null
+/*
+* Copyright (c) 2014 Brocade Communications 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.sal.binding.impl.connect.dom;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotNull;
+import static org.mockito.Matchers.any;
+import static org.mockito.Matchers.eq;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.when;
+
+import java.net.URI;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.Date;
+import java.util.concurrent.ExecutionException;
+import java.util.concurrent.Future;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.mockito.Mock;
+import org.mockito.MockitoAnnotations;
+import org.opendaylight.controller.sal.common.util.Rpcs;
+import org.opendaylight.controller.sal.core.api.RpcProvisionRegistry;
+import org.opendaylight.yangtools.yang.binding.DataObject;
+import org.opendaylight.yangtools.yang.binding.RpcService;
+import org.opendaylight.yangtools.yang.common.QName;
+import org.opendaylight.yangtools.yang.common.RpcError;
+import org.opendaylight.yangtools.yang.common.RpcResult;
+import org.opendaylight.yangtools.yang.data.api.CompositeNode;
+import org.opendaylight.yangtools.yang.data.impl.codec.BindingIndependentMappingService;
+
+import com.google.common.util.concurrent.Futures;
+import com.google.common.util.concurrent.ListenableFuture;
+
+public class RpcInvocationStrategyTest {
+
+ @Mock
+ private BindingIndependentMappingService mockMappingService;
+ @Mock
+ private RpcProvisionRegistry mockbiRpcRegistry;
+
+ private RpcInvocationStrategy rpcInvocationStrategy;
+ private ListenableFuture<RpcResult<DataObject>> futureDataObj;
+ private ListenableFuture<RpcResult<CompositeNode>> futureCompNode;
+ private final RpcError rpcError = mock(RpcError.class);
+ private final Collection<RpcError> errors = new ArrayList<RpcError>();
+
+ private final CompositeNode inputInvokeOn = mock(CompositeNode.class);
+ private final CompositeNode outputInvokeOn = mock(CompositeNode.class);
+
+ private final DataObject toDataDomInput = mock(DataObject.class);
+ private final CompositeNode toDataDomReturn = mock(CompositeNode.class);
+ private final CompositeNode invokeRpcResult = mock(CompositeNode.class);
+
+ private final DataObject inputForward = mock(DataObject.class);
+ private final DataObject outputForward = mock(DataObject.class);
+
+ private QName mockQName;
+ private URI urn;
+
+ private final MockRpcService mockRpcService = new MockRpcService();
+
+ public class MockRpcService implements RpcService {
+
+ public Future<?> rpcnameWithInputNoOutput(DataObject input) {
+ return futureDataObj;
+ }
+
+ public Future<RpcResult<DataObject>> rpcnameWithInputWithOutput(DataObject input) {
+ return futureDataObj;
+ }
+
+ public Future<RpcResult<DataObject>> rpcnameNoInputWithOutput() {
+ return futureDataObj;
+ }
+
+ public Future<?> rpcnameNoInputNoOutput() {
+ return futureDataObj;
+ }
+ }
+
+ public RpcInvocationStrategyTest() {
+ MockitoAnnotations.initMocks(this);
+ }
+
+ @Before
+ public void testInit() throws Exception {
+ urn = new URI(new String("urn:a:valid:urn"));
+ }
+
+ private void setupForForwardToDom(boolean hasOutput, boolean hasInput, int expectedErrorSize) {
+
+ if (expectedErrorSize > 0)
+ errors.add(rpcError);
+ RpcResult<CompositeNode> result = Rpcs.getRpcResult(true, invokeRpcResult, errors);
+ futureCompNode = Futures.immediateFuture(result);
+ if( hasInput )
+ {
+ when(mockMappingService.toDataDom(inputForward)).thenReturn(toDataDomReturn);
+ }
+ when(mockbiRpcRegistry.invokeRpc(eq(mockQName), any(CompositeNode.class))).thenReturn(
+ futureCompNode);
+ if (hasOutput) {
+ when(
+ mockMappingService.dataObjectFromDataDom(eq(rpcInvocationStrategy
+ .getOutputClass().get()), any(CompositeNode.class))).thenReturn(
+ outputForward);
+ }
+
+ }
+
+ private void validateForwardToDomBroker(ListenableFuture<RpcResult<?>> forwardToDomBroker,
+ boolean expectedSuccess, DataObject expectedResult, int expectedErrorSize)
+ throws InterruptedException, ExecutionException {
+ assertNotNull(forwardToDomBroker);
+ assertEquals(expectedSuccess, forwardToDomBroker.get().isSuccessful());
+ assertEquals(expectedResult, forwardToDomBroker.get().getResult());
+ assertEquals(expectedErrorSize, forwardToDomBroker.get().getErrors().size());
+ }
+
+ private void setupTestMethod(String rpcName, String testMethodName, boolean hasInput)
+ throws NoSuchMethodException {
+ mockQName = new QName(urn, new Date(0L), new String("prefix"), new String(rpcName));
+ java.lang.reflect.Method rpcMethod = hasInput ? MockRpcService.class.getMethod(rpcName,
+ DataObject.class) : MockRpcService.class.getMethod(rpcName);
+ rpcInvocationStrategy = new RpcInvocationStrategy(mockQName, rpcMethod, mockMappingService,
+ mockbiRpcRegistry);
+ }
+
+ /*
+ * forwardToDomBroker tests
+ */
+ @Test
+ public void testForwardToDomBroker_WithInputNoOutput() throws Exception {
+ setupTestMethod("rpcnameWithInputNoOutput", "testForwardToDomBroker_WithInputNoOutput",
+ true);
+ setupForForwardToDom(false, true, 0);
+ ListenableFuture<RpcResult<?>> forwardToDomBroker = rpcInvocationStrategy
+ .forwardToDomBroker(inputForward);
+
+ validateForwardToDomBroker(forwardToDomBroker, true, null, 0);
+ }
+
+ @Test
+ public void testForwardToDomBroker_WithInputNoOutput_error() throws Exception {
+ setupTestMethod("rpcnameWithInputNoOutput",
+ "testForwardToDomBroker_WithInputNoOutput_error", true);
+ setupForForwardToDom(false, true, 1);
+ ListenableFuture<RpcResult<?>> forwardToDomBroker = rpcInvocationStrategy
+ .forwardToDomBroker(inputForward);
+
+ validateForwardToDomBroker(forwardToDomBroker, true, null, 1);
+ }
+
+ @Test
+ public void testForwardToDomBroker_WithInputWithOutput() throws Exception {
+ setupTestMethod("rpcnameWithInputWithOutput", "testForwardToDomBroker_WithInputWithOutput",
+ true);
+ setupForForwardToDom(true, true, 0);
+ ListenableFuture<RpcResult<?>> forwardToDomBroker = rpcInvocationStrategy
+ .forwardToDomBroker(inputForward);
+ validateForwardToDomBroker(forwardToDomBroker, true, outputForward, 0);
+ }
+
+ @Test
+ public void testForwardToDomBroker_NoInputWithOutput() throws Exception {
+ setupTestMethod("rpcnameNoInputWithOutput", "testForwardToDomBroker_NoInputWithOutput",
+ false);
+ setupForForwardToDom(true, false, 0);
+ ListenableFuture<RpcResult<?>> forwardToDomBroker = rpcInvocationStrategy
+ .forwardToDomBroker(null);
+ validateForwardToDomBroker(forwardToDomBroker, true, outputForward, 0);
+ }
+
+ @Test
+ public void testForwardToDomBroker_NoInputNoOutput() throws Exception {
+ setupTestMethod("rpcnameNoInputNoOutput", "testForwardToDomBroker_NoInputNoOutput", false);
+ setupForForwardToDom(false, false, 0);
+ ListenableFuture<RpcResult<?>> forwardToDomBroker = rpcInvocationStrategy
+ .forwardToDomBroker(null);
+ validateForwardToDomBroker(forwardToDomBroker, true, null, 0);
+ }
+
+ /*
+ * invokeOn Tests
+ */
+ private void setupRpcResultsWithOutput(int expectedErrorSize) {
+ if (expectedErrorSize > 0)
+ errors.add(rpcError);
+ RpcResult<CompositeNode> resultCompNode = Rpcs.getRpcResult(true, inputInvokeOn, errors);
+ futureCompNode = Futures.immediateFuture(resultCompNode);
+ RpcResult<DataObject> resultDataObj = Rpcs.getRpcResult(true, toDataDomInput, errors);
+ futureDataObj = Futures.immediateFuture(resultDataObj);
+
+ when(mockMappingService.toDataDom(toDataDomInput)).thenReturn(outputInvokeOn);
+ }
+
+ private void setupRpcResultsNoOutput(int expectedErrorSize) {
+ if (expectedErrorSize > 0)
+ errors.add(rpcError);
+ RpcResult<CompositeNode> resultCompNode = Rpcs.getRpcResult(true, inputInvokeOn, errors);
+ futureCompNode = Futures.immediateFuture(resultCompNode);
+ RpcResult<DataObject> resultDataObj = Rpcs.getRpcResult(true, null, errors);
+ futureDataObj = Futures.immediateFuture(resultDataObj);
+ }
+
+ private void validateReturnedImmediateFuture(
+ ListenableFuture<RpcResult<CompositeNode>> immediateFuture, boolean expectedSuccess,
+ CompositeNode expectedReturn, int expectedErrorSize) throws InterruptedException,
+ ExecutionException {
+ assertNotNull(immediateFuture);
+ assertEquals(expectedSuccess, immediateFuture.get().isSuccessful());
+ assertEquals(expectedReturn, immediateFuture.get().getResult());
+ assertEquals(expectedErrorSize, immediateFuture.get().getErrors().size());
+ }
+
+ @Test
+ public void testInvokeOn_NoInputNoOutput() throws Exception {
+ setupTestMethod("rpcnameNoInputNoOutput", "testInvokeOn_NoInputNoOutput", false);
+ setupRpcResultsNoOutput(0);
+ ListenableFuture<RpcResult<CompositeNode>> immediateFuture = Futures
+ .immediateFuture(rpcInvocationStrategy.invokeOn(mockRpcService, inputInvokeOn));
+ validateReturnedImmediateFuture(immediateFuture, true, null, 0);
+ }
+
+ @Test
+ public void testInvokeOn_NoInputNoOutput_errors() throws Exception {
+ setupTestMethod("rpcnameNoInputNoOutput", "testInvokeOn_NoInputNoOutput", false);
+ setupRpcResultsNoOutput(1);
+ ListenableFuture<RpcResult<CompositeNode>> immediateFuture = Futures
+ .immediateFuture(rpcInvocationStrategy.invokeOn(mockRpcService, inputInvokeOn));
+ validateReturnedImmediateFuture(immediateFuture, true, null, 1);
+ }
+
+ @Test
+ public void testInvokeOn_WithInputNoOutput() throws Exception {
+ setupTestMethod("rpcnameWithInputNoOutput", "testInvokeOn_WithInputNoOutput", true);
+ setupRpcResultsNoOutput(0);
+ ListenableFuture<RpcResult<CompositeNode>> immediateFuture = Futures
+ .immediateFuture(rpcInvocationStrategy.invokeOn(mockRpcService, inputInvokeOn));
+ validateReturnedImmediateFuture(immediateFuture, true, null, 0);
+ }
+
+ @Test
+ public void testInvokeOn_WithInputWithOutput() throws Exception {
+ setupTestMethod("rpcnameWithInputWithOutput", "testInvokeOn_WithInputWithOutput", true);
+ setupRpcResultsWithOutput(0);
+ ListenableFuture<RpcResult<CompositeNode>> immediateFuture = Futures
+ .immediateFuture(rpcInvocationStrategy.invokeOn(mockRpcService, inputInvokeOn));
+ validateReturnedImmediateFuture(immediateFuture, true, outputInvokeOn, 0);
+ }
+
+ @Test
+ public void testInvokeOn_NoInputWithOutput() throws Exception {
+ setupTestMethod("rpcnameNoInputWithOutput", "testInvokeOn_NoInputWithOutput", false);
+ setupRpcResultsWithOutput(0);
+ ListenableFuture<RpcResult<CompositeNode>> immediateFuture = Futures
+ .immediateFuture(rpcInvocationStrategy.invokeOn(mockRpcService, inputInvokeOn));
+ validateReturnedImmediateFuture(immediateFuture, true, outputInvokeOn, 0);
+ }
+}
import org.opendaylight.yangtools.yang.common.RpcResult;
import org.opendaylight.yangtools.yang.data.api.CompositeNode;
-public class MultipleAugmentationPuts extends AbstractDataServiceTest implements DataChangeListener {
+public class MultipleAugmentationPutsTest extends AbstractDataServiceTest implements DataChangeListener {
private static final QName NODE_ID_QNAME = QName.create(Node.QNAME, "id");
private static final String NODE_ID = "openflow:1";
*
* @throws Exception
*/
- @Test
+ @Test( timeout = 15000)
public void testAugmentSerialization() throws Exception {
baDataService.registerDataChangeListener(NODES_INSTANCE_ID_BA, this);
}
@Override
- protected NormalizedNodeContainerBuilder createBuilder(final CompositeNode compositeNode) {
+ protected NormalizedNodeContainerBuilder<?, ?, ?, ?> createBuilder(final CompositeNode compositeNode) {
ImmutableMap.Builder<QName, Object> keys = ImmutableMap.builder();
for (QName key : keyDefinition) {
}
@Override
- protected NormalizedNodeContainerBuilder createBuilder(final CompositeNode compositeNode) {
+ protected NormalizedNodeContainerBuilder<?, ?, ?, ?> createBuilder(final CompositeNode compositeNode) {
return Builders.unkeyedListEntryBuilder().withNodeIdentifier(getIdentifier());
}
}
@Override
- protected NormalizedNodeContainerBuilder createBuilder(final CompositeNode compositeNode) {
+ protected NormalizedNodeContainerBuilder<?, ?, ?, ?> createBuilder(final CompositeNode compositeNode) {
return Builders.containerBuilder().withNodeIdentifier(getIdentifier());
}
}
@Override
- protected NormalizedNodeContainerBuilder createBuilder(final CompositeNode compositeNode) {
+ protected NormalizedNodeContainerBuilder<?, ?, ?, ?> createBuilder(final CompositeNode compositeNode) {
return Builders.orderedLeafSetBuilder().withNodeIdentifier(getIdentifier());
}
}
@Override
- protected NormalizedNodeContainerBuilder createBuilder(final CompositeNode compositeNode) {
+ protected NormalizedNodeContainerBuilder<?, ?, ?, ?> createBuilder(final CompositeNode compositeNode) {
return Builders.leafSetBuilder().withNodeIdentifier(getIdentifier());
}
}
@Override
- protected NormalizedNodeContainerBuilder createBuilder(final CompositeNode compositeNode) {
+ protected NormalizedNodeContainerBuilder<?, ?, ?, ?> createBuilder(final CompositeNode compositeNode) {
return Builders.choiceBuilder().withNodeIdentifier(getIdentifier());
}
package org.opendaylight.controller.md.sal.dom.broker.impl.compat;
import org.opendaylight.controller.md.sal.common.api.RegistrationListener;
-import org.opendaylight.controller.md.sal.common.api.data.AsyncDataChangeEvent;
-import org.opendaylight.controller.md.sal.common.api.data.DataChangeEvent;
import org.opendaylight.controller.md.sal.common.api.data.DataCommitHandler;
import org.opendaylight.controller.md.sal.common.api.data.DataCommitHandlerRegistration;
import org.opendaylight.controller.md.sal.common.api.data.DataReader;
import org.opendaylight.controller.md.sal.common.impl.util.compat.DataNormalizer;
import org.opendaylight.controller.md.sal.dom.api.DOMDataBroker;
-import org.opendaylight.controller.md.sal.dom.api.DOMDataChangeListener;
import org.opendaylight.controller.sal.common.DataStoreIdentifier;
import org.opendaylight.controller.sal.core.api.data.DataChangeListener;
import org.opendaylight.controller.sal.core.api.data.DataModificationTransaction;
import org.opendaylight.controller.sal.core.api.data.DataProviderService;
import org.opendaylight.controller.sal.core.api.data.DataValidator;
import org.opendaylight.yangtools.concepts.AbstractObjectRegistration;
-import org.opendaylight.yangtools.concepts.Delegator;
import org.opendaylight.yangtools.concepts.ListenerRegistration;
import org.opendaylight.yangtools.concepts.Registration;
-import org.opendaylight.yangtools.concepts.util.ListenerRegistry;
import org.opendaylight.yangtools.yang.data.api.CompositeNode;
import org.opendaylight.yangtools.yang.data.api.InstanceIdentifier;
-import org.opendaylight.yangtools.yang.data.api.schema.NormalizedNode;
import org.opendaylight.yangtools.yang.model.api.SchemaContext;
import org.opendaylight.yangtools.yang.model.api.SchemaContextListener;
public class BackwardsCompatibleDataBroker implements DataProviderService, SchemaContextListener {
- DOMDataBroker backingBroker;
- DataNormalizer normalizer;
- private final ListenerRegistry<DataChangeListener> fakeRegistry = ListenerRegistry.create();
-
+ private final DOMDataBroker backingBroker;
+ private DataNormalizer normalizer;
public BackwardsCompatibleDataBroker(final DOMDataBroker newBiDataImpl) {
backingBroker = newBiDataImpl;
@Override
public CompositeNode readConfigurationData(final InstanceIdentifier legacyPath) {
- BackwardsCompatibleTransaction<?> tx = BackwardsCompatibleTransaction.readOnlyTransaction(backingBroker.newReadOnlyTransaction(),normalizer);
+ final BackwardsCompatibleTransaction<?> tx = BackwardsCompatibleTransaction.readOnlyTransaction(backingBroker.newReadOnlyTransaction(),normalizer);
try {
return tx.readConfigurationData(legacyPath);
} finally {
@Override
public CompositeNode readOperationalData(final InstanceIdentifier legacyPath) {
- BackwardsCompatibleTransaction<?> tx = BackwardsCompatibleTransaction.readOnlyTransaction(backingBroker.newReadOnlyTransaction(),normalizer);
+ final BackwardsCompatibleTransaction<?> tx = BackwardsCompatibleTransaction.readOnlyTransaction(backingBroker.newReadOnlyTransaction(),normalizer);
try {
return tx.readOperationalData(legacyPath);
} finally {
}
@Override
- public ListenerRegistration<DataChangeListener> registerDataChangeListener(final InstanceIdentifier path,
+ public ListenerRegistration<DataChangeListener> registerDataChangeListener(final InstanceIdentifier legacyPath,
final DataChangeListener listener) {
- return fakeRegistry .register(listener);
+ final InstanceIdentifier normalizedPath = normalizer.toNormalized(legacyPath);
+
+ final TranslatingListenerInvoker translatingCfgListener =
+ TranslatingListenerInvoker.createConfig(listener, normalizer);
+ translatingCfgListener.register(backingBroker, normalizedPath);
+
+ final TranslatingListenerInvoker translatingOpListener =
+ TranslatingListenerInvoker.createOperational(listener, normalizer);
+ translatingOpListener.register(backingBroker, normalizedPath);
+
+ return new DelegateListenerRegistration(translatingCfgListener, translatingOpListener, listener);
}
@Override
return null;
}
- // Obsolote functionality
+ // Obsolete functionality
@Override
public void addValidator(final DataStoreIdentifier store, final DataValidator validator) {
throw new UnsupportedOperationException("Data Reader contract is not supported.");
}
- private final class TranslatingListenerInvoker implements DOMDataChangeListener, Delegator<DataChangeListener> {
-
+ private static class DelegateListenerRegistration implements ListenerRegistration<DataChangeListener> {
+ private final TranslatingListenerInvoker translatingCfgListener;
+ private final TranslatingListenerInvoker translatingOpListener;
+ private final DataChangeListener listener;
- private DataChangeListener delegate;
+ public DelegateListenerRegistration(final TranslatingListenerInvoker translatingCfgListener, final TranslatingListenerInvoker translatingOpListener, final DataChangeListener listener) {
+ this.translatingCfgListener = translatingCfgListener;
+ this.translatingOpListener = translatingOpListener;
+ this.listener = listener;
+ }
@Override
- public void onDataChanged(final AsyncDataChangeEvent<InstanceIdentifier, NormalizedNode<?, ?>> normalizedChange) {
-
- DataChangeEvent<InstanceIdentifier, CompositeNode> legacyChange = null;
- delegate.onDataChanged(legacyChange);
+ public void close() {
+ translatingCfgListener.close();
+ translatingOpListener.close();
}
@Override
- public DataChangeListener getDelegate() {
-
- return delegate;
+ public DataChangeListener getInstance() {
+ return listener;
}
-
-
}
-
}
--- /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.broker.impl.compat;
+
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.Map;
+import java.util.Set;
+
+import org.opendaylight.controller.md.sal.common.api.data.AsyncDataChangeEvent;
+import org.opendaylight.controller.md.sal.common.api.data.DataChangeEvent;
+import org.opendaylight.controller.md.sal.common.impl.util.compat.DataNormalizationException;
+import org.opendaylight.controller.md.sal.common.impl.util.compat.DataNormalizer;
+import org.opendaylight.yangtools.yang.data.api.CompositeNode;
+import org.opendaylight.yangtools.yang.data.api.InstanceIdentifier;
+import org.opendaylight.yangtools.yang.data.api.schema.NormalizedNode;
+
+import com.google.common.collect.Maps;
+
+public abstract class TranslatingDataChangeEvent implements
+ DataChangeEvent<org.opendaylight.yangtools.yang.data.api.InstanceIdentifier, CompositeNode> {
+
+ private TranslatingDataChangeEvent() {
+ }
+
+ public static DataChangeEvent<InstanceIdentifier, CompositeNode> createOperational(
+ final AsyncDataChangeEvent<InstanceIdentifier, NormalizedNode<?, ?>> change, final DataNormalizer normalizer) {
+ return new OperationalChangeEvent(change, normalizer);
+ }
+
+ public static DataChangeEvent<InstanceIdentifier, CompositeNode> createConfiguration(
+ final AsyncDataChangeEvent<InstanceIdentifier, NormalizedNode<?, ?>> change, final DataNormalizer normalizer) {
+ return new ConfigurationChangeEvent(change, normalizer);
+ }
+
+ @Override
+ public Map<org.opendaylight.yangtools.yang.data.api.InstanceIdentifier, CompositeNode> getCreatedOperationalData() {
+ return Collections.emptyMap();
+ }
+
+ @Override
+ public Map<org.opendaylight.yangtools.yang.data.api.InstanceIdentifier, CompositeNode> getCreatedConfigurationData() {
+ return Collections.emptyMap();
+ }
+
+ @Override
+ public Map<org.opendaylight.yangtools.yang.data.api.InstanceIdentifier, CompositeNode> getUpdatedOperationalData() {
+ return Collections.emptyMap();
+ }
+
+ @Override
+ public Map<org.opendaylight.yangtools.yang.data.api.InstanceIdentifier, CompositeNode> getUpdatedConfigurationData() {
+ return Collections.emptyMap();
+ }
+
+ @Override
+ public Set<org.opendaylight.yangtools.yang.data.api.InstanceIdentifier> getRemovedConfigurationData() {
+ return Collections.emptySet();
+ }
+
+ @Override
+ public Set<org.opendaylight.yangtools.yang.data.api.InstanceIdentifier> getRemovedOperationalData() {
+ return Collections.emptySet();
+ }
+
+ @Override
+ public Map<org.opendaylight.yangtools.yang.data.api.InstanceIdentifier, CompositeNode> getOriginalConfigurationData() {
+ return Collections.emptyMap();
+ }
+
+ @Override
+ public Map<org.opendaylight.yangtools.yang.data.api.InstanceIdentifier, CompositeNode> getOriginalOperationalData() {
+ return Collections.emptyMap();
+ }
+
+ @Override
+ public CompositeNode getOriginalConfigurationSubtree() {
+ return null;
+ }
+
+ @Override
+ public CompositeNode getOriginalOperationalSubtree() {
+ return null;
+ }
+
+ @Override
+ public CompositeNode getUpdatedConfigurationSubtree() {
+ return null;
+ }
+
+ @Override
+ public CompositeNode getUpdatedOperationalSubtree() {
+ return null;
+ }
+
+ @SuppressWarnings({ "rawtypes", "unchecked" })
+ private final static class OperationalChangeEvent extends TranslatingDataChangeEvent {
+
+ private final AsyncDataChangeEvent<InstanceIdentifier, NormalizedNode<?, ?>> delegate;
+ private final DataNormalizer normalizer;
+ private Map<org.opendaylight.yangtools.yang.data.api.InstanceIdentifier, CompositeNode> updatedCache;
+
+ public OperationalChangeEvent(final AsyncDataChangeEvent<InstanceIdentifier, NormalizedNode<?, ?>> change,
+ final DataNormalizer normalizer) {
+ this.delegate = change;
+ this.normalizer = normalizer;
+ }
+
+ @Override
+ public Map<org.opendaylight.yangtools.yang.data.api.InstanceIdentifier, CompositeNode> getCreatedOperationalData() {
+ return transformToLegacy(normalizer, delegate.getCreatedData());
+ }
+
+
+ @Override
+ public Set<org.opendaylight.yangtools.yang.data.api.InstanceIdentifier> getRemovedOperationalData() {
+ return delegate.getRemovedPaths();
+ }
+
+ @Override
+ public CompositeNode getOriginalOperationalSubtree() {
+ // first argument is unused
+ return normalizer.toLegacy(null, delegate.getOriginalSubtree());
+ }
+
+ @Override
+ public CompositeNode getUpdatedOperationalSubtree() {
+ // first argument is unused
+ return normalizer.toLegacy(null, delegate.getUpdatedSubtree());
+ }
+
+ @Override
+ public Map<org.opendaylight.yangtools.yang.data.api.InstanceIdentifier, CompositeNode> getOriginalOperationalData() {
+ return transformToLegacy(normalizer, delegate.getOriginalData());
+ }
+
+ @Override
+ public Map<org.opendaylight.yangtools.yang.data.api.InstanceIdentifier, CompositeNode> getUpdatedOperationalData() {
+ if(updatedCache == null) {
+ final Map<InstanceIdentifier, CompositeNode> updated = transformToLegacy(normalizer, delegate.getUpdatedData());
+ final Map<org.opendaylight.yangtools.yang.data.api.InstanceIdentifier, CompositeNode> created = getCreatedConfigurationData();
+ final HashMap<org.opendaylight.yangtools.yang.data.api.InstanceIdentifier, CompositeNode> updatedComposite = new HashMap<>(created.size() + updated.size());
+ updatedComposite.putAll(created);
+ updatedComposite.putAll(updated);
+ updatedCache = Collections.unmodifiableMap(updatedComposite);
+ }
+ return updatedCache;
+ }
+
+ @Override
+ public String toString() {
+ return "OperationalChangeEvent [delegate=" + delegate + "]";
+ }
+
+ }
+
+ private static Map<InstanceIdentifier, CompositeNode> transformToLegacy(final DataNormalizer normalizer, final Map<InstanceIdentifier, ? extends NormalizedNode<?, ?>> nodes) {
+ final Map<InstanceIdentifier, CompositeNode> legacy = Maps.newHashMap();
+
+ for (final Map.Entry<InstanceIdentifier, ? extends NormalizedNode<?, ?>> entry : nodes.entrySet()) {
+ try {
+ legacy.put(normalizer.toLegacy(entry.getKey()), normalizer.toLegacy(entry.getKey(), entry.getValue()));
+ } catch (final DataNormalizationException e) {
+ throw new IllegalStateException("Unable to transform data change event to legacy format", e);
+ }
+ }
+ return legacy;
+ }
+
+ private final static class ConfigurationChangeEvent extends TranslatingDataChangeEvent {
+
+ private final AsyncDataChangeEvent<InstanceIdentifier, NormalizedNode<?, ?>> delegate;
+ private final DataNormalizer normalizer;
+ private Map<org.opendaylight.yangtools.yang.data.api.InstanceIdentifier, CompositeNode> updatedCache;
+
+ public ConfigurationChangeEvent(final AsyncDataChangeEvent<InstanceIdentifier, NormalizedNode<?, ?>> change,
+ final DataNormalizer normalizer) {
+ this.delegate = change;
+ this.normalizer = normalizer;
+ }
+
+ @Override
+ public Map<org.opendaylight.yangtools.yang.data.api.InstanceIdentifier, CompositeNode> getCreatedConfigurationData() {
+ return transformToLegacy(normalizer, delegate.getCreatedData());
+ }
+
+
+ @Override
+ public Set<org.opendaylight.yangtools.yang.data.api.InstanceIdentifier> getRemovedConfigurationData() {
+ return delegate.getRemovedPaths();
+ }
+
+ @Override
+ public CompositeNode getOriginalConfigurationSubtree() {
+ // first argument is unused
+ return normalizer.toLegacy(null, delegate.getOriginalSubtree());
+ }
+
+ @Override
+ public CompositeNode getUpdatedConfigurationSubtree() {
+ // first argument is unused
+ return normalizer.toLegacy(null, delegate.getUpdatedSubtree());
+ }
+
+ @Override
+ public Map<org.opendaylight.yangtools.yang.data.api.InstanceIdentifier, CompositeNode> getOriginalConfigurationData() {
+ return transformToLegacy(normalizer, delegate.getOriginalData());
+ }
+
+ @Override
+ public Map<org.opendaylight.yangtools.yang.data.api.InstanceIdentifier, CompositeNode> getUpdatedConfigurationData() {
+ if(updatedCache == null) {
+ final Map<InstanceIdentifier, CompositeNode> updated = transformToLegacy(normalizer, delegate.getUpdatedData());
+ final Map<org.opendaylight.yangtools.yang.data.api.InstanceIdentifier, CompositeNode> created = getCreatedConfigurationData();
+ final HashMap<org.opendaylight.yangtools.yang.data.api.InstanceIdentifier, CompositeNode> updatedComposite = new HashMap<>(created.size() + updated.size());
+ updatedComposite.putAll(created);
+ updatedComposite.putAll(updated);
+ updatedCache = Collections.unmodifiableMap(updatedComposite);
+ }
+ return updatedCache;
+ }
+
+ @Override
+ public String toString() {
+ return "ConfigurationChangeEvent [delegate=" + delegate + "]";
+ }
+ }
+}
--- /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.broker.impl.compat;
+
+import org.opendaylight.controller.md.sal.common.api.data.AsyncDataBroker;
+import org.opendaylight.controller.md.sal.common.api.data.AsyncDataChangeEvent;
+import org.opendaylight.controller.md.sal.common.api.data.DataChangeEvent;
+import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType;
+import org.opendaylight.controller.md.sal.common.impl.util.compat.DataNormalizer;
+import org.opendaylight.controller.md.sal.dom.api.DOMDataBroker;
+import org.opendaylight.controller.md.sal.dom.api.DOMDataChangeListener;
+import org.opendaylight.controller.sal.core.api.data.DataChangeListener;
+import org.opendaylight.yangtools.concepts.Delegator;
+import org.opendaylight.yangtools.concepts.ListenerRegistration;
+import org.opendaylight.yangtools.yang.data.api.CompositeNode;
+import org.opendaylight.yangtools.yang.data.api.InstanceIdentifier;
+import org.opendaylight.yangtools.yang.data.api.schema.NormalizedNode;
+
+abstract class TranslatingListenerInvoker implements AutoCloseable, DOMDataChangeListener, Delegator<DataChangeListener> {
+
+ private final DataChangeListener delegate;
+ private final DataNormalizer normalizer;
+ protected ListenerRegistration<DOMDataChangeListener> reg;
+
+ protected TranslatingListenerInvoker(final DataChangeListener listener, final DataNormalizer normalizer) {
+ this.delegate = listener;
+ this.normalizer = normalizer;
+ }
+
+ static TranslatingListenerInvoker createConfig(final DataChangeListener listener, final DataNormalizer normalizer) {
+ return new TranslatingConfigListenerInvoker(listener, normalizer);
+ }
+
+ static TranslatingListenerInvoker createOperational(final DataChangeListener listener, final DataNormalizer normalizer) {
+ return new TranslatingOperationalListenerInvoker(listener, normalizer);
+ }
+
+ @Override
+ public void onDataChanged(final AsyncDataChangeEvent<InstanceIdentifier, NormalizedNode<?, ?>> normalizedChange) {
+ delegate.onDataChanged(getLegacyEvent(normalizer, normalizedChange));
+ }
+
+ abstract DataChangeEvent<InstanceIdentifier, CompositeNode> getLegacyEvent(final DataNormalizer normalizer,
+ final AsyncDataChangeEvent<InstanceIdentifier, NormalizedNode<?, ?>> normalizedChange);
+
+ @Override
+ public DataChangeListener getDelegate() {
+ return delegate;
+ }
+
+ abstract void register(final DOMDataBroker backingBroker, final InstanceIdentifier normalizedPath);
+
+ @Override
+ public void close() {
+ if (reg != null) {
+ reg.close();
+ }
+ }
+
+ static final class TranslatingConfigListenerInvoker extends TranslatingListenerInvoker {
+
+ public TranslatingConfigListenerInvoker(final DataChangeListener listener, final DataNormalizer normalizer) {
+ super(listener, normalizer);
+ }
+
+ DataChangeEvent<InstanceIdentifier, CompositeNode> getLegacyEvent(final DataNormalizer normalizer, final AsyncDataChangeEvent<InstanceIdentifier, NormalizedNode<?, ?>> normalizedChange) {
+ return TranslatingDataChangeEvent.createConfiguration(normalizedChange, normalizer);
+ }
+
+ @Override
+ void register(final DOMDataBroker backingBroker, final InstanceIdentifier normalizedPath) {
+ reg = backingBroker.registerDataChangeListener(LogicalDatastoreType.CONFIGURATION, normalizedPath, this,
+ AsyncDataBroker.DataChangeScope.SUBTREE);
+ }
+ }
+
+ static final class TranslatingOperationalListenerInvoker extends TranslatingListenerInvoker {
+
+ public TranslatingOperationalListenerInvoker(final DataChangeListener listener, final DataNormalizer normalizer) {
+ super(listener, normalizer);
+ }
+
+ DataChangeEvent<InstanceIdentifier, CompositeNode> getLegacyEvent(final DataNormalizer normalizer, final AsyncDataChangeEvent<InstanceIdentifier, NormalizedNode<?, ?>> normalizedChange) {
+ return TranslatingDataChangeEvent.createOperational(normalizedChange, normalizer);
+ }
+
+ @Override
+ void register(final DOMDataBroker backingBroker, final InstanceIdentifier normalizedPath) {
+ reg = backingBroker.registerDataChangeListener(LogicalDatastoreType.OPERATIONAL, normalizedPath, this,
+ AsyncDataBroker.DataChangeScope.SUBTREE);
+ }
+ }
+
+}
+++ /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;
-
-import org.opendaylight.yangtools.yang.data.api.InstanceIdentifier;
-
-public class DataPreconditionFailedException extends Exception {
-
- /**
- *
- */
- private static final long serialVersionUID = 596430355175413427L;
- private final InstanceIdentifier path;
-
- public DataPreconditionFailedException(final InstanceIdentifier path) {
- this.path = path;
- }
-
- public DataPreconditionFailedException(final InstanceIdentifier path,final String message) {
- super(message);
- this.path = path;
- }
-
-
- public DataPreconditionFailedException(final InstanceIdentifier path,final Throwable cause) {
- super(cause);
- this.path = path;
- }
-
- public DataPreconditionFailedException(final InstanceIdentifier path,final String message, final Throwable cause) {
- super(message, cause);
- this.path = path;
- }
-
- public DataPreconditionFailedException(final InstanceIdentifier path,final String message, final Throwable cause, final boolean enableSuppression,
- final boolean writableStackTrace) {
- super(message, cause, enableSuppression, writableStackTrace);
- this.path = path;
- }
-
- public InstanceIdentifier getPath() {
- return path;
- }
-
-}
+++ /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;
-
-import java.util.concurrent.locks.ReadWriteLock;
-import java.util.concurrent.locks.ReentrantReadWriteLock;
-
-import org.opendaylight.controller.md.sal.dom.store.impl.tree.StoreMetadataNode;
-import org.opendaylight.yangtools.yang.data.api.InstanceIdentifier;
-import org.opendaylight.yangtools.yang.data.api.InstanceIdentifier.NodeIdentifier;
-import org.opendaylight.yangtools.yang.data.api.schema.NormalizedNode;
-import org.opendaylight.yangtools.yang.data.impl.schema.Builders;
-import org.opendaylight.yangtools.yang.data.impl.schema.NormalizedNodeUtils;
-import org.opendaylight.yangtools.yang.model.api.SchemaContext;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-
-import com.google.common.annotations.VisibleForTesting;
-import com.google.common.base.Optional;
-import com.google.common.base.Preconditions;
-
-/**
- * Read-only snapshot of the data tree.
- */
-final class DataTree {
- public static final class Snapshot {
- private final SchemaContext schemaContext;
- private final StoreMetadataNode rootNode;
-
- @VisibleForTesting
- Snapshot(final SchemaContext schemaContext, final StoreMetadataNode rootNode) {
- this.schemaContext = Preconditions.checkNotNull(schemaContext);
- this.rootNode = Preconditions.checkNotNull(rootNode);
- }
-
- public SchemaContext getSchemaContext() {
- return schemaContext;
- }
-
- public Optional<NormalizedNode<?, ?>> readNode(final InstanceIdentifier path) {
- return NormalizedNodeUtils.findNode(rootNode.getData(), path);
- }
-
- // FIXME: this is a leak of information
- @Deprecated
- StoreMetadataNode getRootNode() {
- return rootNode;
- }
-
- @Override
- public String toString() {
- return rootNode.getSubtreeVersion().toString();
- }
- }
-
- private static final Logger LOG = LoggerFactory.getLogger(DataTree.class);
- private final ReadWriteLock rwLock = new ReentrantReadWriteLock(true);
- private StoreMetadataNode rootNode;
- private SchemaContext currentSchemaContext;
-
- private DataTree(StoreMetadataNode rootNode, final SchemaContext schemaContext) {
- this.rootNode = Preconditions.checkNotNull(rootNode);
- this.currentSchemaContext = schemaContext;
- }
-
- public synchronized void setSchemaContext(final SchemaContext newSchemaContext) {
- Preconditions.checkNotNull(newSchemaContext);
-
- LOG.info("Attepting to install schema context {}", newSchemaContext);
-
- /*
- * FIXME: we should walk the schema contexts, both current and new and see
- * whether they are compatible here. Reject incompatible changes.
- */
-
- // Ready to change the context now, make sure no operations are running
- rwLock.writeLock().lock();
- try {
- this.currentSchemaContext = newSchemaContext;
- } finally {
- rwLock.writeLock().unlock();
- }
- }
-
- public static DataTree create(final SchemaContext schemaContext) {
- final NodeIdentifier root = new NodeIdentifier(SchemaContext.NAME);
- final NormalizedNode<?, ?> data = Builders.containerBuilder().withNodeIdentifier(root).build();
-
- return new DataTree(StoreMetadataNode.createEmpty(data), schemaContext);
- }
-
- public Snapshot takeSnapshot() {
- rwLock.readLock().lock();
-
- try {
- return new Snapshot(currentSchemaContext, rootNode);
- } finally {
- rwLock.readLock().unlock();
- }
- }
-
- public void commitSnapshot(Snapshot currentSnapshot, StoreMetadataNode newDataTree) {
- // Ready to change the context now, make sure no operations are running
- rwLock.writeLock().lock();
- try {
- Preconditions.checkState(currentSnapshot.rootNode == rootNode,
- String.format("Store snapshot %s and transaction snapshot %s differ.",
- rootNode, currentSnapshot.rootNode));
-
- this.rootNode = newDataTree;
- } finally {
- rwLock.writeLock().unlock();
- }
- }
-}
import static com.google.common.base.Preconditions.checkNotNull;
import static com.google.common.base.Preconditions.checkState;
-import static org.opendaylight.controller.md.sal.dom.store.impl.StoreUtils.increase;
import java.util.Collections;
import java.util.concurrent.Callable;
import org.opendaylight.controller.md.sal.common.api.data.AsyncDataBroker.DataChangeScope;
import org.opendaylight.controller.md.sal.common.api.data.AsyncDataChangeListener;
+import org.opendaylight.controller.md.sal.dom.store.impl.tree.DataPreconditionFailedException;
+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.DataTreeSnapshot;
import org.opendaylight.controller.md.sal.dom.store.impl.tree.ListenerTree;
-import org.opendaylight.controller.md.sal.dom.store.impl.tree.ModificationType;
-import org.opendaylight.controller.md.sal.dom.store.impl.tree.NodeModification;
-import org.opendaylight.controller.md.sal.dom.store.impl.tree.StoreMetadataNode;
+import org.opendaylight.controller.md.sal.dom.store.impl.tree.data.InMemoryDataTreeFactory;
import org.opendaylight.controller.sal.core.spi.data.DOMStore;
import org.opendaylight.controller.sal.core.spi.data.DOMStoreReadTransaction;
import org.opendaylight.controller.sal.core.spi.data.DOMStoreReadWriteTransaction;
import org.opendaylight.yangtools.concepts.Identifiable;
import org.opendaylight.yangtools.concepts.ListenerRegistration;
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 org.opendaylight.yangtools.yang.model.api.SchemaContext;
import org.opendaylight.yangtools.yang.model.api.SchemaContextListener;
import com.google.common.base.Objects.ToStringHelper;
import com.google.common.base.Optional;
import com.google.common.base.Preconditions;
-import com.google.common.primitives.UnsignedLong;
import com.google.common.util.concurrent.Futures;
import com.google.common.util.concurrent.ListenableFuture;
import com.google.common.util.concurrent.ListeningExecutorService;
public class InMemoryDOMDataStore implements DOMStore, Identifiable<String>, SchemaContextListener {
-
private static final Logger LOG = LoggerFactory.getLogger(InMemoryDOMDataStore.class);
- private static final InstanceIdentifier PUBLIC_ROOT_PATH = InstanceIdentifier.builder().build();
-
+ private final DataTree dataTree = InMemoryDataTreeFactory.getInstance().create();
+ private final ListenerTree listenerTree = ListenerTree.create();
+ private final AtomicLong txCounter = new AtomicLong(0);
private final ListeningExecutorService executor;
private final String name;
- private final AtomicLong txCounter = new AtomicLong(0);
- private final ListenerTree listenerTree = ListenerTree.create();
- private final DataTree dataTree = DataTree.create(null);
- private ModificationApplyOperation operationTree = new AlwaysFailOperation();
public InMemoryDOMDataStore(final String name, final ListeningExecutorService executor) {
this.name = Preconditions.checkNotNull(name);
@Override
public DOMStoreReadWriteTransaction newReadWriteTransaction() {
- return new SnapshotBackedReadWriteTransaction(nextIdentifier(), dataTree.takeSnapshot(), this, operationTree);
+ return new SnapshotBackedReadWriteTransaction(nextIdentifier(), dataTree.takeSnapshot(), this);
}
@Override
public DOMStoreWriteTransaction newWriteOnlyTransaction() {
- return new SnapshotBackedWriteTransaction(nextIdentifier(), dataTree.takeSnapshot(), this, operationTree);
+ return new SnapshotBackedWriteTransaction(nextIdentifier(), dataTree.takeSnapshot(), this);
}
@Override
public synchronized void onGlobalContextUpdated(final SchemaContext ctx) {
- /*
- * Order of operations is important: dataTree may reject the context
- * and creation of ModificationApplyOperation may fail. So pre-construct
- * the operation, then update the data tree and then move the operation
- * into view.
- */
- final ModificationApplyOperation newOperationTree = SchemaAwareApplyOperationRoot.from(ctx);
dataTree.setSchemaContext(ctx);
- operationTree = newOperationTree;
}
@Override
return name + "-" + txCounter.getAndIncrement();
}
- private void commit(final DataTree.Snapshot currentSnapshot, final StoreMetadataNode newDataTree,
- final ResolveDataChangeEventsTask listenerResolver) {
- LOG.debug("Updating Store snaphot version: {} with version:{}", currentSnapshot, newDataTree.getSubtreeVersion());
-
- if (LOG.isTraceEnabled()) {
- LOG.trace("Data Tree is {}", StoreUtils.toStringTree(newDataTree.getData()));
- }
-
- /*
- * The commit has to occur atomically with regard to listener
- * registrations.
- */
- synchronized (this) {
- dataTree.commitSnapshot(currentSnapshot, newDataTree);
-
- for (ChangeListenerNotifyTask task : listenerResolver.call()) {
- LOG.trace("Scheduling invocation of listeners: {}", task);
- executor.submit(task);
- }
- }
- }
-
private static abstract class AbstractDOMStoreTransaction implements DOMStoreTransaction {
private final Object identifier;
}
private static final class SnapshotBackedReadTransaction extends AbstractDOMStoreTransaction implements
- DOMStoreReadTransaction {
- private DataTree.Snapshot stableSnapshot;
+ DOMStoreReadTransaction {
+ private DataTreeSnapshot stableSnapshot;
- public SnapshotBackedReadTransaction(final Object identifier, final DataTree.Snapshot snapshot) {
+ public SnapshotBackedReadTransaction(final Object identifier, final DataTreeSnapshot snapshot) {
super(identifier);
this.stableSnapshot = Preconditions.checkNotNull(snapshot);
LOG.debug("ReadOnly Tx: {} allocated with snapshot {}", identifier, snapshot);
}
private static class SnapshotBackedWriteTransaction extends AbstractDOMStoreTransaction implements
- DOMStoreWriteTransaction {
- private MutableDataTree mutableTree;
+ DOMStoreWriteTransaction {
+ private DataTreeModification mutableTree;
private InMemoryDOMDataStore store;
private boolean ready = false;
- public SnapshotBackedWriteTransaction(final Object identifier, final DataTree.Snapshot snapshot,
- final InMemoryDOMDataStore store, final ModificationApplyOperation applyOper) {
+ public SnapshotBackedWriteTransaction(final Object identifier, final DataTreeSnapshot snapshot,
+ final InMemoryDOMDataStore store) {
super(identifier);
- mutableTree = MutableDataTree.from(snapshot, applyOper);
+ mutableTree = snapshot.newModification();
this.store = store;
LOG.debug("Write Tx: {} allocated with snapshot {}", identifier, snapshot);
}
return store.submit(this);
}
- protected MutableDataTree getMutatedView() {
+ protected DataTreeModification getMutatedView() {
return mutableTree;
}
}
private static class SnapshotBackedReadWriteTransaction extends SnapshotBackedWriteTransaction implements
- DOMStoreReadWriteTransaction {
+ DOMStoreReadWriteTransaction {
- protected SnapshotBackedReadWriteTransaction(final Object identifier, final DataTree.Snapshot snapshot,
- final InMemoryDOMDataStore store, final ModificationApplyOperation applyOper) {
- super(identifier, snapshot, store, applyOper);
+ protected SnapshotBackedReadWriteTransaction(final Object identifier, final DataTreeSnapshot snapshot,
+ final InMemoryDOMDataStore store) {
+ super(identifier, snapshot, store);
}
@Override
public ListenableFuture<Optional<NormalizedNode<?, ?>>> read(final InstanceIdentifier path) {
LOG.trace("Tx: {} Read: {}", getIdentifier(), path);
try {
- return Futures.immediateFuture(getMutatedView().read(path));
+ return Futures.immediateFuture(getMutatedView().readNode(path));
} catch (Exception e) {
LOG.error("Tx: {} Failed Read of {}", getIdentifier(), path, e);
throw e;
private class ThreePhaseCommitImpl implements DOMStoreThreePhaseCommitCohort {
private final SnapshotBackedWriteTransaction transaction;
- private final NodeModification modification;
+ private final DataTreeModification modification;
- private DataTree.Snapshot storeSnapshot;
- private Optional<StoreMetadataNode> proposedSubtree;
private ResolveDataChangeEventsTask listenerResolver;
+ private DataTreeCandidate candidate;
public ThreePhaseCommitImpl(final SnapshotBackedWriteTransaction writeTransaction) {
this.transaction = writeTransaction;
- this.modification = transaction.getMutatedView().getRootModification();
+ this.modification = transaction.getMutatedView();
}
@Override
public ListenableFuture<Boolean> canCommit() {
- final DataTree.Snapshot snapshotCapture = dataTree.takeSnapshot();
- final ModificationApplyOperation snapshotOperation = operationTree;
-
return executor.submit(new Callable<Boolean>() {
-
@Override
- public Boolean call() throws Exception {
- Boolean applicable = false;
+ public Boolean call() {
try {
- snapshotOperation.checkApplicable(PUBLIC_ROOT_PATH, modification,
- Optional.of(snapshotCapture.getRootNode()));
- applicable = true;
+ dataTree.validate(modification);
+ LOG.debug("Store Transaction: {} can be committed", transaction.getIdentifier());
+ return true;
} catch (DataPreconditionFailedException e) {
LOG.warn("Store Tx: {} Data Precondition failed for {}.",transaction.getIdentifier(),e.getPath(),e);
- applicable = false;
+ return false;
}
- LOG.debug("Store Transaction: {} : canCommit : {}", transaction.getIdentifier(), applicable);
- return applicable;
}
});
}
@Override
public ListenableFuture<Void> preCommit() {
- storeSnapshot = dataTree.takeSnapshot();
- if (modification.getModificationType() == ModificationType.UNMODIFIED) {
- return Futures.immediateFuture(null);
- }
return executor.submit(new Callable<Void>() {
-
@Override
- public Void call() throws Exception {
- StoreMetadataNode metadataTree = storeSnapshot.getRootNode();
-
- proposedSubtree = operationTree.apply(modification, Optional.of(metadataTree),
- increase(metadataTree.getSubtreeVersion()));
-
- listenerResolver = ResolveDataChangeEventsTask.create() //
- .setRootPath(PUBLIC_ROOT_PATH) //
- .setBeforeRoot(Optional.of(metadataTree)) //
- .setAfterRoot(proposedSubtree) //
- .setModificationRoot(modification) //
- .setListenerRoot(listenerTree);
-
+ public Void call() {
+ candidate = dataTree.prepare(modification);
+ listenerResolver = ResolveDataChangeEventsTask.create(candidate, listenerTree);
return null;
}
});
@Override
public ListenableFuture<Void> abort() {
- storeSnapshot = null;
- proposedSubtree = null;
- return Futures.<Void> immediateFuture(null);
+ candidate = null;
+ return Futures.immediateFuture(null);
}
@Override
public ListenableFuture<Void> commit() {
- if (modification.getModificationType() == ModificationType.UNMODIFIED) {
- return Futures.immediateFuture(null);
+ checkState(candidate != null, "Proposed subtree must be computed");
+
+ /*
+ * The commit has to occur atomically with regard to listener
+ * registrations.
+ */
+ synchronized (this) {
+ dataTree.commit(candidate);
+
+ for (ChangeListenerNotifyTask task : listenerResolver.call()) {
+ LOG.trace("Scheduling invocation of listeners: {}", task);
+ executor.submit(task);
+ }
}
- checkState(proposedSubtree != null, "Proposed subtree must be computed");
- checkState(storeSnapshot != null, "Proposed subtree must be computed");
- // return ImmediateFuture<>;
- InMemoryDOMDataStore.this.commit(storeSnapshot, proposedSubtree.get(), listenerResolver);
- return Futures.<Void> immediateFuture(null);
- }
-
- }
-
- private static final class AlwaysFailOperation implements ModificationApplyOperation {
-
- @Override
- public Optional<StoreMetadataNode> apply(final NodeModification modification,
- final Optional<StoreMetadataNode> storeMeta, final UnsignedLong subtreeVersion) {
- throw new IllegalStateException("Schema Context is not available.");
+ return Futures.immediateFuture(null);
}
-
- @Override
- public void checkApplicable(final InstanceIdentifier path,final NodeModification modification, final Optional<StoreMetadataNode> storeMetadata) {
- throw new IllegalStateException("Schema Context is not available.");
- }
-
- @Override
- public Optional<ModificationApplyOperation> getChild(final PathArgument child) {
- throw new IllegalStateException("Schema Context is not available.");
- }
-
- @Override
- public void verifyStructure(final NodeModification modification) throws IllegalArgumentException {
- throw new IllegalStateException("Schema Context is not available.");
- }
-
}
}
package org.opendaylight.controller.md.sal.dom.store.impl;
import static org.opendaylight.controller.md.sal.dom.store.impl.DOMImmutableDataChangeEvent.builder;
-import static org.opendaylight.controller.md.sal.dom.store.impl.StoreUtils.append;
+import static org.opendaylight.controller.md.sal.dom.store.impl.tree.StoreUtils.append;
import java.util.Collection;
import java.util.Collections;
import org.opendaylight.controller.md.sal.common.api.data.AsyncDataBroker.DataChangeScope;
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.NodeModification;
-import org.opendaylight.controller.md.sal.dom.store.impl.tree.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;
import org.slf4j.LoggerFactory;
import com.google.common.base.Optional;
+import com.google.common.base.Preconditions;
import com.google.common.collect.HashMultimap;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.Iterables;
* </ul>
*
*/
-public class ResolveDataChangeEventsTask implements Callable<Iterable<ChangeListenerNotifyTask>> {
+final class ResolveDataChangeEventsTask implements Callable<Iterable<ChangeListenerNotifyTask>> {
private static final Logger LOG = LoggerFactory.getLogger(ResolveDataChangeEventsTask.class);
private static final DOMImmutableDataChangeEvent NO_CHANGE = builder(DataChangeScope.BASE).build();
- private InstanceIdentifier rootPath;
- private ListenerTree listenerRoot;
- private NodeModification modificationRoot;
- private Optional<StoreMetadataNode> beforeRoot;
- private Optional<StoreMetadataNode> afterRoot;
private final Multimap<ListenerTree.Node, DOMImmutableDataChangeEvent> events = HashMultimap.create();
+ private final DataTreeCandidate candidate;
+ private final ListenerTree listenerRoot;
- protected InstanceIdentifier getRootPath() {
- return rootPath;
- }
-
- protected ResolveDataChangeEventsTask setRootPath(final InstanceIdentifier rootPath) {
- this.rootPath = rootPath;
- return this;
- }
-
- protected ListenerTree getListenerRoot() {
- return listenerRoot;
- }
-
- protected ResolveDataChangeEventsTask setListenerRoot(final ListenerTree listenerRoot) {
- this.listenerRoot = listenerRoot;
- return this;
- }
-
- protected NodeModification getModificationRoot() {
- return modificationRoot;
- }
-
- protected ResolveDataChangeEventsTask setModificationRoot(final NodeModification modificationRoot) {
- this.modificationRoot = modificationRoot;
- return this;
- }
-
- protected Optional<StoreMetadataNode> getBeforeRoot() {
- return beforeRoot;
- }
-
- protected ResolveDataChangeEventsTask setBeforeRoot(final Optional<StoreMetadataNode> beforeRoot) {
- this.beforeRoot = beforeRoot;
- return this;
- }
-
- protected Optional<StoreMetadataNode> getAfterRoot() {
- return afterRoot;
- }
-
- protected ResolveDataChangeEventsTask setAfterRoot(final Optional<StoreMetadataNode> afterRoot) {
- this.afterRoot = afterRoot;
- return this;
+ public ResolveDataChangeEventsTask(DataTreeCandidate candidate, ListenerTree listenerTree) {
+ this.candidate = Preconditions.checkNotNull(candidate);
+ this.listenerRoot = Preconditions.checkNotNull(listenerTree);
}
/**
*/
@Override
public Iterable<ChangeListenerNotifyTask> call() {
- LOG.trace("Resolving events for {}", modificationRoot);
-
try (final Walker w = listenerRoot.getWalker()) {
- resolveAnyChangeEvent(rootPath, Collections.singleton(w.getRootNode()), modificationRoot, beforeRoot,
- afterRoot);
+ 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() {
- return new ResolveDataChangeEventsTask();
+ public static ResolveDataChangeEventsTask create(DataTreeCandidate candidate, ListenerTree listenerTree) {
+ return new ResolveDataChangeEventsTask(candidate, listenerTree);
}
}
--- /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;
+
+import com.google.common.base.Preconditions;
+
+public class DataPreconditionFailedException extends Exception {
+ private static final long serialVersionUID = 1L;
+ private final InstanceIdentifier path;
+
+ public DataPreconditionFailedException(final InstanceIdentifier path, final String message) {
+ super(message);
+ this.path = Preconditions.checkNotNull(path);
+ }
+
+ public DataPreconditionFailedException(final InstanceIdentifier path, final String message, final Throwable cause) {
+ super(message, cause);
+ this.path = Preconditions.checkNotNull(path);
+ }
+
+ public InstanceIdentifier getPath() {
+ return path;
+ }
+}
--- /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.model.api.SchemaContext;
+
+/**
+ * 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();
+
+ /**
+ * 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);
+
+ /**
+ * Validate whether a particular modification can be applied to the data tree.
+ */
+ void validate(DataTreeModification modification) throws DataPreconditionFailedException;
+
+ /**
+ * Prepare a modification for commit.
+ *
+ * @param modification
+ * @return candidate data tree
+ */
+ DataTreeCandidate prepare(DataTreeModification modification);
+
+ /**
+ * Commit a data tree candidate.
+ *
+ * @param candidate data tree candidate
+ */
+ void commit(DataTreeCandidate candidate);
+}
--- /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;
+
+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();
+}
--- /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;
+
+/**
+ * Factory interface for creating data trees.
+ */
+public interface DataTreeFactory {
+ /**
+ * Create a new data tree.
+ *
+ * @return A data tree instance.
+ */
+ DataTree create();
+}
--- /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;
+import org.opendaylight.yangtools.yang.data.api.schema.NormalizedNode;
+
+/**
+ * Class encapsulation of set of modifications to a base tree. This tree is backed
+ * by a read-only snapshot and tracks modifications on top of that. The modification
+ * has the ability to rebase itself to a new snapshot.
+ */
+public interface DataTreeModification extends DataTreeSnapshot {
+ void delete(InstanceIdentifier path);
+ void merge(InstanceIdentifier path, NormalizedNode<?, ?> data);
+ void write(InstanceIdentifier path, NormalizedNode<?, ?> data);
+ void seal();
+}
--- /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;
+import org.opendaylight.yangtools.yang.data.api.schema.NormalizedNode;
+
+import com.google.common.base.Optional;
+
+/**
+ * Read-only snapshot of a {@link DataTree}. The snapshot is stable and isolated,
+ * e.g. data tree changes occurring after the snapshot has been taken are not
+ * visible through the snapshot.
+ */
+public interface DataTreeSnapshot {
+ /**
+ * Read a particular node from the snapshot.
+ *
+ * @param path Path of the node
+ * @return Optional result encapsulating the presence and value of the node
+ */
+ Optional<NormalizedNode<?, ?>> readNode(InstanceIdentifier path);
+
+ /**
+ * Create a new data tree modification based on this snapshot, using the
+ * specified data application strategy.
+ *
+ * @param strategy data modification strategy
+ * @return A new data tree modification
+ */
+ DataTreeModification newModification();
+}
* 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;
+package org.opendaylight.controller.md.sal.dom.store.impl.tree;
import java.util.Set;
--- /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 org.opendaylight.controller.md.sal.dom.store.impl.tree.DataTreeCandidate;
+import org.opendaylight.yangtools.yang.data.api.InstanceIdentifier;
+
+import com.google.common.base.Preconditions;
+
+abstract class AbstractDataTreeCandidate implements DataTreeCandidate {
+ private final InstanceIdentifier rootPath;
+
+ protected AbstractDataTreeCandidate(final InstanceIdentifier rootPath) {
+ this.rootPath = Preconditions.checkNotNull(rootPath);
+ }
+
+ @Override
+ public final InstanceIdentifier getRootPath() {
+ return rootPath;
+ }
+
+}
--- /dev/null
+package org.opendaylight.controller.md.sal.dom.store.impl.tree.data;
+
+import org.opendaylight.yangtools.yang.data.api.InstanceIdentifier;
+import org.opendaylight.yangtools.yang.data.api.InstanceIdentifier.PathArgument;
+
+import com.google.common.base.Optional;
+import com.google.common.primitives.UnsignedLong;
+
+final class AlwaysFailOperation implements ModificationApplyOperation {
+
+ @Override
+ public Optional<StoreMetadataNode> apply(final NodeModification modification,
+ final Optional<StoreMetadataNode> storeMeta, final UnsignedLong subtreeVersion) {
+ throw new IllegalStateException("Schema Context is not available.");
+ }
+
+ @Override
+ public void checkApplicable(final InstanceIdentifier path,final NodeModification modification, final Optional<StoreMetadataNode> storeMetadata) {
+ throw new IllegalStateException("Schema Context is not available.");
+ }
+
+ @Override
+ public Optional<ModificationApplyOperation> getChild(final PathArgument child) {
+ throw new IllegalStateException("Schema Context is not available.");
+ }
+
+ @Override
+ public void verifyStructure(final NodeModification modification) throws IllegalArgumentException {
+ throw new IllegalStateException("Schema Context is not available.");
+ }
+}
\ No newline at end of file
--- /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 java.util.concurrent.locks.ReadWriteLock;
+import java.util.concurrent.locks.ReentrantReadWriteLock;
+
+import org.opendaylight.controller.md.sal.dom.store.impl.tree.DataPreconditionFailedException;
+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;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import com.google.common.base.Optional;
+import com.google.common.base.Preconditions;
+
+/**
+ * Read-only snapshot of the data tree.
+ */
+final class InMemoryDataTree implements DataTree {
+ private static final Logger LOG = LoggerFactory.getLogger(InMemoryDataTree.class);
+ private static final InstanceIdentifier PUBLIC_ROOT_PATH = InstanceIdentifier.builder().build();
+
+ private final ReadWriteLock rwLock = new ReentrantReadWriteLock(true);
+ private ModificationApplyOperation applyOper = new AlwaysFailOperation();
+ private SchemaContext currentSchemaContext;
+ private StoreMetadataNode rootNode;
+
+ public InMemoryDataTree(StoreMetadataNode rootNode, final SchemaContext schemaContext) {
+ this.rootNode = Preconditions.checkNotNull(rootNode);
+
+ if (schemaContext != null) {
+ // Also sets applyOper
+ setSchemaContext(schemaContext);
+ }
+ }
+
+ @Override
+ public synchronized void setSchemaContext(final SchemaContext newSchemaContext) {
+ Preconditions.checkNotNull(newSchemaContext);
+
+ LOG.info("Attepting to install schema context {}", newSchemaContext);
+
+ /*
+ * FIXME: we should walk the schema contexts, both current and new and see
+ * whether they are compatible here. Reject incompatible changes.
+ */
+
+ // Instantiate new apply operation, this still may fail
+ final ModificationApplyOperation newApplyOper = SchemaAwareApplyOperation.from(newSchemaContext);
+
+ // Ready to change the context now, make sure no operations are running
+ rwLock.writeLock().lock();
+ try {
+ this.applyOper = newApplyOper;
+ this.currentSchemaContext = newSchemaContext;
+ } finally {
+ rwLock.writeLock().unlock();
+ }
+ }
+
+ @Override
+ public InMemoryDataTreeSnapshot takeSnapshot() {
+ rwLock.readLock().lock();
+ try {
+ return new InMemoryDataTreeSnapshot(currentSchemaContext, rootNode, applyOper);
+ } finally {
+ rwLock.readLock().unlock();
+ }
+ }
+
+ @Override
+ public void validate(DataTreeModification modification) throws DataPreconditionFailedException {
+ Preconditions.checkArgument(modification instanceof InMemoryDataTreeModification, "Invalid modification class %s", modification.getClass());
+
+ final InMemoryDataTreeModification m = (InMemoryDataTreeModification)modification;
+ m.getStrategy().checkApplicable(PUBLIC_ROOT_PATH, m.getRootModification(), Optional.of(rootNode));
+ }
+
+ @Override
+ public synchronized DataTreeCandidate prepare(DataTreeModification modification) {
+ Preconditions.checkArgument(modification instanceof InMemoryDataTreeModification, "Invalid modification class %s", modification.getClass());
+
+ final InMemoryDataTreeModification m = (InMemoryDataTreeModification)modification;
+ final NodeModification root = m.getRootModification();
+
+ if (root.getModificationType() == ModificationType.UNMODIFIED) {
+ return new NoopDataTreeCandidate(PUBLIC_ROOT_PATH, root);
+ }
+
+ rwLock.writeLock().lock();
+ try {
+ // FIXME: rootNode needs to be a read-write snapshot here...
+ final Optional<StoreMetadataNode> newRoot = m.getStrategy().apply(m.getRootModification(), Optional.of(rootNode), StoreUtils.increase(rootNode.getSubtreeVersion()));
+ Preconditions.checkState(newRoot.isPresent(), "Apply strategy failed to produce root node");
+ return new InMemoryDataTreeCandidate(PUBLIC_ROOT_PATH, root, rootNode, newRoot.get());
+ } finally {
+ rwLock.writeLock().unlock();
+ }
+ }
+
+ @Override
+ public synchronized void commit(DataTreeCandidate candidate) {
+ if (candidate instanceof NoopDataTreeCandidate) {
+ return;
+ }
+
+ Preconditions.checkArgument(candidate instanceof InMemoryDataTreeCandidate, "Invalid candidate class %s", candidate.getClass());
+ final InMemoryDataTreeCandidate c = (InMemoryDataTreeCandidate)candidate;
+
+ LOG.debug("Updating Store snapshot version: {} with version:{}", rootNode.getSubtreeVersion(), c.getAfterRoot().getSubtreeVersion());
+
+ if (LOG.isTraceEnabled()) {
+ LOG.trace("Data Tree is {}", StoreUtils.toStringTree(c.getAfterRoot().getData()));
+ }
+
+ // Ready to change the context now, make sure no operations are running
+ rwLock.writeLock().lock();
+ try {
+ Preconditions.checkState(c.getBeforeRoot() == rootNode,
+ String.format("Store tree %s and candidate base %s differ.", rootNode, c.getBeforeRoot()));
+ this.rootNode = c.getAfterRoot();
+ } finally {
+ rwLock.writeLock().unlock();
+ }
+ }
+}
--- /dev/null
+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 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;
+ }
+}
--- /dev/null
+package org.opendaylight.controller.md.sal.dom.store.impl.tree.data;
+
+import org.opendaylight.controller.md.sal.dom.store.impl.tree.DataTreeFactory;
+import org.opendaylight.yangtools.yang.data.api.InstanceIdentifier.NodeIdentifier;
+import org.opendaylight.yangtools.yang.data.api.schema.NormalizedNode;
+import org.opendaylight.yangtools.yang.data.impl.schema.Builders;
+import org.opendaylight.yangtools.yang.model.api.SchemaContext;
+
+/**
+ * A factory for creating in-memory data trees.
+ */
+public final class InMemoryDataTreeFactory implements DataTreeFactory {
+ private static final InMemoryDataTreeFactory INSTANCE = new InMemoryDataTreeFactory();
+
+ private InMemoryDataTreeFactory() {
+ // Never instantiated externally
+ }
+
+ @Override
+ public InMemoryDataTree create() {
+ final NodeIdentifier root = new NodeIdentifier(SchemaContext.NAME);
+ final NormalizedNode<?, ?> data = Builders.containerBuilder().withNodeIdentifier(root).build();
+
+ return new InMemoryDataTree(StoreMetadataNode.createEmpty(data), null);
+ }
+
+ /**
+ * Get an instance of this factory. This method cannot fail.
+ *
+ * @return Data tree factory instance.
+ */
+ public static final InMemoryDataTreeFactory getInstance() {
+ return INSTANCE;
+ }
+}
* 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;
+package org.opendaylight.controller.md.sal.dom.store.impl.tree.data;
import static com.google.common.base.Preconditions.checkState;
import java.util.Map.Entry;
-import java.util.concurrent.atomic.AtomicBoolean;
+import java.util.concurrent.atomic.AtomicIntegerFieldUpdater;
-import org.opendaylight.controller.md.sal.dom.store.impl.tree.NodeModification;
-import org.opendaylight.controller.md.sal.dom.store.impl.tree.StoreMetadataNode;
+import org.opendaylight.controller.md.sal.dom.store.impl.tree.DataTreeModification;
+import org.opendaylight.controller.md.sal.dom.store.impl.tree.StoreUtils;
import org.opendaylight.controller.md.sal.dom.store.impl.tree.TreeNodeUtils;
import org.opendaylight.yangtools.yang.data.api.InstanceIdentifier;
import org.opendaylight.yangtools.yang.data.api.InstanceIdentifier.PathArgument;
import com.google.common.base.Optional;
import com.google.common.base.Preconditions;
-/*
- * FIXME: the thread safety of concurrent write/delete/read/seal operations
- * needs to be evaluated.
- */
-class MutableDataTree {
- private static final Logger LOG = LoggerFactory.getLogger(MutableDataTree.class);
- private final AtomicBoolean sealed = new AtomicBoolean();
+final class InMemoryDataTreeModification implements DataTreeModification {
+ private static final Logger LOG = LoggerFactory.getLogger(InMemoryDataTreeModification.class);
+
+ /*
+ * FIXME: the thread safety of concurrent write/delete/read/seal operations
+ * needs to be evaluated.
+ */
+ private static final AtomicIntegerFieldUpdater<InMemoryDataTreeModification> SEALED_UPDATER =
+ AtomicIntegerFieldUpdater.newUpdater(InMemoryDataTreeModification.class, "sealed");
+ private volatile int sealed = 0;
+
private final ModificationApplyOperation strategyTree;
- private final NodeModification rootModification;
- private final DataTree.Snapshot snapshot;
+ private final InMemoryDataTreeSnapshot snapshot;
+ private final NodeModification rootNode;
- private MutableDataTree(final DataTree.Snapshot snapshot, final ModificationApplyOperation strategyTree) {
+ InMemoryDataTreeModification(final InMemoryDataTreeSnapshot snapshot, final ModificationApplyOperation resolver) {
this.snapshot = Preconditions.checkNotNull(snapshot);
- this.strategyTree = Preconditions.checkNotNull(strategyTree);
- this.rootModification = NodeModification.createUnmodified(snapshot.getRootNode());
+ this.strategyTree = Preconditions.checkNotNull(resolver);
+ this.rootNode = NodeModification.createUnmodified(snapshot.getRootNode());
+ }
+
+ NodeModification getRootModification() {
+ return rootNode;
}
+ ModificationApplyOperation getStrategy() {
+ return strategyTree;
+ }
+
+ @Override
public void write(final InstanceIdentifier path, final NormalizedNode<?, ?> value) {
checkSealed();
resolveModificationFor(path).write(value);
}
+ @Override
public void merge(final InstanceIdentifier path, final NormalizedNode<?, ?> data) {
checkSealed();
mergeImpl(resolveModificationFor(path),data);
op.merge(data);
}
+ @Override
public void delete(final InstanceIdentifier path) {
checkSealed();
resolveModificationFor(path).delete();
}
- public Optional<NormalizedNode<?, ?>> read(final InstanceIdentifier path) {
- Entry<InstanceIdentifier, NodeModification> modification = TreeNodeUtils.findClosestsOrFirstMatch(rootModification, path, NodeModification.IS_TERMINAL_PREDICATE);
-
- Optional<StoreMetadataNode> result = resolveSnapshot(modification);
+ @Override
+ public Optional<NormalizedNode<?, ?>> readNode(final InstanceIdentifier path) {
+ /*
+ * 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,
}
private OperationWithModification resolveModificationFor(final InstanceIdentifier path) {
- NodeModification modification = rootModification;
+ NodeModification modification = rootNode;
// We ensure strategy is present.
ModificationApplyOperation operation = resolveModificationStrategy(path);
for (PathArgument pathArg : path.getPath()) {
return OperationWithModification.from(operation, modification);
}
- public static MutableDataTree from(final DataTree.Snapshot snapshot, final ModificationApplyOperation resolver) {
- return new MutableDataTree(snapshot, resolver);
- }
-
+ @Override
public void seal() {
- final boolean success = sealed.compareAndSet(false, true);
+ final boolean success = SEALED_UPDATER.compareAndSet(this, 0, 1);
Preconditions.checkState(success, "Attempted to seal an already-sealed Data Tree.");
- rootModification.seal();
+ rootNode.seal();
}
private void checkSealed() {
- checkState(!sealed.get(), "Data Tree is sealed. No further modifications allowed.");
+ checkState(sealed == 0, "Data Tree is sealed. No further modifications allowed.");
}
- protected NodeModification getRootModification() {
- return rootModification;
+ @Override
+ public String toString() {
+ return "MutableDataTree [modification=" + rootNode + "]";
}
@Override
- public String toString() {
- return "MutableDataTree [modification=" + rootModification + "]";
+ public DataTreeModification newModification() {
+ // FIXME: transaction chaining
+ throw new UnsupportedOperationException("Implement this as part of transaction chaining");
}
}
--- /dev/null
+package org.opendaylight.controller.md.sal.dom.store.impl.tree.data;
+
+import org.opendaylight.controller.md.sal.dom.store.impl.tree.DataTreeSnapshot;
+import org.opendaylight.yangtools.yang.data.api.InstanceIdentifier;
+import org.opendaylight.yangtools.yang.data.api.schema.NormalizedNode;
+import org.opendaylight.yangtools.yang.data.impl.schema.NormalizedNodeUtils;
+import org.opendaylight.yangtools.yang.model.api.SchemaContext;
+
+import com.google.common.base.Optional;
+import com.google.common.base.Preconditions;
+
+final class InMemoryDataTreeSnapshot implements DataTreeSnapshot {
+ private final ModificationApplyOperation applyOper;
+ private final SchemaContext schemaContext;
+ private final StoreMetadataNode rootNode;
+
+ InMemoryDataTreeSnapshot(final SchemaContext schemaContext, final StoreMetadataNode rootNode,
+ final ModificationApplyOperation applyOper) {
+ this.schemaContext = Preconditions.checkNotNull(schemaContext);
+ this.rootNode = Preconditions.checkNotNull(rootNode);
+ this.applyOper = Preconditions.checkNotNull(applyOper);
+ }
+
+ StoreMetadataNode getRootNode() {
+ return rootNode;
+ }
+
+ SchemaContext getSchemaContext() {
+ return schemaContext;
+ }
+
+ @Override
+ public Optional<NormalizedNode<?, ?>> readNode(final InstanceIdentifier path) {
+ return NormalizedNodeUtils.findNode(rootNode.getData(), path);
+ }
+
+ @Override
+ public InMemoryDataTreeModification newModification() {
+ return new InMemoryDataTreeModification(this, applyOper);
+ }
+
+ @Override
+ public String toString() {
+ return rootNode.getSubtreeVersion().toString();
+ }
+
+}
\ No newline at end of file
* 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;
+package org.opendaylight.controller.md.sal.dom.store.impl.tree.data;
-import org.opendaylight.controller.md.sal.dom.store.impl.tree.NodeModification;
-import org.opendaylight.controller.md.sal.dom.store.impl.tree.StoreMetadataNode;
+import org.opendaylight.controller.md.sal.dom.store.impl.tree.DataPreconditionFailedException;
import org.opendaylight.controller.md.sal.dom.store.impl.tree.StoreTreeNode;
import org.opendaylight.yangtools.yang.data.api.InstanceIdentifier;
import org.opendaylight.yangtools.yang.data.api.InstanceIdentifier.PathArgument;
*
*
*/
-public interface ModificationApplyOperation extends StoreTreeNode<ModificationApplyOperation> {
+interface ModificationApplyOperation extends StoreTreeNode<ModificationApplyOperation> {
/**
*
Optional<ModificationApplyOperation> getChild(PathArgument child);
/**
- *
- * Checks if provided node modification could be applied to current metadata node.
- *
- * @param modification Modification
- * @param current Metadata Node to which modification should be applied
- * @return true if modification is applicable
- * false if modification is no applicable
+ *
+ * Checks if provided node modification could be applied to current metadata node.
+ *
+ * @param modification Modification
+ * @param current Metadata Node to which modification should be applied
+ * @return true if modification is applicable
+ * false if modification is no applicable
* @throws DataPreconditionFailedException
- */
+ */
void checkApplicable(InstanceIdentifier path, NodeModification modification, Optional<StoreMetadataNode> current) throws DataPreconditionFailedException;
}
* 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;
+package org.opendaylight.controller.md.sal.dom.store.impl.tree.data;
import static com.google.common.base.Preconditions.checkState;
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;
import org.opendaylight.yangtools.yang.data.api.schema.NormalizedNode;
*
* This tree is lazily created and populated via {@link #modifyChild(PathArgument)}
* and {@link StoreMetadataNode} which represents original state {@link #getOriginal()}.
- *
*/
-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
*
* @return
*/
- public NormalizedNode<?, ?> getWritenValue() {
+ public NormalizedNode<?, ?> getWrittenValue() {
return value;
}
--- /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 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 {
+ 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;
+ }
+}
* 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;
+package org.opendaylight.controller.md.sal.dom.store.impl.tree.data;
-import org.opendaylight.controller.md.sal.dom.store.impl.tree.NodeModification;
-import org.opendaylight.controller.md.sal.dom.store.impl.tree.StoreMetadataNode;
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.primitives.UnsignedLong;
-public class OperationWithModification {
+final class OperationWithModification {
private final NodeModification modification;
* 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;
+package org.opendaylight.controller.md.sal.dom.store.impl.tree.data;
import static com.google.common.base.Preconditions.checkArgument;
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.ModificationType;
-import org.opendaylight.controller.md.sal.dom.store.impl.tree.NodeModification;
-import org.opendaylight.controller.md.sal.dom.store.impl.tree.StoreMetadataNode;
-import org.opendaylight.controller.md.sal.dom.store.impl.tree.StoreNodeCompositeBuilder;
+import org.opendaylight.controller.md.sal.dom.store.impl.tree.StoreUtils;
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 com.google.common.collect.ImmutableMap;
import com.google.common.primitives.UnsignedLong;
-public abstract class SchemaAwareApplyOperation implements ModificationApplyOperation {
+abstract class SchemaAwareApplyOperation implements ModificationApplyOperation {
public static SchemaAwareApplyOperation from(final DataSchemaNode schemaNode) {
if (schemaNode instanceof ContainerSchemaNode) {
public static SchemaAwareApplyOperation from(final DataNodeContainer resolvedTree,
final AugmentationTarget augSchemas, final AugmentationIdentifier identifier) {
AugmentationSchema augSchema = null;
- allAugments: for (AugmentationSchema potential : augSchemas.getAvailableAugmentations()) {
- boolean containsAll = true;
- for (DataSchemaNode child : potential.getChildNodes()) {
- if (identifier.getPossibleChildNames().contains(child.getQName())) {
- augSchema = potential;
- break allAugments;
+
+ 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);
}
@Override
public void verifyStructure(final NodeModification modification) throws IllegalArgumentException {
if (modification.getModificationType() == ModificationType.WRITE) {
- verifyWritenStructure(modification.getWritenValue());
+ verifyWrittenStructure(modification.getWrittenValue());
}
}
- protected abstract void verifyWritenStructure(NormalizedNode<?, ?> writenValue);
+ protected abstract void verifyWrittenStructure(NormalizedNode<?, ?> writtenValue);
@Override
public void checkApplicable(final InstanceIdentifier path,final NodeModification modification, final Optional<StoreMetadataNode> current) throws DataPreconditionFailedException {
protected abstract StoreMetadataNode applySubtreeChange(NodeModification modification,
StoreMetadataNode currentMeta, UnsignedLong subtreeVersion);
- public static abstract class ValueNodeModificationStrategy<T extends DataSchemaNode> extends
- SchemaAwareApplyOperation {
+ public static abstract class ValueNodeModificationStrategy<T extends DataSchemaNode> extends SchemaAwareApplyOperation {
private final T schema;
private final Class<? extends NormalizedNode<?, ?>> nodeClass;
}
@Override
- protected void verifyWritenStructure(final NormalizedNode<?, ?> writenValue) {
- checkArgument(nodeClass.isInstance(writenValue), "Node should must be of type %s", nodeClass);
+ protected void verifyWrittenStructure(final NormalizedNode<?, ?> writtenValue) {
+ checkArgument(nodeClass.isInstance(writtenValue), "Node should must be of type %s", nodeClass);
}
@Override
@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.getWritenValue()).build();
+ return StoreMetadataNode.builder(subtreeVersion).setSubtreeVersion(subtreeVersion)
+ .setData(modification.getWrittenValue()).build();
}
@Override
@SuppressWarnings("rawtypes")
@Override
- protected void verifyWritenStructure(final NormalizedNode<?, ?> writenValue) {
- checkArgument(nodeClass.isInstance(writenValue), "Node should must be of type %s", nodeClass);
- checkArgument(writenValue instanceof NormalizedNodeContainer);
- NormalizedNodeContainer writenCont = (NormalizedNodeContainer) writenValue;
- for (Object child : writenCont.getValue()) {
+ 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);
- NormalizedNode childNode = (NormalizedNode) child;
+
+ /*
+ * FIXME: fail-fast semantics:
+ *
+ * We can validate the data structure here, aborting the commit
+ * before it ever progresses to being committed.
+ */
}
}
protected StoreMetadataNode applyWrite(final NodeModification modification,
final Optional<StoreMetadataNode> currentMeta, final UnsignedLong subtreeVersion) {
- NormalizedNode<?, ?> newValue = modification.getWritenValue();
+ NormalizedNode<?, ?> newValue = modification.getWrittenValue();
final UnsignedLong nodeVersion;
if (currentMeta.isPresent()) {
nodeVersion = subtreeVersion;
}
- final StoreMetadataNode newValueMeta = StoreMetadataNode.createRecursively(newValue, nodeVersion, nodeVersion);
+ final StoreMetadataNode newValueMeta = StoreMetadataNode.createRecursively(newValue, nodeVersion);
if (!modification.hasAdditionalModifications()) {
return newValueMeta;
}
@SuppressWarnings("rawtypes")
NormalizedNodeContainerBuilder dataBuilder = createBuilder(newValue);
- StoreNodeCompositeBuilder builder = StoreNodeCompositeBuilder.from(dataBuilder) //
- .setNodeVersion(nodeVersion) //
+ StoreNodeCompositeBuilder builder = StoreNodeCompositeBuilder.create(nodeVersion, dataBuilder) //
.setSubtreeVersion(subtreeVersion);
return mutateChildren(modification.getModifications(), newValueMeta, builder, nodeVersion);
@SuppressWarnings("rawtypes")
NormalizedNodeContainerBuilder dataBuilder = createBuilder(currentMeta.getData());
- StoreNodeCompositeBuilder builder = StoreNodeCompositeBuilder.from(dataBuilder, currentMeta)
- .setIdentifier(modification.getIdentifier()).setNodeVersion(currentMeta.getNodeVersion())
+ StoreNodeCompositeBuilder builder = StoreNodeCompositeBuilder.create(dataBuilder, currentMeta)
+ .setIdentifier(modification.getIdentifier())
.setSubtreeVersion(updatedSubtreeVersion);
return mutateChildren(modification.getModifications(), currentMeta, builder, updatedSubtreeVersion);
protected abstract NormalizedNodeContainerBuilder createBuilder(NormalizedNode<?, ?> original);
}
- public static abstract class DataNodeContainerModificationStrategy<T extends DataNodeContainer> extends
- NormalizedNodeContainerModificationStrategy {
+ public static abstract class DataNodeContainerModificationStrategy<T extends DataNodeContainer> extends NormalizedNodeContainerModificationStrategy {
private final T schema;
private final LoadingCache<PathArgument, ModificationApplyOperation> childCache = CacheBuilder.newBuilder()
}
- public static class ContainerModificationStrategy extends
- DataNodeContainerModificationStrategy<ContainerSchemaNode> {
+ public static class ContainerModificationStrategy extends DataNodeContainerModificationStrategy<ContainerSchemaNode> {
public ContainerModificationStrategy(final ContainerSchemaNode schemaNode) {
super(schemaNode, ContainerNode.class);
}
}
- public static class UnkeyedListItemModificationStrategy extends
- DataNodeContainerModificationStrategy<ListSchemaNode> {
+ public static class UnkeyedListItemModificationStrategy extends DataNodeContainerModificationStrategy<ListSchemaNode> {
public UnkeyedListItemModificationStrategy(final ListSchemaNode schemaNode) {
super(schemaNode, UnkeyedListEntryNode.class);
}
}
- public static class AugmentationModificationStrategy extends
- DataNodeContainerModificationStrategy<AugmentationSchema> {
+ public static class AugmentationModificationStrategy extends DataNodeContainerModificationStrategy<AugmentationSchema> {
protected AugmentationModificationStrategy(final AugmentationSchema schema, final DataNodeContainer resolved) {
super(createAugmentProxy(schema,resolved), AugmentationNode.class);
public static class ChoiceModificationStrategy extends NormalizedNodeContainerModificationStrategy {
- private final ChoiceNode schema;
private final Map<PathArgument, ModificationApplyOperation> childNodes;
public ChoiceModificationStrategy(final ChoiceNode schemaNode) {
super(org.opendaylight.yangtools.yang.data.api.schema.ChoiceNode.class);
- this.schema = schemaNode;
ImmutableMap.Builder<PathArgument, ModificationApplyOperation> child = ImmutableMap.builder();
for (ChoiceCaseNode caze : schemaNode.getCases()) {
@Override
protected StoreMetadataNode applyWrite(final NodeModification modification,
final Optional<StoreMetadataNode> currentMeta, final UnsignedLong subtreeVersion) {
- return StoreMetadataNode.createRecursively(modification.getWritenValue(), subtreeVersion);
+ return StoreMetadataNode.createRecursively(modification.getWrittenValue(), subtreeVersion);
}
@Override
}
@Override
- protected void verifyWritenStructure(final NormalizedNode<?, ?> writenValue) {
+ protected void verifyWrittenStructure(final NormalizedNode<?, ?> writtenValue) {
}
}
}
- public void verifyIdentifier(final PathArgument identifier) {
-
- }
-
public static AugmentationSchema createAugmentProxy(final AugmentationSchema schema, final DataNodeContainer resolved) {
Set<DataSchemaNode> realChildSchemas = new HashSet<>();
for(DataSchemaNode augChild : schema.getChildNodes()) {
* 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;
+package org.opendaylight.controller.md.sal.dom.store.impl.tree.data;
import static com.google.common.base.Preconditions.checkState;
import com.google.common.base.Preconditions;
import com.google.common.primitives.UnsignedLong;
-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);
- }
}
* 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;
+package org.opendaylight.controller.md.sal.dom.store.impl.tree.data;
import org.opendaylight.yangtools.yang.data.api.InstanceIdentifier.PathArgument;
import org.opendaylight.yangtools.yang.data.impl.schema.builder.api.NormalizedNodeContainerBuilder;
*
*/
@SuppressWarnings("rawtypes")
-public class StoreNodeCompositeBuilder {
+class StoreNodeCompositeBuilder {
private final StoreMetadataNode.Builder metadata;
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;
package org.opendaylight.controller.sal.dom.broker
import java.util.Hashtable
+import org.opendaylight.controller.md.sal.dom.api.DOMDataBroker
+import org.opendaylight.controller.md.sal.dom.broker.impl.compat.BackwardsCompatibleDataBroker
+import org.opendaylight.controller.sal.core.api.RpcProvisionRegistry
import org.opendaylight.controller.sal.core.api.data.DataBrokerService
import org.opendaylight.controller.sal.core.api.data.DataProviderService
import org.opendaylight.controller.sal.core.api.data.DataStore
import org.opendaylight.controller.sal.core.api.model.SchemaService
-import org.opendaylight.yangtools.yang.model.api.SchemaServiceListener
import org.opendaylight.controller.sal.core.api.mount.MountProvisionService
import org.opendaylight.controller.sal.core.api.mount.MountService
import org.opendaylight.controller.sal.dom.broker.impl.SchemaAwareDataStoreAdapter
import org.opendaylight.controller.sal.dom.broker.impl.SchemaAwareRpcBroker
+import org.opendaylight.controller.sal.dom.broker.impl.SchemaContextProviders
import org.opendaylight.yangtools.yang.data.api.InstanceIdentifier
+import org.opendaylight.yangtools.yang.model.api.SchemaServiceListener
import org.osgi.framework.BundleContext
import org.osgi.framework.ServiceRegistration
-import org.opendaylight.controller.sal.dom.broker.impl.SchemaContextProviders
-import org.opendaylight.controller.sal.core.api.RpcProvisionRegistry
-import org.opendaylight.controller.md.sal.dom.broker.impl.compat.BackwardsCompatibleDataBroker
-import org.opendaylight.controller.md.sal.dom.broker.impl.DOMDataBrokerImpl
-import com.google.common.util.concurrent.MoreExecutors
-import com.google.common.collect.ImmutableMap
-import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType
-import org.opendaylight.controller.sal.core.spi.data.DOMStore
-import org.opendaylight.controller.md.sal.dom.store.impl.InMemoryDOMDataStore
-import java.util.concurrent.Executors
-import org.opendaylight.controller.md.sal.dom.api.DOMDataBroker
class BrokerConfigActivator implements AutoCloseable {
-package org.opendaylight.controller.md.sal.dom.store.impl;
+/*
+ * 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 org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import org.junit.Before;
import org.junit.Test;
-import org.opendaylight.controller.md.sal.dom.store.impl.tree.StoreMetadataNode;
+import org.opendaylight.controller.md.sal.dom.store.impl.TestModel;
+import org.opendaylight.controller.md.sal.dom.store.impl.tree.DataTree;
+import org.opendaylight.controller.md.sal.dom.store.impl.tree.DataTreeModification;
import org.opendaylight.yangtools.yang.data.api.InstanceIdentifier;
import org.opendaylight.yangtools.yang.data.api.InstanceIdentifier.NodeIdentifier;
import org.opendaylight.yangtools.yang.data.api.schema.ContainerNode;
.withChild(mapEntry(INNER_LIST_QNAME, NAME_QNAME, TWO_ONE_NAME)) //
.withChild(mapEntry(INNER_LIST_QNAME, NAME_QNAME, TWO_TWO_NAME)) //
.build()) //
- .build();
+ .build();
private SchemaContext schemaContext;
+ private ModificationApplyOperation applyOper;
@Before
public void prepare() {
schemaContext = TestModel.createTestContext();
assertNotNull("Schema context must not be null.", schemaContext);
+ applyOper = SchemaAwareApplyOperation.from(schemaContext);
}
/**
.withNodeIdentifier(new NodeIdentifier(TEST_QNAME))
.withChild(
mapNodeBuilder(OUTER_LIST_QNAME)
- .withChild(mapEntry(OUTER_LIST_QNAME, ID_QNAME, ONE_ID))
- .withChild(BAR_NODE).build()).build();
+ .withChild(mapEntry(OUTER_LIST_QNAME, ID_QNAME, ONE_ID))
+ .withChild(BAR_NODE).build()).build();
}
@Test
public void basicReadWrites() {
- MutableDataTree modificationTree = MutableDataTree.from(new DataTree.Snapshot(schemaContext,
- StoreMetadataNode.createRecursively(createDocumentOne(), UnsignedLong.valueOf(5))),
+ DataTreeModification modificationTree = new InMemoryDataTreeModification(new InMemoryDataTreeSnapshot(schemaContext,
+ StoreMetadataNode.createRecursively(createDocumentOne(), UnsignedLong.valueOf(5)), applyOper),
new SchemaAwareApplyOperationRoot(schemaContext));
- Optional<NormalizedNode<?, ?>> originalBarNode = modificationTree.read(OUTER_LIST_2_PATH);
+ Optional<NormalizedNode<?, ?>> originalBarNode = modificationTree.readNode(OUTER_LIST_2_PATH);
assertTrue(originalBarNode.isPresent());
assertSame(BAR_NODE, originalBarNode.get());
// reads node to /outer-list/1/inner_list/two/value
// and checks if node is already present
- Optional<NormalizedNode<?, ?>> barTwoCModified = modificationTree.read(TWO_TWO_VALUE_PATH);
+ Optional<NormalizedNode<?, ?>> barTwoCModified = modificationTree.readNode(TWO_TWO_VALUE_PATH);
assertTrue(barTwoCModified.isPresent());
assertEquals(ImmutableNodes.leafNode(VALUE_QNAME, "test"), barTwoCModified.get());
// delete node to /outer-list/1/inner_list/two/value
modificationTree.delete(TWO_TWO_VALUE_PATH);
- Optional<NormalizedNode<?, ?>> barTwoCAfterDelete = modificationTree.read(TWO_TWO_VALUE_PATH);
+ Optional<NormalizedNode<?, ?>> barTwoCAfterDelete = modificationTree.readNode(TWO_TWO_VALUE_PATH);
assertFalse(barTwoCAfterDelete.isPresent());
}
- public MutableDataTree createEmptyModificationTree() {
+ public DataTreeModification createEmptyModificationTree() {
/**
* Creates empty Snapshot with associated schema context.
*/
- DataTree t = DataTree.create(schemaContext);
+ DataTree t = InMemoryDataTreeFactory.getInstance().create();
+ t.setSchemaContext(schemaContext);
/**
*
* context.
*
*/
- MutableDataTree modificationTree = MutableDataTree.from(t.takeSnapshot(), new SchemaAwareApplyOperationRoot(
- schemaContext));
- return modificationTree;
+ return t.takeSnapshot().newModification();
}
@Test
public void createFromEmptyState() {
- MutableDataTree modificationTree = createEmptyModificationTree();
+ DataTreeModification modificationTree = createEmptyModificationTree();
/**
* Writes empty container node to /test
*
/**
* Reads list node from /test/outer-list
*/
- Optional<NormalizedNode<?, ?>> potentialOuterList = modificationTree.read(OUTER_LIST_PATH);
+ Optional<NormalizedNode<?, ?>> potentialOuterList = modificationTree.readNode(OUTER_LIST_PATH);
assertTrue(potentialOuterList.isPresent());
/**
* Reads container node from /test and verifies that it contains test
* node
*/
- Optional<NormalizedNode<?, ?>> potentialTest = modificationTree.read(TEST_PATH);
+ Optional<NormalizedNode<?, ?>> potentialTest = modificationTree.readNode(TEST_PATH);
ContainerNode containerTest = assertPresentAndType(potentialTest, ContainerNode.class);
/**
@Test
public void writeSubtreeReadChildren() {
- MutableDataTree modificationTree = createEmptyModificationTree();
+ DataTreeModification modificationTree = createEmptyModificationTree();
modificationTree.write(TEST_PATH, createTestContainer());
- Optional<NormalizedNode<?, ?>> potential = modificationTree.read(TWO_TWO_PATH);
- MapEntryNode node = assertPresentAndType(potential, MapEntryNode.class);
+ Optional<NormalizedNode<?, ?>> potential = modificationTree.readNode(TWO_TWO_PATH);
+ assertPresentAndType(potential, MapEntryNode.class);
}
@Test
public void writeSubtreeDeleteChildren() {
- MutableDataTree modificationTree = createEmptyModificationTree();
+ DataTreeModification modificationTree = createEmptyModificationTree();
modificationTree.write(TEST_PATH, createTestContainer());
// We verify data are present
- Optional<NormalizedNode<?, ?>> potentialBeforeDelete = modificationTree.read(TWO_TWO_PATH);
- MapEntryNode node = assertPresentAndType(potentialBeforeDelete, MapEntryNode.class);
+ Optional<NormalizedNode<?, ?>> potentialBeforeDelete = modificationTree.readNode(TWO_TWO_PATH);
+ assertPresentAndType(potentialBeforeDelete, MapEntryNode.class);
modificationTree.delete(TWO_TWO_PATH);
- Optional<NormalizedNode<?, ?>> potentialAfterDelete = modificationTree.read(TWO_TWO_PATH);
+ Optional<NormalizedNode<?, ?>> potentialAfterDelete = modificationTree.readNode(TWO_TWO_PATH);
assertFalse(potentialAfterDelete.isPresent());
}
* 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;
+package org.opendaylight.controller.md.sal.dom.store.impl.tree.data;
import org.opendaylight.yangtools.yang.data.api.schema.ContainerNode;
import org.opendaylight.yangtools.yang.data.api.schema.NormalizedNode;
import java.io.InputStream;
import java.net.InetAddress;
import java.net.InetSocketAddress;
+import java.net.URI;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
+import org.opendaylight.controller.md.sal.common.api.data.DataChangeEvent;
import org.opendaylight.controller.netconf.client.NetconfClientDispatcher;
import org.opendaylight.controller.netconf.client.NetconfClientDispatcherImpl;
import org.opendaylight.controller.netconf.client.conf.NetconfClientConfiguration;
import org.opendaylight.controller.netconf.client.conf.NetconfReconnectingClientConfigurationBuilder;
import org.opendaylight.controller.netconf.nettyutil.handler.ssh.authentication.LoginPassword;
import org.opendaylight.controller.sal.binding.api.data.DataProviderService;
+import org.opendaylight.controller.sal.connect.netconf.InventoryUtils;
import org.opendaylight.controller.sal.connect.netconf.NetconfDevice;
import org.opendaylight.controller.sal.connect.netconf.NetconfDeviceListener;
+import org.opendaylight.controller.sal.core.api.data.DataChangeListener;
import org.opendaylight.protocol.framework.ReconnectStrategy;
import org.opendaylight.protocol.framework.ReconnectStrategyFactory;
import org.opendaylight.protocol.framework.TimedReconnectStrategy;
import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.nodes.Node;
import org.opendaylight.yang.gen.v1.urn.opendaylight.netconf.node.inventory.rev140108.NetconfNode;
import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
+import org.opendaylight.yangtools.yang.common.QName;
+import org.opendaylight.yangtools.yang.data.api.CompositeNode;
import org.opendaylight.yangtools.yang.model.util.repo.AbstractCachingSchemaSourceProvider;
import org.opendaylight.yangtools.yang.model.util.repo.FilesystemSchemaCachingProvider;
import org.opendaylight.yangtools.yang.model.util.repo.SchemaSourceProvider;
* @param routeId route identifier
* @return remote network address
*/
- private String lookupRemoteAddressForGlobalRpc(RpcRouter.RouteIdentifier routeId){
+ private String lookupRemoteAddressForGlobalRpc(RpcRouter.RouteIdentifier<?, ?, ?> routeId){
checkNotNull(routeId, "route must not be null");
- Optional<RoutingTable<RpcRouter.RouteIdentifier, String>> routingTable = routingTableProvider.getRoutingTable();
+ Optional<RoutingTable<RpcRouter.RouteIdentifier<?, ?, ?>, String>> routingTable = routingTableProvider.getRoutingTable();
checkNotNull(routingTable.isPresent(), "Routing table is null");
String address = null;
* @param routeId route identifier
* @return remote network address
*/
- private String lookupRemoteAddressForRpc(RpcRouter.RouteIdentifier routeId){
+ private String lookupRemoteAddressForRpc(RpcRouter.RouteIdentifier<?, ?, ?> routeId){
checkNotNull(routeId, "route must not be null");
- Optional<RoutingTable<RpcRouter.RouteIdentifier, String>> routingTable = routingTableProvider.getRoutingTable();
+ Optional<RoutingTable<RpcRouter.RouteIdentifier<?, ?, ?>, String>> routingTable = routingTableProvider.getRoutingTable();
checkNotNull(routingTable.isPresent(), "Routing table is null");
String address = routingTable.get().getLastAddedRoute(routeId);
*/
private void closeZmqContext() {
ExecutorService exec = Executors.newSingleThreadExecutor();
- FutureTask zmqTermination = new FutureTask(new Runnable() {
+ FutureTask<?> zmqTermination = new FutureTask<Void>(new Runnable() {
@Override
public void run() {
package org.opendaylight.controller.sal.connector.remoterpc;
-import org.zeromq.ZMQ;
-
import java.net.Inet4Address;
import java.net.InetAddress;
import java.net.NetworkInterface;
import java.net.SocketException;
import java.util.Enumeration;
+import org.zeromq.ZMQ;
+
/**
* Provides a ZeroMQ Context object
*/
public class Context {
- private ZMQ.Context zmqContext = ZMQ.context(1);
+ private final ZMQ.Context zmqContext = ZMQ.context(1);
private String uri;
private final String DEFAULT_RPC_PORT = "5554";
*/
private String findIpAddress() {
String hostAddress = null;
- Enumeration e = null;
+ Enumeration<?> e = null;
try {
e = NetworkInterface.getNetworkInterfaces();
} catch (SocketException e1) {
NetworkInterface n = (NetworkInterface) e.nextElement();
- Enumeration ee = n.getInetAddresses();
+ Enumeration<?> ee = n.getInetAddresses();
while (ee.hasMoreElements()) {
InetAddress i = (InetAddress) ee.nextElement();
if ((i instanceof Inet4Address) && (i.isSiteLocalAddress()))
package org.opendaylight.controller.sal.connector.remoterpc;
-import org.opendaylight.controller.sal.core.api.RpcImplementation;
-import org.opendaylight.controller.sal.core.api.RoutedRpcDefaultImplementation;
-
public interface RemoteRpcClient extends AutoCloseable{
void setRoutingTableProvider(RoutingTableProvider provider);
-
+
void stop();
-
+
void start();
}
private ProviderSession brokerSession;
private RpcProvisionRegistry rpcProvisionRegistry;
private BundleContext context;
- private ServiceTracker clusterTracker;
+ private ServiceTracker<?, ?> clusterTracker;
public RemoteRpcProvider(ServerImpl server, ClientImpl client) {
this.server = server;
}
- private RoutingTable<RpcRouter.RouteIdentifier, String> getRoutingTable(){
- Optional<RoutingTable<RpcRouter.RouteIdentifier, String>> routingTable =
+ private RoutingTable<RpcRouter.RouteIdentifier<?, ?, ?>, String> getRoutingTable(){
+ Optional<RoutingTable<RpcRouter.RouteIdentifier<?, ?, ?>, String>> routingTable =
routingTableProvider.getRoutingTable();
checkState(routingTable.isPresent(), "Routing table is null");
RouteIdentifierImpl routeId = new RouteIdentifierImpl();
routeId.setType(rpc);
- RoutingTable<RpcRouter.RouteIdentifier, String> routingTable = getRoutingTable();
+ RoutingTable<RpcRouter.RouteIdentifier<?, ?, ?>, String> routingTable = getRoutingTable();
try {
routingTable.addGlobalRoute(routeId, server.getServerAddress());
RouteIdentifierImpl routeId = new RouteIdentifierImpl();
routeId.setType(rpc);
- RoutingTable<RpcRouter.RouteIdentifier, String> routingTable = getRoutingTable();
+ RoutingTable<RpcRouter.RouteIdentifier<?, ?, ?>, String> routingTable = getRoutingTable();
try {
routingTable.removeGlobalRoute(routeId);
*
* @param announcements
*/
- private void announce(Set<RpcRouter.RouteIdentifier> announcements) {
+ private void announce(Set<RpcRouter.RouteIdentifier<?, ?, ?>> announcements) {
_logger.debug("Announcing [{}]", announcements);
- RoutingTable<RpcRouter.RouteIdentifier, String> routingTable = getRoutingTable();
+ RoutingTable<RpcRouter.RouteIdentifier<?, ?, ?>, String> routingTable = getRoutingTable();
try {
routingTable.addRoutes(announcements, server.getServerAddress());
} catch (RoutingTableException | SystemException e) {
*
* @param removals
*/
- private void remove(Set<RpcRouter.RouteIdentifier> removals){
+ private void remove(Set<RpcRouter.RouteIdentifier<?, ?, ?>> removals){
_logger.debug("Removing [{}]", removals);
- RoutingTable<RpcRouter.RouteIdentifier, String> routingTable = getRoutingTable();
+ RoutingTable<RpcRouter.RouteIdentifier<?, ?, ?>, String> routingTable = getRoutingTable();
try {
routingTable.removeRoutes(removals, server.getServerAddress());
} catch (RoutingTableException | SystemException e) {
* @param changes
* @return
*/
- private Set<RpcRouter.RouteIdentifier> getRouteIdentifiers(Map<RpcRoutingContext, Set<InstanceIdentifier>> changes) {
+ private Set<RpcRouter.RouteIdentifier<?, ?, ?>> getRouteIdentifiers(Map<RpcRoutingContext, Set<InstanceIdentifier>> changes) {
RouteIdentifierImpl routeId = null;
- Set<RpcRouter.RouteIdentifier> routeIdSet = new HashSet<RpcRouter.RouteIdentifier>();
+ Set<RpcRouter.RouteIdentifier<?, ?, ?>> routeIdSet = new HashSet<>();
for (RpcRoutingContext context : changes.keySet()){
routeId = new RouteIdentifierImpl();
package org.opendaylight.controller.sal.connector.remoterpc;
-import com.google.common.base.Optional;
import org.opendaylight.controller.sal.connector.api.RpcRouter;
-import org.opendaylight.controller.sal.connector.remoterpc.api.RouteChangeListener;
import org.opendaylight.controller.sal.connector.remoterpc.api.RoutingTable;
-import org.opendaylight.controller.sal.connector.remoterpc.dto.RouteIdentifierImpl;
import org.opendaylight.controller.sal.connector.remoterpc.impl.RoutingTableImpl;
import org.osgi.framework.BundleContext;
import org.osgi.util.tracker.ServiceTracker;
+import com.google.common.base.Optional;
+
public class RoutingTableProvider implements AutoCloseable {
@SuppressWarnings("rawtypes")
final ServiceTracker<RoutingTable,RoutingTable> tracker;
- private RoutingTableImpl routingTableImpl = null;
+ private RoutingTableImpl<?, ?> routingTableImpl = null;
//final private RouteChangeListener routeChangeListener;
-
-
+
+
public RoutingTableProvider(BundleContext ctx){//,RouteChangeListener rcl) {
@SuppressWarnings("rawtypes")
ServiceTracker<RoutingTable, RoutingTable> rawTracker = new ServiceTracker<>(ctx, RoutingTable.class, null);
//routeChangeListener = rcl;
}
-
- public Optional<RoutingTable<RpcRouter.RouteIdentifier, String>> getRoutingTable() {
+
+ public Optional<RoutingTable<RpcRouter.RouteIdentifier<?, ?, ?>, String>> getRoutingTable() {
@SuppressWarnings("unchecked")
- RoutingTable<RpcRouter.RouteIdentifier,String> tracked = tracker.getService();
+ RoutingTable<RpcRouter.RouteIdentifier<?, ?, ?>, String> tracked = tracker.getService();
if(tracked instanceof RoutingTableImpl){
if(routingTableImpl != tracked){
- routingTableImpl= (RoutingTableImpl)tracked;
+ routingTableImpl= (RoutingTableImpl<?, ?>)tracked;
//routingTableImpl.setRouteChangeListener(routeChangeListener);
}
}
*/
package org.opendaylight.controller.sal.connector.remoterpc;
-import com.google.common.base.Optional;
-import com.google.common.base.Preconditions;
-import com.google.common.base.Predicate;
-import com.google.common.collect.Sets;
-import org.opendaylight.controller.md.sal.common.api.routing.RouteChange;
-import org.opendaylight.controller.sal.connector.remoterpc.api.RouteChangeListener;
-import org.opendaylight.controller.sal.connector.remoterpc.api.RoutingTable;
-import org.opendaylight.controller.sal.connector.remoterpc.api.RoutingTableException;
-import org.opendaylight.controller.sal.connector.remoterpc.api.SystemException;
-import org.opendaylight.controller.sal.connector.remoterpc.dto.RouteIdentifierImpl;
-import org.opendaylight.controller.sal.core.api.Broker.ProviderSession;
-import org.opendaylight.controller.sal.core.api.RpcProvisionRegistry;
-import org.opendaylight.controller.sal.core.api.RpcRegistrationListener;
-import org.opendaylight.controller.sal.core.api.RpcRoutingContext;
-import org.opendaylight.yangtools.yang.common.QName;
-import org.opendaylight.yangtools.yang.data.api.InstanceIdentifier;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-import org.zeromq.ZMQ;
-
import java.net.Inet4Address;
import java.net.InetAddress;
import java.net.NetworkInterface;
import java.net.SocketException;
import java.util.Enumeration;
import java.util.HashSet;
-import java.util.Map;
import java.util.Set;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.FutureTask;
import java.util.concurrent.TimeUnit;
-import static com.google.common.base.Preconditions.checkNotNull;
-import static com.google.common.base.Preconditions.checkState;
+import org.opendaylight.controller.sal.core.api.Broker.ProviderSession;
+import org.opendaylight.yangtools.yang.common.QName;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.zeromq.ZMQ;
+
+import com.google.common.base.Optional;
+import com.google.common.base.Preconditions;
/**
* ZeroMq based implementation of RpcRouter.
*/
public class ServerImpl implements RemoteRpcServer {
- private Logger _logger = LoggerFactory.getLogger(ServerImpl.class);
+ private final Logger _logger = LoggerFactory.getLogger(ServerImpl.class);
private ExecutorService serverPool;
protected ServerRequestHandler handler;
private volatile State status = State.STOPPED;
private String serverAddress;
- private int port;
+ private final int port;
public static enum State {
STARTING, STARTED, STOPPED;
*/
private void closeZmqContext() {
ExecutorService exec = Executors.newSingleThreadExecutor();
- FutureTask zmqTermination = new FutureTask(new Runnable() {
+ FutureTask<?> zmqTermination = new FutureTask<Void>(new Runnable() {
@Override
public void run() {
* @return
*/
private String findIpAddress() {
- Enumeration e = null;
+ Enumeration<?> e = null;
try {
e = NetworkInterface.getNetworkInterfaces();
} catch (SocketException e1) {
NetworkInterface n = (NetworkInterface) e.nextElement();
- Enumeration ee = n.getInetAddresses();
+ Enumeration<?> ee = n.getInetAddresses();
while (ee.hasMoreElements()) {
InetAddress i = (InetAddress) ee.nextElement();
_logger.debug("Trying address {}", i);
package org.opendaylight.controller.sal.connector.remoterpc;
+import java.io.IOException;
+import java.io.PrintWriter;
+import java.io.StringWriter;
+import java.util.concurrent.BlockingQueue;
+import java.util.concurrent.Future;
+import java.util.concurrent.LinkedBlockingQueue;
+import java.util.concurrent.ThreadPoolExecutor;
+import java.util.concurrent.TimeUnit;
+import java.util.concurrent.atomic.AtomicInteger;
+
import org.opendaylight.controller.sal.connector.api.RpcRouter;
import org.opendaylight.controller.sal.connector.remoterpc.dto.Message;
-import org.opendaylight.controller.sal.connector.remoterpc.dto.RouteIdentifierImpl;
import org.opendaylight.controller.sal.connector.remoterpc.util.XmlUtils;
import org.opendaylight.controller.sal.core.api.Broker;
import org.opendaylight.yangtools.yang.common.QName;
-import org.opendaylight.yangtools.yang.common.RpcError;
import org.opendaylight.yangtools.yang.common.RpcResult;
import org.opendaylight.yangtools.yang.data.api.CompositeNode;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.zeromq.ZMQ;
-import java.io.IOException;
-import java.io.PrintWriter;
-import java.io.StringWriter;
-import java.util.Collection;
-import java.util.concurrent.*;
-import java.util.concurrent.atomic.AtomicInteger;
-
/**
*
*/
public class ServerRequestHandler implements AutoCloseable{
- private Logger _logger = LoggerFactory.getLogger(ServerRequestHandler.class);
+ private final Logger _logger = LoggerFactory.getLogger(ServerRequestHandler.class);
private final String DEFAULT_NAME = "remote-rpc-worker";
- private String dealerAddress;
- private String serverAddress;
- private int workerCount;
- private ZMQ.Context context;
- private Broker.ProviderSession broker;
+ private final String dealerAddress;
+ private final String serverAddress;
+ private final int workerCount;
+ private final ZMQ.Context context;
+ private final Broker.ProviderSession broker;
private RequestHandlerThreadPool workerPool;
private final AtomicInteger threadId = new AtomicInteger();
* Worker to handles RPC request
*/
private class Worker implements Runnable {
- private String name;
+ private final String name;
public Worker(int id){
this.name = DEFAULT_NAME + "-" + id;
}
class MessageHandler{
- private ZMQ.Socket socket;
+ private final ZMQ.Socket socket;
private Message message; //parsed message received on zmq server port
private boolean messageForBroker = false; //if the message is valid and not a "ping" message
CompositeNode payload = (result != null) ? result.getResult() : null;
String recipient = null;
- RpcRouter.RouteIdentifier routeId = null;
+ RpcRouter.RouteIdentifier<?, ?, ?> routeId = null;
if (message != null) {
recipient = message.getSender();
private MessageType type;
private String sender;
private String recipient;
- private RpcRouter.RouteIdentifier route;
+ private RpcRouter.RouteIdentifier<?, ?, ?> route;
private Object payload;
public MessageType getType() {
this.sender = sender;
}
- public RpcRouter.RouteIdentifier getRoute() {
+ public RpcRouter.RouteIdentifier<?, ?, ?> getRoute() {
return route;
}
- public void setRoute(RpcRouter.RouteIdentifier route) {
+ public void setRoute(RpcRouter.RouteIdentifier<?, ?, ?> route) {
this.route = route;
}
return o.readObject();
}
- public static class Response extends Message implements RpcRouter.RpcReply {
+ public static class Response extends Message implements RpcRouter.RpcReply<Object> {
private static final long serialVersionUID = 1L;
private ResponseCode code; // response code
return this;
}
- public MessageBuilder route(RpcRouter.RouteIdentifier route){
+ public MessageBuilder route(RpcRouter.RouteIdentifier<?, ?, ?> route){
message.setRoute(route);
return this;
}
//mock routing table
routingTableProvider = mock(RoutingTableProvider.class);
- RoutingTable<RpcRouter.RouteIdentifier, String> mockRoutingTable = new MockRoutingTable<String, String>();
- Optional<RoutingTable<RpcRouter.RouteIdentifier, String>> optionalRoutingTable = Optional.fromNullable(mockRoutingTable);
+ RoutingTable<RpcRouter.RouteIdentifier<?, ?, ?>, String> mockRoutingTable = new MockRoutingTable<String, String>();
+ Optional<RoutingTable<RpcRouter.RouteIdentifier<?, ?, ?>, String>> optionalRoutingTable = Optional.fromNullable(mockRoutingTable);
when(routingTableProvider.getRoutingTable()).thenReturn(optionalRoutingTable);
//mock ClientRequestHandler
private Message handleMessageWithTimeout(final Message request) {
Message response = null;
- FutureTask task = new FutureTask(new Callable<Message>() {
+ FutureTask<?> task = new FutureTask<Message>(new Callable<Message>() {
@Override
public Message call() {
*/
package org.opendaylight.controller.sal.connector.remoterpc;
-import org.opendaylight.controller.sal.connector.remoterpc.api.RouteChangeListener;
+import java.util.HashSet;
+import java.util.Set;
+
import org.opendaylight.controller.sal.connector.remoterpc.api.RoutingTable;
import org.opendaylight.controller.sal.connector.remoterpc.api.RoutingTableException;
import org.opendaylight.controller.sal.connector.remoterpc.api.SystemException;
-import java.util.Collections;
-import java.util.HashSet;
-import java.util.Map;
-import java.util.Set;
-
/**
* Mock implementation of routing table
*/
}
@Override
- public Set getRoutes(Object o) {
+ public Set<String> getRoutes(Object o) {
Set<String> routes = new HashSet<String>();
routes.add("localhost:5554");
return routes;
package org.opendaylight.controller.sal.connector.remoterpc;
-import com.google.common.base.Optional;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.when;
+
+import java.lang.reflect.Field;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.List;
+import java.util.concurrent.ExecutorService;
+import java.util.concurrent.ThreadPoolExecutor;
+
import junit.framework.Assert;
-import org.junit.*;
+
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Test;
import org.opendaylight.controller.sal.connector.api.RpcRouter;
import org.opendaylight.controller.sal.connector.remoterpc.api.RoutingTable;
import org.opendaylight.controller.sal.connector.remoterpc.utils.MessagingUtil;
import org.opendaylight.controller.sal.core.api.Broker;
import org.opendaylight.controller.sal.core.api.RpcRegistrationListener;
+import org.opendaylight.yangtools.yang.common.QName;
import org.opendaylight.yangtools.yang.data.api.CompositeNode;
import org.zeromq.ZMQ;
+
import zmq.Ctx;
import zmq.SocketBase;
-import java.lang.reflect.Field;
-import java.util.ArrayList;
-import java.util.Collections;
-import java.util.List;
-import java.util.concurrent.ExecutorService;
-import java.util.concurrent.ThreadPoolExecutor;
-
-import static org.mockito.Mockito.mock;
-import static org.mockito.Mockito.when;
+import com.google.common.base.Optional;
public class ServerImplTest {
server = new ServerImpl(port);
server.setBrokerSession(brokerSession);
- RoutingTable<RpcRouter.RouteIdentifier, String> mockRoutingTable = new MockRoutingTable<String, String>();
- Optional<RoutingTable<RpcRouter.RouteIdentifier, String>> optionalRoutingTable = Optional.fromNullable(mockRoutingTable);
+ RoutingTable<RpcRouter.RouteIdentifier<?, ?, ?>, String> mockRoutingTable = new MockRoutingTable<String, String>();
+ Optional<RoutingTable<RpcRouter.RouteIdentifier<?, ?, ?>, String>> optionalRoutingTable = Optional.fromNullable(mockRoutingTable);
when(routingTableProvider.getRoutingTable()).thenReturn(optionalRoutingTable);
when(brokerSession.addRpcRegistrationListener(listener)).thenReturn(null);
- when(brokerSession.getSupportedRpcs()).thenReturn(Collections.EMPTY_SET);
+ when(brokerSession.getSupportedRpcs()).thenReturn(Collections.<QName>emptySet());
when(brokerSession.rpc(null, mock(CompositeNode.class))).thenReturn(null);
server.start();
Thread.sleep(5000);//wait for server to start
Thread[] threads = new Thread[Thread.activeCount()];
Thread.enumerate(threads);
- List<Thread> foundThreads = new ArrayList();
+ List<Thread> foundThreads = new ArrayList<Thread>();
for (Thread t : threads) {
if (t.getName().startsWith(name))
foundThreads.add(t);
package org.opendaylight.controller.sal.connector.remoterpc;
+import static org.mockito.Mockito.mock;
+
+import java.util.ArrayList;
+import java.util.List;
+import java.util.concurrent.ExecutorService;
+import java.util.concurrent.Executors;
+
import junit.framework.Assert;
+
import org.junit.After;
import org.junit.Before;
import org.junit.Test;
import org.opendaylight.controller.sal.core.api.Broker;
import org.zeromq.ZMQ;
-import java.util.ArrayList;
-import java.util.List;
-import java.util.concurrent.ExecutorService;
-import java.util.concurrent.Executors;
-
-import static org.mockito.Mockito.mock;
-
public class ServerRequestHandlerTest {
ServerRequestHandler handler;
ZMQ.Context context;
ExecutorService executorService = Executors.newCachedThreadPool();
- private int workerCount = 2;
- private String mockDealerAddress = "inproc://rpc-request-handler";
- private String mockServerIp = "localhost";
- private int mockServerPort = 5554;
+ private final int workerCount = 2;
+ private final String mockDealerAddress = "inproc://rpc-request-handler";
+ private final String mockServerIp = "localhost";
+ private final int mockServerPort = 5554;
@Before
public void setUp() throws Exception {
Thread[] threads = new Thread[Thread.activeCount()];
Thread.enumerate(threads);
- List<Thread> foundThreads = new ArrayList();
+ List<Thread> foundThreads = new ArrayList<Thread>();
for (Thread t : threads) {
if (t.getName().startsWith(name))
foundThreads.add(t);
package org.opendaylight.controller.sal.connector.remoterpc.utils;
-import junit.framework.Assert;
-import org.opendaylight.controller.sal.connector.remoterpc.dto.Message;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-import org.zeromq.ZMQ;
-
import java.io.IOException;
import java.io.PrintWriter;
import java.io.StringWriter;
import java.util.concurrent.FutureTask;
import java.util.concurrent.TimeUnit;
+import junit.framework.Assert;
+
+import org.opendaylight.controller.sal.connector.remoterpc.dto.Message;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.zeromq.ZMQ;
+
public class MessagingUtil {
private static final Logger _logger = LoggerFactory.getLogger(MessagingUtil.class);
if (context == null) return;
ExecutorService exec = Executors.newSingleThreadExecutor();
- FutureTask zmqTermination = new FutureTask(new Runnable() {
+ FutureTask<?> zmqTermination = new FutureTask<Void>(new Runnable() {
@Override
public void run() {
package org.opendaylight.controller.sal.connector.remoterpc.utils;
+import java.util.concurrent.ExecutorService;
+import java.util.concurrent.Executors;
+
import org.opendaylight.controller.sal.connector.api.RpcRouter;
import org.opendaylight.controller.sal.connector.remoterpc.dto.Message;
import org.opendaylight.controller.sal.connector.remoterpc.util.XmlUtils;
import org.opendaylight.yangtools.yang.data.api.CompositeNode;
import org.zeromq.ZMQ;
-import java.util.concurrent.ExecutorService;
-import java.util.concurrent.Executors;
-
public class RemoteServerTestClient {
}
public Message createAddFlowMessage(String serverAddress ){
- RpcRouter.RouteIdentifier routeIdentifier = getAddFlowRpcIdentifier();
+ RpcRouter.RouteIdentifier<?, ?, ?> routeIdentifier = getAddFlowRpcIdentifier();
Message addFlow = new Message.MessageBuilder()
.type(Message.MessageType.REQUEST)
return addFlow;
}
- private RpcRouter.RouteIdentifier getAddFlowRpcIdentifier(){
+ private RpcRouter.RouteIdentifier<?, ?, ?> getAddFlowRpcIdentifier(){
throw new UnsupportedOperationException();
}
<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) {