<dependency>
<groupId>org.opendaylight.controller</groupId>
<artifactId>config-netty-config</artifactId>
+ <!--
+ note, the reason the type and classifier
+ are here instead of in opendaylight/commons/opendaylight/pom.xml
+ is because they are used as jars in distribution.
+ -->
+ <version>${config.version}</version>
+ <type>xml</type>
+ <classifier>config</classifier>
</dependency>
<!-- test to validate features.xml -->
<dependency>
</properties>
<dependencies>
+ <!-- dependency for opendaylight-karaf-empty for use by testing -->
+ <dependency>
+ <groupId>org.opendaylight.controller</groupId>
+ <artifactId>opendaylight-karaf-empty</artifactId>
+ <version>1.4.2-SNAPSHOT</version>
+ <type>zip</type>
+ </dependency>
<dependency>
<groupId>org.opendaylight.yangtools</groupId>
<artifactId>features-yangtools</artifactId>
<dependency>
<groupId>org.opendaylight.controller</groupId>
<artifactId>md-sal-config</artifactId>
+ <version>${mdsal.version}</version>
+ <type>xml</type>
+ <classifier>config</classifier>
</dependency>
<dependency>
<groupId>org.opendaylight.controller</groupId>
<dependency>
<groupId>org.opendaylight.controller</groupId>
<artifactId>netconf-connector-config</artifactId>
+ <version>${netconf.version}</version>
+ <type>xml</type>
+ <classifier>config</classifier>
</dependency>
<dependency>
<groupId>org.opendaylight.controller</groupId>
<dependency>
<groupId>org.opendaylight.controller</groupId>
<artifactId>sal-rest-connector-config</artifactId>
+ <version>${mdsal.version}</version>
+ <type>xml</type>
+ <classifier>config</classifier>
</dependency>
<dependency>
<groupId>org.opendaylight.controller.samples</groupId>
<dependency>
<groupId>org.opendaylight.controller.samples</groupId>
<artifactId>toaster-config</artifactId>
+ <version>${mdsal.version}</version>
+ <type>xml</type>
+ <classifier>config</classifier>
</dependency>
<!-- test to validate features.xml -->
<dependency>
package org.opendaylight.controller.frm.reconil;
+import com.google.common.base.Optional;
+import com.google.common.base.Preconditions;
+import com.google.common.util.concurrent.ListenableFuture;
+import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Set;
import java.util.concurrent.ExecutionException;
-
import org.opendaylight.controller.frm.AbstractChangeListener;
import org.opendaylight.controller.frm.FlowCookieProducer;
import org.opendaylight.controller.md.sal.binding.api.ReadOnlyTransaction;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
-import com.google.common.base.Optional;
-import com.google.common.base.Preconditions;
-import com.google.common.util.concurrent.ListenableFuture;
-
/**
* forwardingrules-manager
* org.opendaylight.controller.frm
}
@Override
- public void onDataChanged(AsyncDataChangeEvent<InstanceIdentifier<?>, DataObject> changeEvent) {
+ public void onDataChanged(final AsyncDataChangeEvent<InstanceIdentifier<?>, DataObject> changeEvent) {
/* FlowCapableNode DataObjects for reconciliation */
final Set<Entry<InstanceIdentifier<? extends DataObject>, DataObject>> createdEntries =
changeEvent.getCreatedData().entrySet();
final InstanceIdentifier<Node> nodeIdent = identifier.firstIdentifierOf(Node.class);
final NodeRef nodeRef = new NodeRef(nodeIdent);
/* Groups - have to be first */
- for (Group group : flowCapNode.get().getGroup()) {
- final GroupRef groupRef = new GroupRef(flowNodeIdent.child(Group.class, group.getKey()));
- final AddGroupInputBuilder groupBuilder = new AddGroupInputBuilder(group);
- groupBuilder.setGroupRef(groupRef);
- groupBuilder.setNode(nodeRef);
- this.provider.getSalGroupService().addGroup(groupBuilder.build());
+ List<Group> groups = flowCapNode.get().getGroup();
+ if(groups != null) {
+ for (Group group : groups) {
+ final GroupRef groupRef = new GroupRef(flowNodeIdent.child(Group.class, group.getKey()));
+ final AddGroupInputBuilder groupBuilder = new AddGroupInputBuilder(group);
+ groupBuilder.setGroupRef(groupRef);
+ groupBuilder.setNode(nodeRef);
+ this.provider.getSalGroupService().addGroup(groupBuilder.build());
+ }
}
/* Meters */
- for (Meter meter : flowCapNode.get().getMeter()) {
- final MeterRef meterRef = new MeterRef(flowNodeIdent.child(Meter.class, meter.getKey()));
- final AddMeterInputBuilder meterBuilder = new AddMeterInputBuilder(meter);
- meterBuilder.setMeterRef(meterRef);
- meterBuilder.setNode(nodeRef);
- this.provider.getSalMeterService().addMeter(meterBuilder.build());
+ List<Meter> meters = flowCapNode.get().getMeter();
+ if(meters != null) {
+ for (Meter meter : meters) {
+ final MeterRef meterRef = new MeterRef(flowNodeIdent.child(Meter.class, meter.getKey()));
+ final AddMeterInputBuilder meterBuilder = new AddMeterInputBuilder(meter);
+ meterBuilder.setMeterRef(meterRef);
+ meterBuilder.setNode(nodeRef);
+ this.provider.getSalMeterService().addMeter(meterBuilder.build());
+ }
}
/* Flows */
- for (Table flowTable : flowCapNode.get().getTable()) {
- final InstanceIdentifier<Table> tableIdent = flowNodeIdent.child(Table.class, flowTable.getKey());
- for (Flow flow : flowTable.getFlow()) {
- final FlowCookie flowCookie = new FlowCookie(FlowCookieProducer.INSTANCE.getNewCookie(tableIdent));
- final FlowRef flowRef = new FlowRef(tableIdent.child(Flow.class, flow.getKey()));
- final FlowTableRef flowTableRef = new FlowTableRef(tableIdent);
- final AddFlowInputBuilder flowBuilder = new AddFlowInputBuilder(flow);
- flowBuilder.setCookie(flowCookie);
- flowBuilder.setNode(nodeRef);
- flowBuilder.setFlowTable(flowTableRef);
- flowBuilder.setFlowRef(flowRef);
- this.provider.getSalFlowService().addFlow(flowBuilder.build());
+ List<Table> tables = flowCapNode.get().getTable();
+ if(tables != null) {
+ for (Table flowTable : tables) {
+ final InstanceIdentifier<Table> tableIdent = flowNodeIdent.child(Table.class, flowTable.getKey());
+ List<Flow> flows = flowTable.getFlow();
+ if(flows != null) {
+ for (Flow flow : flows) {
+ final FlowCookie flowCookie = new FlowCookie(FlowCookieProducer.INSTANCE.getNewCookie(tableIdent));
+ final FlowRef flowRef = new FlowRef(tableIdent.child(Flow.class, flow.getKey()));
+ final FlowTableRef flowTableRef = new FlowTableRef(tableIdent);
+ final AddFlowInputBuilder flowBuilder = new AddFlowInputBuilder(flow);
+ flowBuilder.setCookie(flowCookie);
+ flowBuilder.setNode(nodeRef);
+ flowBuilder.setFlowTable(flowTableRef);
+ flowBuilder.setFlowRef(flowRef);
+ this.provider.getSalFlowService().addFlow(flowBuilder.build());
+ }
+ }
}
}
}
@Override
protected void update(final InstanceIdentifier<? extends DataObject> identifier,
- final DataObject original, DataObject update) {
+ final DataObject original, final DataObject update) {
// NOOP - Listener is registered for DataChangeScope.BASE only
}
import com.google.common.util.concurrent.Futures;
import java.util.concurrent.BlockingQueue;
import java.util.concurrent.LinkedBlockingDeque;
+import org.opendaylight.controller.md.sal.binding.api.BindingTransactionChain;
import org.opendaylight.controller.md.sal.binding.api.DataBroker;
import org.opendaylight.controller.md.sal.binding.api.ReadWriteTransaction;
+import org.opendaylight.controller.md.sal.common.api.data.AsyncTransaction;
+import org.opendaylight.controller.md.sal.common.api.data.TransactionChain;
+import org.opendaylight.controller.md.sal.common.api.data.TransactionChainListener;
import org.opendaylight.controller.md.sal.common.api.data.TransactionCommitFailedException;
import org.opendaylight.controller.sal.binding.api.NotificationProviderService;
import org.opendaylight.yangtools.concepts.ListenerRegistration;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
-class FlowCapableInventoryProvider implements AutoCloseable, Runnable {
+class FlowCapableInventoryProvider implements AutoCloseable, Runnable, TransactionChainListener {
private static final Logger LOG = LoggerFactory.getLogger(FlowCapableInventoryProvider.class);
private static final int QUEUE_DEPTH = 500;
private static final int MAX_BATCH = 100;
private final NotificationProviderService notificationService;
private final DataBroker dataBroker;
+ private BindingTransactionChain txChain;
private ListenerRegistration<?> listenerRegistration;
private Thread thread;
final NodeChangeCommiter changeCommiter = new NodeChangeCommiter(FlowCapableInventoryProvider.this);
this.listenerRegistration = this.notificationService.registerNotificationListener(changeCommiter);
+ this.txChain = dataBroker.createTransactionChain(this);
thread = new Thread(this);
thread.setDaemon(true);
thread.setName("FlowCapableInventoryProvider");
thread.join();
thread = null;
}
+ if(txChain != null) {
+ txChain.close();
+ txChain = null;
+ }
}
for (; ; ) {
InventoryOperation op = queue.take();
- final ReadWriteTransaction tx = dataBroker.newReadWriteTransaction();
+ final ReadWriteTransaction tx = txChain.newReadWriteTransaction();
LOG.debug("New operations available, starting transaction {}", tx.getIdentifier());
int ops = 0;
final CheckedFuture<Void, TransactionCommitFailedException> result = tx.submit();
Futures.addCallback(result, new FutureCallback<Void>() {
@Override
- public void onSuccess(Void aVoid) {
+ public void onSuccess(final Void aVoid) {
//NOOP
}
@Override
- public void onFailure(Throwable throwable) {
+ public void onFailure(final Throwable throwable) {
LOG.error("Transaction {} failed.", tx.getIdentifier(), throwable);
}
});
queue.poll();
}
}
+
+ @Override
+ public void onTransactionChainFailed(final TransactionChain<?, ?> chain, final AsyncTransaction<?, ?> transaction,
+ final Throwable cause) {
+ LOG.error("Failed to export Flow Capable Inventory, Transaction {} failed.",transaction.getIdentifier(),cause);
+
+ }
+
+ @Override
+ public void onTransactionChainSuccessful(final TransactionChain<?, ?> chain) {
+ // NOOP
+ }
}
import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.node.NodeConnectorBuilder;
import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.node.NodeConnectorKey;
import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.nodes.Node;
-import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.nodes.NodeBuilder;
-import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.nodes.NodeKey;
import org.opendaylight.yangtools.yang.binding.DataObject;
import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
import org.opendaylight.yangtools.yang.binding.InstanceIdentifier.InstanceIdentifierBuilder;
InstanceIdentifier<NodeConnector> value = (InstanceIdentifier<NodeConnector>) ref.getValue();
LOG.debug("updating node connector : {}.", value);
NodeConnector build = data.build();
- tx.put(LogicalDatastoreType.OPERATIONAL, value, build);
+ tx.merge(LogicalDatastoreType.OPERATIONAL, value, build, true);
}
});
}
manager.enqueue(new InventoryOperation() {
@Override
public void applyOperation(final ReadWriteTransaction tx) {
- final NodeBuilder nodeBuilder = new NodeBuilder(node);
- nodeBuilder.setKey(new NodeKey(node.getId()));
-
final FlowCapableNode augment = InventoryMapping.toInventoryAugment(flowNode);
- nodeBuilder.addAugmentation(FlowCapableNode.class, augment);
LOG.debug("updating node :{} ", path);
- tx.put(LogicalDatastoreType.OPERATIONAL, path, augment);
+ tx.merge(LogicalDatastoreType.OPERATIONAL, path, augment, true);
}
});
}
<groupId>org.opendaylight.yangtools</groupId>
<artifactId>binding-generator-impl</artifactId>
</dependency>
+ <dependency>
+ <groupId>org.opendaylight.yangtools</groupId>
+ <artifactId>binding-data-codec</artifactId>
+ <version>0.6.2-SNAPSHOT</version>
+ </dependency>
<dependency>
<groupId>org.opendaylight.yangtools</groupId>
<artifactId>yang-data-impl</artifactId>
import java.util.Collection;
import java.util.Collections;
-
+import org.opendaylight.controller.md.sal.binding.impl.BindingToNormalizedNodeCodec;
import org.opendaylight.controller.md.sal.binding.impl.ForwardedBindingDataBroker;
import org.opendaylight.controller.md.sal.dom.api.DOMDataBroker;
import org.opendaylight.controller.sal.core.api.Broker;
import org.opendaylight.controller.sal.core.api.Broker.ProviderSession;
import org.opendaylight.controller.sal.core.api.Provider;
import org.opendaylight.controller.sal.core.api.model.SchemaService;
-import org.opendaylight.yangtools.yang.data.impl.codec.BindingIndependentMappingService;
public class BindingAsyncDataBrokerImplModule extends
org.opendaylight.controller.config.yang.md.sal.binding.impl.AbstractBindingAsyncDataBrokerImplModule implements
@Override
public java.lang.AutoCloseable createInstance() {
Broker domBroker = getDomAsyncBrokerDependency();
- BindingIndependentMappingService mappingService = getBindingMappingServiceDependency();
+ BindingToNormalizedNodeCodec mappingService = getBindingMappingServiceDependency();
// FIXME: Switch this to DOM Broker registration which would not require
// BundleContext when API are updated.
+++ /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.config.yang.md.sal.binding.impl;
-
-import java.util.concurrent.ExecutorService;
-
-import org.opendaylight.controller.sal.binding.codegen.impl.SingletonHolder;
-import org.opendaylight.controller.sal.binding.impl.RootDataBrokerImpl;
-import org.opendaylight.controller.sal.binding.impl.connect.dom.BindingDomConnectorDeployer;
-import org.opendaylight.controller.sal.binding.impl.connect.dom.BindingIndependentConnector;
-import org.opendaylight.controller.sal.binding.impl.forward.DomForwardedDataBrokerImpl;
-import org.opendaylight.controller.sal.core.api.Broker.ProviderSession;
-import org.opendaylight.yangtools.yang.data.impl.codec.BindingIndependentMappingService;
-
-/**
-*
-*/
-public final class DataBrokerImplModule extends
- org.opendaylight.controller.config.yang.md.sal.binding.impl.AbstractDataBrokerImplModule {
-
- public DataBrokerImplModule(final org.opendaylight.controller.config.api.ModuleIdentifier identifier,
- final org.opendaylight.controller.config.api.DependencyResolver dependencyResolver) {
- super(identifier, dependencyResolver);
- }
-
- public DataBrokerImplModule(final org.opendaylight.controller.config.api.ModuleIdentifier identifier,
- final org.opendaylight.controller.config.api.DependencyResolver dependencyResolver,
- final DataBrokerImplModule oldModule, final java.lang.AutoCloseable oldInstance) {
- super(identifier, dependencyResolver, oldModule, oldInstance);
- }
-
- @Override
- public void validate() {
- super.validate();
- }
-
- @Override
- public java.lang.AutoCloseable createInstance() {
- RootDataBrokerImpl dataBindingBroker;
-
-
- ExecutorService listeningExecutor = SingletonHolder.getDefaultCommitExecutor();
- BindingIndependentMappingService potentialMapping = getMappingServiceDependency();
- if (getDomBrokerDependency() != null && potentialMapping != null) {
-
- dataBindingBroker = createDomConnectedBroker(listeningExecutor,potentialMapping);
- } else {
- dataBindingBroker = createStandAloneBroker(listeningExecutor);
- }
- dataBindingBroker.registerRuntimeBean(getRootRuntimeBeanRegistratorWrapper());
- dataBindingBroker.setNotificationExecutor(SingletonHolder.getDefaultChangeEventExecutor());
- return dataBindingBroker;
- }
-
-
- private RootDataBrokerImpl createStandAloneBroker(final ExecutorService listeningExecutor) {
- RootDataBrokerImpl broker = new RootDataBrokerImpl();
- broker.setExecutor(listeningExecutor);
- return broker;
- }
-
- private RootDataBrokerImpl createDomConnectedBroker(final ExecutorService listeningExecutor, final BindingIndependentMappingService mappingService) {
- DomForwardedDataBrokerImpl forwardedBroker = new DomForwardedDataBrokerImpl();
- forwardedBroker.setExecutor(listeningExecutor);
- BindingIndependentConnector connector = BindingDomConnectorDeployer.createConnector(mappingService);
- getDomBrokerDependency().registerProvider(forwardedBroker, null);
- ProviderSession domContext = forwardedBroker.getDomProviderContext();
- forwardedBroker.setConnector(connector);
- forwardedBroker.setDomProviderContext(domContext);
- forwardedBroker.startForwarding();
- return forwardedBroker;
- }
-
-}
+++ /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.config.yang.md.sal.binding.impl;
-
-
-/**
-*
-*/
-public class DataBrokerImplModuleFactory extends
- org.opendaylight.controller.config.yang.md.sal.binding.impl.AbstractDataBrokerImplModuleFactory {
-
-}
*/
package org.opendaylight.controller.config.yang.md.sal.binding.impl;
+import com.google.common.util.concurrent.ListeningExecutorService;
import java.util.Collection;
import java.util.Collections;
-
+import org.opendaylight.controller.md.sal.binding.impl.BindingToNormalizedNodeCodec;
import org.opendaylight.controller.md.sal.binding.impl.ForwardedBackwardsCompatibleDataBroker;
import org.opendaylight.controller.md.sal.dom.api.DOMDataBroker;
import org.opendaylight.controller.sal.binding.codegen.impl.SingletonHolder;
import org.opendaylight.controller.sal.core.api.Broker.ProviderSession;
import org.opendaylight.controller.sal.core.api.Provider;
import org.opendaylight.controller.sal.core.api.model.SchemaService;
-import org.opendaylight.yangtools.yang.data.impl.codec.BindingIndependentMappingService;
-
-import com.google.common.util.concurrent.ListeningExecutorService;
/**
*
@Override
public java.lang.AutoCloseable createInstance() {
ListeningExecutorService listeningExecutor = SingletonHolder.getDefaultCommitExecutor();
- BindingIndependentMappingService mappingService = getBindingMappingServiceDependency();
+ BindingToNormalizedNodeCodec mappingService = getBindingMappingServiceDependency();
Broker domBroker = getDomAsyncBrokerDependency();
ProviderSession session = domBroker.registerProvider(this, null);
ForwardedBackwardsCompatibleDataBroker dataBroker = new ForwardedBackwardsCompatibleDataBroker(domDataBroker,
mappingService, schemaService,listeningExecutor);
- dataBroker.setConnector(BindingDomConnectorDeployer.createConnector(getBindingMappingServiceDependency()));
+ dataBroker.setConnector(BindingDomConnectorDeployer.createConnector(mappingService.getLegacy()));
dataBroker.setDomProviderContext(session);
return dataBroker;
}
*/
package org.opendaylight.controller.config.yang.md.sal.binding.impl;
+import com.google.common.base.Optional;
+import com.google.common.base.Preconditions;
import java.util.Hashtable;
import java.util.Map.Entry;
import java.util.Set;
-
+import javassist.ClassPool;
+import org.opendaylight.controller.md.sal.binding.impl.BindingToNormalizedNodeCodec;
import org.opendaylight.controller.sal.binding.codegen.impl.SingletonHolder;
+import org.opendaylight.yangtools.binding.data.codec.gen.impl.StreamWriterGenerator;
+import org.opendaylight.yangtools.binding.data.codec.impl.BindingNormalizedNodeCodecRegistry;
import org.opendaylight.yangtools.concepts.Delegator;
+import org.opendaylight.yangtools.sal.binding.generator.impl.GeneratedClassLoadingStrategy;
import org.opendaylight.yangtools.sal.binding.generator.impl.RuntimeGeneratedMappingServiceImpl;
import org.opendaylight.yangtools.yang.binding.DataContainer;
import org.opendaylight.yangtools.yang.binding.DataObject;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
-import com.google.common.base.Optional;
-import com.google.common.base.Preconditions;
-
/**
*
*/
private BundleContext bundleContext;
- public RuntimeMappingModule(org.opendaylight.controller.config.api.ModuleIdentifier identifier,
- org.opendaylight.controller.config.api.DependencyResolver dependencyResolver) {
+ public RuntimeMappingModule(final org.opendaylight.controller.config.api.ModuleIdentifier identifier,
+ final org.opendaylight.controller.config.api.DependencyResolver dependencyResolver) {
super(identifier, dependencyResolver);
}
- public RuntimeMappingModule(org.opendaylight.controller.config.api.ModuleIdentifier identifier,
- org.opendaylight.controller.config.api.DependencyResolver dependencyResolver,
- RuntimeMappingModule oldModule, java.lang.AutoCloseable oldInstance) {
+ public RuntimeMappingModule(final org.opendaylight.controller.config.api.ModuleIdentifier identifier,
+ final org.opendaylight.controller.config.api.DependencyResolver dependencyResolver,
+ final RuntimeMappingModule oldModule, final java.lang.AutoCloseable oldInstance) {
super(identifier, dependencyResolver, oldModule, oldInstance);
}
}
@Override
- public boolean canReuseInstance(AbstractRuntimeMappingModule oldModule) {
+ public boolean canReuseInstance(final AbstractRuntimeMappingModule oldModule) {
return true;
}
@Override
public java.lang.AutoCloseable createInstance() {
+ final GeneratedClassLoadingStrategy classLoading = getGlobalClassLoadingStrategy();
+ final BindingIndependentMappingService legacyMapping = getGlobalLegacyMappingService(classLoading);
+ BindingNormalizedNodeCodecRegistry codecRegistry = new BindingNormalizedNodeCodecRegistry(new StreamWriterGenerator(SingletonHolder.JAVASSIST));
+ BindingToNormalizedNodeCodec instance = new BindingToNormalizedNodeCodec(classLoading, legacyMapping, codecRegistry);
+ bundleContext.registerService(SchemaContextListener.class, instance, new Hashtable<String,String>());
+ return instance;
+ }
- RuntimeGeneratedMappingServiceProxy potential = tryToReuseGlobalInstance();
- if(potential != null) {
- return potential;
+ private BindingIndependentMappingService getGlobalLegacyMappingService(final GeneratedClassLoadingStrategy classLoading) {
+ BindingIndependentMappingService potential = tryToReuseGlobalMappingServiceInstance();
+ if(potential == null) {
+ potential = new RuntimeGeneratedMappingServiceImpl(ClassPool.getDefault(),classLoading);
+ bundleContext.registerService(SchemaContextListener.class, (SchemaContextListener) potential, new Hashtable<String,String>());
}
+ return potential;
+ }
- final RuntimeGeneratedMappingServiceImpl service = new RuntimeGeneratedMappingServiceImpl(SingletonHolder.CLASS_POOL);
- bundleContext.registerService(SchemaContextListener.class, service, new Hashtable<String,String>());
- return service;
+ private GeneratedClassLoadingStrategy getGlobalClassLoadingStrategy() {
+ ServiceReference<GeneratedClassLoadingStrategy> ref = bundleContext.getServiceReference(GeneratedClassLoadingStrategy.class);
+ return bundleContext.getService(ref);
}
- private RuntimeGeneratedMappingServiceProxy tryToReuseGlobalInstance() {
+ private BindingIndependentMappingService tryToReuseGlobalMappingServiceInstance() {
ServiceReference<BindingIndependentMappingService> serviceRef = getBundleContext().getServiceReference(BindingIndependentMappingService.class);
if(serviceRef == null) {
return null;
}
+ return bundleContext.getService(serviceRef);
- BindingIndependentMappingService delegate = bundleContext.getService(serviceRef);
- if (delegate == null) {
- return null;
- }
- return new RuntimeGeneratedMappingServiceProxy(getBundleContext(),serviceRef,delegate);
}
private BundleContext getBundleContext() {
return bundleContext;
}
- public void setBundleContext(BundleContext bundleContext) {
+ public void setBundleContext(final BundleContext bundleContext) {
this.bundleContext = bundleContext;
}
private ServiceReference<BindingIndependentMappingService> reference;
private BundleContext bundleContext;
- public RuntimeGeneratedMappingServiceProxy(BundleContext bundleContext,
- ServiceReference<BindingIndependentMappingService> serviceRef,
- BindingIndependentMappingService delegate) {
+ public RuntimeGeneratedMappingServiceProxy(final BundleContext bundleContext,
+ final ServiceReference<BindingIndependentMappingService> serviceRef,
+ final BindingIndependentMappingService delegate) {
this.bundleContext = Preconditions.checkNotNull(bundleContext);
this.reference = Preconditions.checkNotNull(serviceRef);
this.delegate = Preconditions.checkNotNull(delegate);
}
@Override
- public CompositeNode toDataDom(DataObject data) {
+ public CompositeNode toDataDom(final DataObject data) {
return delegate.toDataDom(data);
}
@Override
public Entry<YangInstanceIdentifier, CompositeNode> toDataDom(
- Entry<org.opendaylight.yangtools.yang.binding.InstanceIdentifier<? extends DataObject>, DataObject> entry) {
+ final Entry<org.opendaylight.yangtools.yang.binding.InstanceIdentifier<? extends DataObject>, DataObject> entry) {
return delegate.toDataDom(entry);
}
@Override
public YangInstanceIdentifier toDataDom(
- org.opendaylight.yangtools.yang.binding.InstanceIdentifier<? extends DataObject> path) {
+ final org.opendaylight.yangtools.yang.binding.InstanceIdentifier<? extends DataObject> path) {
return delegate.toDataDom(path);
}
@Override
public DataObject dataObjectFromDataDom(
- org.opendaylight.yangtools.yang.binding.InstanceIdentifier<? extends DataObject> path,
- CompositeNode result) throws DeserializationException {
+ final org.opendaylight.yangtools.yang.binding.InstanceIdentifier<? extends DataObject> path,
+ final CompositeNode result) throws DeserializationException {
return delegate.dataObjectFromDataDom(path, result);
}
@Override
- public org.opendaylight.yangtools.yang.binding.InstanceIdentifier<?> fromDataDom(YangInstanceIdentifier entry)
+ public org.opendaylight.yangtools.yang.binding.InstanceIdentifier<?> fromDataDom(final YangInstanceIdentifier entry)
throws DeserializationException {
return delegate.fromDataDom(entry);
}
@Override
- public Set<QName> getRpcQNamesFor(Class<? extends RpcService> service) {
+ public Set<QName> getRpcQNamesFor(final Class<? extends RpcService> service) {
return delegate.getRpcQNamesFor(service);
}
@Override
- public Optional<Class<? extends RpcService>> getRpcServiceClassFor(String namespace, String revision) {
+ public Optional<Class<? extends RpcService>> getRpcServiceClassFor(final String namespace, final String revision) {
return delegate.getRpcServiceClassFor(namespace,revision);
}
@Override
- public DataContainer dataObjectFromDataDom(Class<? extends DataContainer> inputClass, CompositeNode domInput) {
+ public DataContainer dataObjectFromDataDom(final Class<? extends DataContainer> inputClass, final CompositeNode domInput) {
return delegate.dataObjectFromDataDom(inputClass, domInput);
}
import com.google.common.base.Objects;
import com.google.common.base.Optional;
-
import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Set;
-
import org.opendaylight.controller.md.sal.binding.api.DataChangeListener;
import org.opendaylight.controller.md.sal.common.api.data.AsyncDataBroker.DataChangeScope;
import org.opendaylight.controller.md.sal.common.api.data.AsyncDataChangeEvent;
import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier;
import org.opendaylight.yangtools.yang.data.api.schema.NormalizedNode;
-import org.opendaylight.yangtools.yang.data.impl.codec.BindingIndependentMappingService;
import org.opendaylight.yangtools.yang.data.impl.codec.DeserializationException;
import org.opendaylight.yangtools.yang.model.api.SchemaContext;
import org.opendaylight.yangtools.yang.model.api.SchemaContextListener;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
-public abstract class AbstractForwardedDataBroker implements Delegator<DOMDataBroker>, DomForwardedBroker, SchemaContextListener, AutoCloseable {
+public abstract class AbstractForwardedDataBroker implements Delegator<DOMDataBroker>, DomForwardedBroker,
+ SchemaContextListener, AutoCloseable {
private static final Logger LOG = LoggerFactory.getLogger(AbstractForwardedDataBroker.class);
// The Broker to whom we do all forwarding
private final DOMDataBroker domDataBroker;
- // Mapper to convert from Binding Independent objects to Binding Aware
- // objects
- private final BindingIndependentMappingService mappingService;
-
private final BindingToNormalizedNodeCodec codec;
private BindingIndependentConnector connector;
private ProviderSession context;
private final ListenerRegistration<SchemaContextListener> schemaListenerRegistration;
- protected AbstractForwardedDataBroker(final DOMDataBroker domDataBroker,
- final BindingIndependentMappingService mappingService,final SchemaService schemaService) {
+ protected AbstractForwardedDataBroker(final DOMDataBroker domDataBroker, final BindingToNormalizedNodeCodec codec,
+ final SchemaService schemaService) {
this.domDataBroker = domDataBroker;
- this.mappingService = mappingService;
- this.codec = new BindingToNormalizedNodeCodec(mappingService);
+ this.codec = codec;
this.schemaListenerRegistration = schemaService.registerSchemaContextListener(this);
}
return codec;
}
- protected BindingIndependentMappingService getMappingService() {
- return mappingService;
- }
-
@Override
public DOMDataBroker getDelegate() {
return domDataBroker;
@Override
public void onGlobalContextUpdated(final SchemaContext ctx) {
- codec.onGlobalContextUpdated(ctx);
+ // NOOP
}
public ListenerRegistration<DataChangeListener> registerDataChangeListener(final LogicalDatastoreType store,
- final InstanceIdentifier<?> path, final DataChangeListener listener,
- final DataChangeScope triggeringScope) {
+ final InstanceIdentifier<?> path, final DataChangeListener listener, final DataChangeScope triggeringScope) {
DOMDataChangeListener domDataChangeListener = new TranslatingDataChangeInvoker(store, path, listener,
triggeringScope);
YangInstanceIdentifier domPath = codec.toNormalized(path);
return new ListenerRegistrationImpl(listener, domRegistration);
}
- protected Map<InstanceIdentifier<?>, DataObject> toBinding(
- InstanceIdentifier<?> path,
+ protected Map<InstanceIdentifier<?>, DataObject> toBinding(final InstanceIdentifier<?> path,
final Map<YangInstanceIdentifier, ? extends NormalizedNode<?, ?>> normalized) {
Map<InstanceIdentifier<?>, DataObject> newMap = new HashMap<>();
for (Map.Entry<YangInstanceIdentifier, ? extends NormalizedNode<?, ?>> entry : sortedEntries(normalized)) {
try {
- Optional<Entry<InstanceIdentifier<? extends DataObject>, DataObject>> potential = getCodec().toBinding(
- entry);
+ Optional<Entry<InstanceIdentifier<? extends DataObject>, DataObject>> potential = getCodec().toBinding(entry);
if (potential.isPresent()) {
Entry<InstanceIdentifier<? extends DataObject>, DataObject> binding = potential.get();
newMap.put(binding.getKey(), binding.getValue());
- } else if (entry.getKey().getLastPathArgument() instanceof YangInstanceIdentifier.AugmentationIdentifier) {
- DataObject bindingDataObject = getCodec().toBinding(path, entry.getValue());
- if (bindingDataObject != null) {
- newMap.put(path, bindingDataObject);
- }
}
} catch (DeserializationException e) {
LOG.warn("Failed to transform {}, omitting it", entry, e);
private static final Comparator<Entry<YangInstanceIdentifier, ?>> MAP_ENTRY_COMPARATOR = new Comparator<Entry<YangInstanceIdentifier, ?>>() {
@Override
- public int compare(final Entry<YangInstanceIdentifier, ?> left,
- final Entry<YangInstanceIdentifier, ?> right) {
+ public int compare(final Entry<YangInstanceIdentifier, ?> left, final Entry<YangInstanceIdentifier, ?> right) {
final Iterator<?> li = left.getKey().getPathArguments().iterator();
final Iterator<?> ri = right.getKey().getPathArguments().iterator();
}
};
- private static <T> Iterable<Entry<YangInstanceIdentifier,T>> sortedEntries(final Map<YangInstanceIdentifier, T> map) {
+ private static <T> Iterable<Entry<YangInstanceIdentifier, T>> sortedEntries(final Map<YangInstanceIdentifier, T> map) {
if (!map.isEmpty()) {
ArrayList<Entry<YangInstanceIdentifier, T>> entries = new ArrayList<>(map.entrySet());
Collections.sort(entries, MAP_ENTRY_COMPARATOR);
}
}
- protected Set<InstanceIdentifier<?>> toBinding(InstanceIdentifier<?> path,
+ protected Set<InstanceIdentifier<?>> toBinding(final InstanceIdentifier<?> path,
final Set<YangInstanceIdentifier> normalized) {
Set<InstanceIdentifier<?>> hashSet = new HashSet<>();
for (YangInstanceIdentifier normalizedPath : normalized) {
if (path.isWildcarded()) {
return Optional.absent();
}
-
- try {
- return Optional.fromNullable(getCodec().toBinding(path, data));
- } catch (DeserializationException e) {
- return Optional.absent();
- }
+ return (Optional) getCodec().deserializeFunction(path).apply(Optional.<NormalizedNode<?, ?>> of(data));
}
private class TranslatingDataChangeInvoker implements DOMDataChangeListener {
}
@Override
- public void onDataChanged(
- final AsyncDataChangeEvent<YangInstanceIdentifier, NormalizedNode<?, ?>> change) {
+ public void onDataChanged(final AsyncDataChangeEvent<YangInstanceIdentifier, NormalizedNode<?, ?>> change) {
bindingDataChangeListener.onDataChanged(new TranslatedDataChangeEvent(change, path));
}
}
@Override
public DataObject getOriginalSubtree() {
if (originalDataCache == null) {
- if(domEvent.getOriginalSubtree() != null) {
+ if (domEvent.getOriginalSubtree() != null) {
originalDataCache = toBindingData(path, domEvent.getOriginalSubtree());
} else {
originalDataCache = Optional.absent();
@Override
public DataObject getUpdatedSubtree() {
if (updatedDataCache == null) {
- if(domEvent.getUpdatedSubtree() != null) {
+ if (domEvent.getUpdatedSubtree() != null) {
updatedDataCache = toBindingData(path, domEvent.getUpdatedSubtree());
} else {
updatedDataCache = Optional.absent();
*/
package org.opendaylight.controller.md.sal.binding.impl;
-import java.lang.reflect.Method;
+import com.google.common.base.Function;
+import com.google.common.base.Optional;
import java.util.AbstractMap.SimpleEntry;
-import java.util.Collection;
-import java.util.HashSet;
import java.util.Iterator;
import java.util.Map.Entry;
-import java.util.Set;
-
-import javax.annotation.Nullable;
-
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.yang.binding.Augmentation;
-import org.opendaylight.yangtools.yang.binding.BindingMapping;
+import org.opendaylight.yangtools.binding.data.codec.impl.BindingNormalizedNodeCodecRegistry;
+import org.opendaylight.yangtools.sal.binding.generator.impl.GeneratedClassLoadingStrategy;
+import org.opendaylight.yangtools.sal.binding.generator.util.BindingRuntimeContext;
import org.opendaylight.yangtools.yang.binding.DataObject;
import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
-import org.opendaylight.yangtools.yang.binding.YangModuleInfo;
-import org.opendaylight.yangtools.yang.binding.util.BindingReflections;
-import org.opendaylight.yangtools.yang.common.QName;
-import org.opendaylight.yangtools.yang.common.QNameModule;
-import org.opendaylight.yangtools.yang.data.api.CompositeNode;
-import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier.AugmentationIdentifier;
-import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier.NodeIdentifier;
import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier.PathArgument;
-import org.opendaylight.yangtools.yang.data.api.schema.AugmentationNode;
-import org.opendaylight.yangtools.yang.data.api.schema.ContainerNode;
-import org.opendaylight.yangtools.yang.data.api.schema.DataContainerChild;
-import org.opendaylight.yangtools.yang.data.api.schema.DataContainerNode;
import org.opendaylight.yangtools.yang.data.api.schema.NormalizedNode;
import org.opendaylight.yangtools.yang.data.impl.codec.BindingIndependentMappingService;
import org.opendaylight.yangtools.yang.data.impl.codec.DeserializationException;
-import org.opendaylight.yangtools.yang.data.impl.schema.Builders;
-import org.opendaylight.yangtools.yang.model.api.AugmentationSchema;
-import org.opendaylight.yangtools.yang.model.api.AugmentationTarget;
-import org.opendaylight.yangtools.yang.model.api.DataSchemaNode;
import org.opendaylight.yangtools.yang.model.api.SchemaContext;
import org.opendaylight.yangtools.yang.model.api.SchemaContextListener;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
-import com.google.common.base.Function;
-import com.google.common.base.Optional;
-import com.google.common.base.Preconditions;
-import com.google.common.base.Predicate;
-import com.google.common.collect.ImmutableList;
-import com.google.common.collect.Iterables;
-
-public class BindingToNormalizedNodeCodec implements SchemaContextListener {
+public class BindingToNormalizedNodeCodec implements SchemaContextListener,AutoCloseable {
private static final Logger LOG = LoggerFactory.getLogger(BindingToNormalizedNodeCodec.class);
private final BindingIndependentMappingService bindingToLegacy;
+ private final BindingNormalizedNodeCodecRegistry codecRegistry;
private DataNormalizer legacyToNormalized;
+ private final GeneratedClassLoadingStrategy classLoadingStrategy;
- public BindingToNormalizedNodeCodec(final BindingIndependentMappingService mappingService) {
+ public BindingToNormalizedNodeCodec(final GeneratedClassLoadingStrategy classLoadingStrategy, final BindingIndependentMappingService mappingService, final BindingNormalizedNodeCodecRegistry codecRegistry) {
super();
this.bindingToLegacy = mappingService;
+ this.classLoadingStrategy = classLoadingStrategy;
+ this.codecRegistry = codecRegistry;
+
}
public org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier toNormalized(
final InstanceIdentifier<? extends DataObject> binding) {
-
- // Used instance-identifier codec do not support serialization of last
- // path
- // argument if it is Augmentation (behaviour expected by old datastore)
- // in this case, we explicitly check if last argument is augmentation
- // to process it separately
- if (isAugmentationIdentifier(binding)) {
- return toNormalizedAugmented(binding);
- }
- return toNormalizedImpl(binding);
+ return codecRegistry.toYangInstanceIdentifier(binding);
}
+ @SuppressWarnings({ "unchecked", "rawtypes" })
public Entry<org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier, NormalizedNode<?, ?>> toNormalizedNode(
final InstanceIdentifier<? extends DataObject> bindingPath, final DataObject bindingObject) {
- return toNormalizedNode(toBindingEntry(bindingPath, bindingObject));
+ return codecRegistry.toNormalizedNode((InstanceIdentifier) bindingPath, bindingObject);
}
public Entry<org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier, NormalizedNode<?, ?>> toNormalizedNode(
final Entry<org.opendaylight.yangtools.yang.binding.InstanceIdentifier<? extends DataObject>, DataObject> binding) {
- Entry<org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier, CompositeNode> legacyEntry = bindingToLegacy
- .toDataDom(binding);
- Entry<org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier, NormalizedNode<?, ?>> normalizedEntry = legacyToNormalized
- .toNormalized(legacyEntry);
- LOG.trace("Serialization of {}, Legacy Representation: {}, Normalized Representation: {}", binding,
- legacyEntry, normalizedEntry);
- if (isAugmentation(binding.getKey().getTargetType())) {
-
- for (DataContainerChild<? extends PathArgument, ?> child : ((DataContainerNode<?>) normalizedEntry
- .getValue()).getValue()) {
- if (child instanceof AugmentationNode) {
- ImmutableList<PathArgument> childArgs = ImmutableList.<PathArgument> builder()
- .addAll(normalizedEntry.getKey().getPathArguments()).add(child.getIdentifier()).build();
- org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier childPath = org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier
- .create(childArgs);
- return toDOMEntry(childPath, child);
- }
- }
-
- }
- return normalizedEntry;
-
+ return toNormalizedNode(binding.getKey(),binding.getValue());
}
/**
public Optional<InstanceIdentifier<? extends DataObject>> toBinding(
final org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier normalized)
throws DeserializationException {
-
- PathArgument lastArgument = Iterables.getLast(normalized.getPathArguments());
- // Used instance-identifier codec do not support serialization of last
- // path
- // argument if it is AugmentationIdentifier (behaviour expected by old
- // datastore)
- // in this case, we explicitly check if last argument is augmentation
- // to process it separately
- if (lastArgument instanceof AugmentationIdentifier) {
- return toBindingAugmented(normalized);
- }
- return toBindingImpl(normalized);
- }
-
- private Optional<InstanceIdentifier<? extends DataObject>> toBindingAugmented(
- final org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier normalized)
- throws DeserializationException {
- Optional<InstanceIdentifier<? extends DataObject>> potential = toBindingImpl(normalized);
- // Shorthand check, if codec already supports deserialization
- // of AugmentationIdentifier we will return
- if (potential.isPresent() && isAugmentationIdentifier(potential.get())) {
- return potential;
- }
-
- int normalizedCount = getAugmentationCount(normalized);
- AugmentationIdentifier lastArgument = (AugmentationIdentifier) Iterables.getLast(normalized.getPathArguments());
-
- // Here we employ small trick - Binding-aware Codec injects an pointer
- // to augmentation class
- // if child is referenced - so we will reference child and then shorten
- // path.
- LOG.trace("Looking for candidates to match {}", normalized);
- for (QName child : lastArgument.getPossibleChildNames()) {
- org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier childPath = normalized.node(child);
- try {
- if (isNotRepresentable(childPath)) {
- LOG.trace("Path {} is not BI-representable, skipping it", childPath);
- continue;
- }
- } catch (DataNormalizationException e) {
- LOG.warn("Failed to denormalize path {}, skipping it", childPath, e);
- continue;
- }
-
- Optional<InstanceIdentifier<? extends DataObject>> baId = toBindingImpl(childPath);
- if (!baId.isPresent()) {
- LOG.debug("No binding-aware identifier found for path {}, skipping it", childPath);
- continue;
- }
-
- InstanceIdentifier<? extends DataObject> potentialPath = shortenToLastAugment(baId.get());
- int potentialAugmentCount = getAugmentationCount(potentialPath);
- if (potentialAugmentCount == normalizedCount) {
- LOG.trace("Found matching path {}", potentialPath);
- return Optional.<InstanceIdentifier<? extends DataObject>> of(potentialPath);
- }
-
- LOG.trace("Skipping mis-matched potential path {}", potentialPath);
- }
-
- LOG.trace("Failed to find augmentation matching {}", normalized);
- return Optional.absent();
- }
-
- private Optional<InstanceIdentifier<? extends DataObject>> toBindingImpl(
- final org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier normalized)
- throws DeserializationException {
- org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier legacyPath;
-
try {
- if (isNotRepresentable(normalized)) {
- return Optional.absent();
- }
- legacyPath = legacyToNormalized.toLegacy(normalized);
- } catch (DataNormalizationException e) {
- throw new IllegalStateException("Could not denormalize path.", e);
- }
- LOG.trace("InstanceIdentifier Path Deserialization: Legacy representation {}, Normalized representation: {}",
- legacyPath, normalized);
- return Optional.<InstanceIdentifier<? extends DataObject>> of(bindingToLegacy.fromDataDom(legacyPath));
- }
-
- private boolean isNotRepresentable(final org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier normalized)
- throws DataNormalizationException {
- DataNormalizationOperation<?> op = findNormalizationOperation(normalized);
- if (op.isMixin() && op.getIdentifier() instanceof NodeIdentifier) {
- return true;
- }
- if (op.isLeaf()) {
- return true;
+ return Optional.<InstanceIdentifier<? extends DataObject>>of(codecRegistry.fromYangInstanceIdentifier(normalized));
+ } catch (IllegalArgumentException e) {
+ return Optional.absent();
}
- return false;
}
- private DataNormalizationOperation<?> findNormalizationOperation(
- final org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier normalized)
- throws DataNormalizationException {
- DataNormalizationOperation<?> current = legacyToNormalized.getRootOperation();
- for (PathArgument arg : normalized.getPathArguments()) {
- current = current.getChild(arg);
- }
- return current;
- }
private static final Entry<org.opendaylight.yangtools.yang.binding.InstanceIdentifier<? extends DataObject>, DataObject> toBindingEntry(
final org.opendaylight.yangtools.yang.binding.InstanceIdentifier<? extends DataObject> key,
key, value);
}
- private static final Entry<org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier, NormalizedNode<?, ?>> toDOMEntry(
- final org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier key, final NormalizedNode<?, ?> value) {
- return new SimpleEntry<org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier, NormalizedNode<?, ?>>(key,
- value);
- }
-
- public DataObject toBinding(final InstanceIdentifier<?> path, final NormalizedNode<?, ?> normalizedNode)
- throws DeserializationException {
- CompositeNode legacy = null;
- if (isAugmentationIdentifier(path) && normalizedNode instanceof AugmentationNode) {
- QName augIdentifier = BindingReflections.findQName(path.getTargetType());
- ContainerNode virtualNode = Builders.containerBuilder() //
- .withNodeIdentifier(new NodeIdentifier(augIdentifier)) //
- .withChild((DataContainerChild<?, ?>) normalizedNode) //
- .build();
- legacy = (CompositeNode) DataNormalizer.toLegacy(virtualNode);
- } else {
- legacy = (CompositeNode) DataNormalizer.toLegacy(normalizedNode);
- }
-
- return bindingToLegacy.dataObjectFromDataDom(path, legacy);
- }
-
public DataNormalizer getDataNormalizer() {
return legacyToNormalized;
}
+ @SuppressWarnings("unchecked")
public Optional<Entry<org.opendaylight.yangtools.yang.binding.InstanceIdentifier<? extends DataObject>, DataObject>> toBinding(
final Entry<org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier, ? extends NormalizedNode<?, ?>> normalized)
throws DeserializationException {
- Optional<InstanceIdentifier<? extends DataObject>> potentialPath = toBinding(normalized.getKey());
- if (potentialPath.isPresent()) {
- InstanceIdentifier<? extends DataObject> bindingPath = potentialPath.get();
- DataObject bindingData = toBinding(bindingPath, normalized.getValue());
- if (bindingData == null) {
- LOG.warn("Failed to deserialize {} to Binding format. Binding path is: {}", normalized, bindingPath);
- }
- return Optional.of(toBindingEntry(bindingPath, bindingData));
- } else {
+ try {
+ @SuppressWarnings("rawtypes")
+ Entry binding = codecRegistry.fromNormalizedNode(normalized.getKey(), normalized.getValue());
+ return Optional.<Entry<org.opendaylight.yangtools.yang.binding.InstanceIdentifier<? extends DataObject>, DataObject>>fromNullable(binding);
+ } catch (IllegalArgumentException e) {
return Optional.absent();
}
}
@Override
public void onGlobalContextUpdated(final SchemaContext arg0) {
legacyToNormalized = new DataNormalizer(arg0);
+ codecRegistry.onBindingRuntimeContextUpdated(BindingRuntimeContext.create(classLoadingStrategy, arg0));
}
- private org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier toNormalizedAugmented(
- final InstanceIdentifier<?> augPath) {
- org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier processed = toNormalizedImpl(augPath);
- // If used instance identifier codec added supports for deserialization
- // of last AugmentationIdentifier we will just reuse it
- if (isAugmentationIdentifier(processed)) {
- return processed;
- }
- Optional<org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier> additionalSerialized;
- additionalSerialized = toNormalizedAugmentedUsingChildContainers(augPath, processed);
-
- if (additionalSerialized.isPresent()) {
- return additionalSerialized.get();
- }
- additionalSerialized = toNormalizedAugmentedUsingChildLeafs(augPath, processed);
- if (additionalSerialized.isPresent()) {
- return additionalSerialized.get();
- }
- throw new IllegalStateException("Unabled to construct augmentation identfier for " + augPath);
- }
-
- /**
- * Tries to find correct augmentation identifier using children leafs
- *
- * This method uses normalized Instance Identifier of parent node to fetch
- * schema and {@link BindingReflections#getModuleInfo(Class)} to learn about
- * augmentation namespace, specificly, in which module it was defined.
- *
- * Then it uses it to filter all available augmentations for parent by
- * module. After that it walks augmentations in particular module and
- * pick-up first which at least one leaf name matches supplied augmentation.
- * We could do this safely since YANG explicitly states that no any existing
- * augmentations must differ in leaf fully qualified names.
- *
- *
- * @param augPath
- * Binding Aware Path which ends with augment
- * @param parentPath
- * Processed path
- * @return
- */
- private Optional<org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier> toNormalizedAugmentedUsingChildLeafs(
- final InstanceIdentifier<?> augPath,
- final org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier parentPath) {
- try {
- DataNormalizationOperation<?> parentOp = legacyToNormalized.getOperation(parentPath);
- if(!parentOp.getDataSchemaNode().isPresent()) {
- return Optional.absent();
- }
- DataSchemaNode parentSchema = parentOp.getDataSchemaNode().get();
- if (parentSchema instanceof AugmentationTarget) {
- Set<AugmentationSchema> augmentations = ((AugmentationTarget) parentSchema).getAvailableAugmentations();
- LOG.info("Augmentations for {}, {}", augPath, augmentations);
- Optional<AugmentationSchema> schema = findAugmentation(augPath.getTargetType(), augmentations);
- if (schema.isPresent()) {
- AugmentationIdentifier augmentationIdentifier = DataNormalizationOperation
- .augmentationIdentifierFrom(schema.get());
- return Optional.of(parentPath.node(augmentationIdentifier));
- }
- }
- } catch (DataNormalizationException e) {
- throw new IllegalArgumentException(e);
- }
- return Optional.absent();
- }
-
- /**
- * Creates instance identifier for augmentation child, tries to serialize it
- * Instance Identifier is then shortened to last augmentation.
- *
- * This is for situations, where underlying codec is implementing hydrogen
- * style DOM APIs (which did not supported {@link AugmentationIdentifier}.)
- *
- * @param augPath
- * @param parentPath
- * Path to parent node
- * @return
- */
- @SuppressWarnings("rawtypes")
- private Optional<org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier> toNormalizedAugmentedUsingChildContainers(
- final InstanceIdentifier<?> augPath,
- final org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier parentPath) {
- for (Class augChild : BindingReflections.getChildrenClasses(augPath.getTargetType())) {
- @SuppressWarnings("unchecked")
- InstanceIdentifier<?> childPath = augPath.child(augChild);
- org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier normalized = toNormalizedImpl(childPath);
- org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier potentialDiscovered = shortenToLastAugmentation(
- normalized, parentPath);
- if (potentialDiscovered != null) {
- return Optional.of(potentialDiscovered);
- }
- }
- return Optional.absent();
- }
-
- private Optional<AugmentationSchema> findAugmentation(final Class<?> targetType,
- final Set<AugmentationSchema> augmentations) {
- YangModuleInfo moduleInfo;
- try {
- moduleInfo = BindingReflections.getModuleInfo(targetType);
- } catch (Exception e) {
- throw new IllegalStateException(e);
- }
- Iterable<AugmentationSchema> filtered = filteredByModuleInfo(augmentations,
- BindingReflections.getModuleQName(moduleInfo).getModule());
- filtered.toString();
- Set<String> targetTypeGetters = getYangModeledGetters(targetType);
- for (AugmentationSchema schema : filtered) {
- for (DataSchemaNode child : schema.getChildNodes()) {
- String getterName = "get" + BindingMapping.getClassName(child.getQName());
- if (targetTypeGetters.contains(getterName)) {
- return Optional.of(schema);
- }
- }
- }
- return Optional.absent();
- }
-
- private static Iterable<AugmentationSchema> filteredByModuleInfo(final Iterable<AugmentationSchema> augmentations,
- final QNameModule module) {
- return Iterables.filter(augmentations, new Predicate<AugmentationSchema>() {
- @Override
- public boolean apply(final AugmentationSchema schema) {
- final Collection<DataSchemaNode> childNodes = schema.getChildNodes();
- return !childNodes.isEmpty() && module.equals(Iterables.get(childNodes, 0).getQName().getModule());
- }
- });
- }
-
- public static final Set<String> getYangModeledGetters(final Class<?> targetType) {
- HashSet<String> ret = new HashSet<String>();
- for (Method method : targetType.getMethods()) {
- if (isYangModeledGetter(method)) {
- ret.add(method.getName());
- }
- }
- return ret;
- }
-
- /**
- *
- * Returns true if supplied method represent getter for YANG modeled value
- *
- * @param method
- * Method to be tested
- * @return true if method represent getter for YANG Modeled value.
- */
- private static final boolean isYangModeledGetter(final Method method) {
- return !method.getName().equals("getClass") && !method.getName().equals("getImplementedInterface")
- && method.getName().startsWith("get") && method.getParameterTypes().length == 0;
- }
-
- private org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier shortenToLastAugmentation(
- final org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier normalized,
- final org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier parentPath) {
- int parentSize = Iterables.size(parentPath.getPathArguments());
- int position = 0;
- int foundPosition = -1;
- for (PathArgument arg : normalized.getPathArguments()) {
- position++;
- if (arg instanceof AugmentationIdentifier) {
- foundPosition = position;
- }
- }
- if (foundPosition > 0 && foundPosition > parentSize) {
- Iterable<PathArgument> shortened = Iterables.limit(normalized.getPathArguments(), foundPosition);
- return org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier.create(shortened);
- }
- return null;
- }
-
- private InstanceIdentifier<? extends DataObject> shortenToLastAugment(
- final InstanceIdentifier<? extends DataObject> binding) {
- int position = 0;
- int foundPosition = -1;
- for (org.opendaylight.yangtools.yang.binding.InstanceIdentifier.PathArgument arg : binding.getPathArguments()) {
- position++;
- if (isAugmentation(arg.getType())) {
- foundPosition = position;
- }
- }
- return InstanceIdentifier.create(Iterables.limit(binding.getPathArguments(), foundPosition));
- }
-
- private org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier toNormalizedImpl(
- final InstanceIdentifier<? extends DataObject> binding) {
- final org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier legacyPath = bindingToLegacy
- .toDataDom(binding);
- final org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier normalized = legacyToNormalized
- .toNormalized(legacyPath);
- return normalized;
- }
-
- private static boolean isAugmentation(final Class<? extends DataObject> type) {
- return Augmentation.class.isAssignableFrom(type);
- }
-
- private static boolean isAugmentationIdentifier(final InstanceIdentifier<?> potential) {
- return Augmentation.class.isAssignableFrom(potential.getTargetType());
- }
-
- private boolean isAugmentationIdentifier(final org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier processed) {
- return Iterables.getLast(processed.getPathArguments()) instanceof AugmentationIdentifier;
- }
-
- private static int getAugmentationCount(final InstanceIdentifier<?> potential) {
- int count = 0;
- for (org.opendaylight.yangtools.yang.binding.InstanceIdentifier.PathArgument arg : potential.getPathArguments()) {
- if (isAugmentation(arg.getType())) {
- count++;
- }
-
- }
- return count;
- }
-
- private static int getAugmentationCount(final org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier potential) {
- int count = 0;
- for (PathArgument arg : potential.getPathArguments()) {
- if (arg instanceof AugmentationIdentifier) {
- count++;
- }
- }
- return count;
- }
-
- @SuppressWarnings({ "rawtypes", "unchecked" })
public <T extends DataObject> Function<Optional<NormalizedNode<?, ?>>, Optional<T>> deserializeFunction(final InstanceIdentifier<T> path) {
- return new DeserializeFunction(this, path);
- }
-
- private static class DeserializeFunction<T extends DataObject> implements Function<Optional<NormalizedNode<?, ?>>, Optional<T>> {
-
- private final BindingToNormalizedNodeCodec codec;
- private final InstanceIdentifier<?> path;
-
- public DeserializeFunction(final BindingToNormalizedNodeCodec codec, final InstanceIdentifier<?> path) {
- super();
- this.codec = Preconditions.checkNotNull(codec, "Codec must not be null");
- this.path = Preconditions.checkNotNull(path, "Path must not be null");
- }
-
- @SuppressWarnings("rawtypes")
- @Nullable
- @Override
- public Optional apply(@Nullable final Optional<NormalizedNode<?, ?>> normalizedNode) {
- if (normalizedNode.isPresent()) {
- final DataObject dataObject;
- try {
- dataObject = codec.toBinding(path, normalizedNode.get());
- } catch (DeserializationException e) {
- LOG.warn("Failed to create dataobject from node {}", normalizedNode.get(), e);
- throw new IllegalStateException("Failed to create dataobject", e);
- }
-
- if (dataObject != null) {
- return Optional.of(dataObject);
- }
- }
- return Optional.absent();
- }
+ return codecRegistry.deserializeFunction(path);
}
/**
}
return currentOp.createDefault(path.getLastPathArgument());
}
+
+ public BindingIndependentMappingService getLegacy() {
+ return bindingToLegacy;
+ }
+
+ @Override
+ public void close() throws Exception {
+ // NOOP Intentionally
+ }
}
*/
package org.opendaylight.controller.md.sal.binding.impl;
+import com.google.common.base.Function;
+import com.google.common.util.concurrent.AsyncFunction;
+import com.google.common.util.concurrent.FutureCallback;
+import com.google.common.util.concurrent.Futures;
+import com.google.common.util.concurrent.ListenableFuture;
+import com.google.common.util.concurrent.ListeningExecutorService;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.concurrent.Callable;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ExecutionException;
-
import org.opendaylight.controller.md.sal.common.api.RegistrationListener;
import org.opendaylight.controller.md.sal.common.api.TransactionStatus;
import org.opendaylight.controller.md.sal.common.api.data.AsyncDataBroker.DataChangeScope;
import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
import org.opendaylight.yangtools.yang.common.RpcResult;
import org.opendaylight.yangtools.yang.common.RpcResultBuilder;
-import org.opendaylight.yangtools.yang.data.impl.codec.BindingIndependentMappingService;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
-import com.google.common.base.Function;
-import com.google.common.util.concurrent.AsyncFunction;
-import com.google.common.util.concurrent.FutureCallback;
-import com.google.common.util.concurrent.Futures;
-import com.google.common.util.concurrent.ListenableFuture;
-import com.google.common.util.concurrent.ListeningExecutorService;
-
@SuppressWarnings("deprecation")
public class ForwardedBackwardsCompatibleDataBroker extends AbstractForwardedDataBroker implements DataProviderService, AutoCloseable {
private final ListeningExecutorService executorService;
public ForwardedBackwardsCompatibleDataBroker(final DOMDataBroker domDataBroker,
- final BindingIndependentMappingService mappingService, final SchemaService schemaService,final ListeningExecutorService executor) {
+ final BindingToNormalizedNodeCodec mappingService, final SchemaService schemaService,final ListeningExecutorService executor) {
super(domDataBroker, mappingService,schemaService);
executorService = executor;
LOG.info("ForwardedBackwardsCompatibleBroker started.");
import org.opendaylight.controller.md.sal.common.api.data.TransactionChainListener;
import org.opendaylight.controller.md.sal.dom.api.DOMDataBroker;
import org.opendaylight.controller.sal.core.api.model.SchemaService;
-import org.opendaylight.yangtools.yang.data.impl.codec.BindingIndependentMappingService;
/**
* The DataBrokerImpl simply defers to the DOMDataBroker for all its operations.
*/
public class ForwardedBindingDataBroker extends AbstractForwardedDataBroker implements DataBroker {
- public ForwardedBindingDataBroker(final DOMDataBroker domDataBroker, final BindingIndependentMappingService mappingService, final SchemaService schemaService) {
- super(domDataBroker, mappingService,schemaService);
+ public ForwardedBindingDataBroker(final DOMDataBroker domDataBroker, final BindingToNormalizedNodeCodec codec, final SchemaService schemaService) {
+ super(domDataBroker, codec,schemaService);
}
@Override
*/
package org.opendaylight.controller.sal.binding.codegen.impl;
+import com.google.common.util.concurrent.ForwardingBlockingQueue;
+import com.google.common.util.concurrent.ListeningExecutorService;
+import com.google.common.util.concurrent.MoreExecutors;
+import com.google.common.util.concurrent.ThreadFactoryBuilder;
import java.util.concurrent.BlockingQueue;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.ThreadFactory;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;
-
import javassist.ClassPool;
-
import org.apache.commons.lang3.StringUtils;
import org.opendaylight.controller.sal.binding.codegen.RuntimeCodeGenerator;
import org.opendaylight.controller.sal.binding.spi.NotificationInvokerFactory;
+import org.opendaylight.yangtools.sal.binding.generator.util.JavassistUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
-import com.google.common.util.concurrent.ForwardingBlockingQueue;
-import com.google.common.util.concurrent.ListeningExecutorService;
-import com.google.common.util.concurrent.MoreExecutors;
-import com.google.common.util.concurrent.ThreadFactoryBuilder;
-
public class SingletonHolder {
private static final Logger logger = LoggerFactory.getLogger(SingletonHolder.class);
public static final ClassPool CLASS_POOL = ClassPool.getDefault();
+ public static final JavassistUtils JAVASSIST = JavassistUtils.forClassPool(CLASS_POOL);
public static final org.opendaylight.controller.sal.binding.codegen.impl.RuntimeCodeGenerator RPC_GENERATOR_IMPL = new org.opendaylight.controller.sal.binding.codegen.impl.RuntimeCodeGenerator(
CLASS_POOL);
public static final RuntimeCodeGenerator RPC_GENERATOR = RPC_GENERATOR_IMPL;
+++ /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.sal.binding.impl;\r
-\r
-import org.opendaylight.controller.config.yang.md.sal.binding.impl.Data;\r
-import org.opendaylight.controller.config.yang.md.sal.binding.impl.DataBrokerImplRuntimeMXBean;\r
-import org.opendaylight.controller.config.yang.md.sal.binding.impl.DataBrokerImplRuntimeRegistration;\r
-import org.opendaylight.controller.config.yang.md.sal.binding.impl.DataBrokerImplRuntimeRegistrator;\r
-import org.opendaylight.controller.config.yang.md.sal.binding.impl.Transactions;\r
-import org.opendaylight.controller.sal.binding.impl.connect.dom.BindingIndependentConnector;\r
-\r
-public class RootDataBrokerImpl extends DataBrokerImpl implements DataBrokerImplRuntimeMXBean {\r
-\r
- private final Transactions transactions = new Transactions();\r
- private final Data data = new Data();\r
- private BindingIndependentConnector bindingIndependentConnector;\r
- private DataBrokerImplRuntimeRegistration runtimeBeanRegistration;\r
-\r
- public BindingIndependentConnector getBindingIndependentConnector() {\r
- return bindingIndependentConnector;\r
- }\r
-\r
- public Transactions getTransactions() {\r
- transactions.setCreated(getCreatedTransactionsCount().get());\r
- transactions.setSubmitted(getSubmittedTransactionsCount().get());\r
- transactions.setSuccessful(getFinishedTransactionsCount().get());\r
- transactions.setFailed(getFailedTransactionsCount().get());\r
- return transactions;\r
- }\r
-\r
- @Override\r
- public Data getData() {\r
- data.setTransactions(getTransactions());\r
- return data;\r
- }\r
-\r
- public void setBindingIndependentConnector(BindingIndependentConnector runtimeMapping) {\r
- this.bindingIndependentConnector = runtimeMapping;\r
- }\r
-\r
- public void registerRuntimeBean(DataBrokerImplRuntimeRegistrator rootRegistrator) {\r
- runtimeBeanRegistration = rootRegistrator.register(this);\r
- }\r
-\r
-}\r
+++ /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.sal.binding.impl.forward;
-
-import java.util.Collection;
-import java.util.Collections;
-
-import org.opendaylight.controller.sal.binding.impl.RootDataBrokerImpl;
-import org.opendaylight.controller.sal.binding.impl.connect.dom.BindingDomConnectorDeployer;
-import org.opendaylight.controller.sal.binding.impl.connect.dom.BindingIndependentConnector;
-import org.opendaylight.controller.sal.core.api.Provider;
-import org.opendaylight.controller.sal.core.api.Broker.ProviderSession;
-
-public class DomForwardedDataBrokerImpl extends RootDataBrokerImpl implements Provider, DomForwardedBroker {
-
- private BindingIndependentConnector connector;
- private ProviderSession domProviderContext;
-
- public void setConnector(BindingIndependentConnector connector) {
- this.connector = connector;
- }
-
- @Override
- public void onSessionInitiated(ProviderSession session) {
- this.setDomProviderContext(session);
- }
-
- @Override
- public Collection<ProviderFunctionality> getProviderFunctionality() {
- return Collections.emptySet();
- }
-
- @Override
- public BindingIndependentConnector getConnector() {
- return connector;
- }
-
- @Override
- public ProviderSession getDomProviderContext() {
- return domProviderContext;
- }
-
- public void setDomProviderContext(ProviderSession domProviderContext) {
- this.domProviderContext = domProviderContext;
- }
-
- @Override
- public void startForwarding() {
- BindingDomConnectorDeployer.startDataForwarding(getConnector(), this, getDomProviderContext());
- }
-}
identity binding-dom-mapping-service {
base config:service-type;
- config:java-class "org.opendaylight.yangtools.yang.data.impl.codec.BindingIndependentMappingService";
+ config:java-class "org.opendaylight.controller.md.sal.binding.impl.BindingToNormalizedNodeCodec";
}
-
identity binding-broker-impl {
base config:module-type;
config:provided-service sal:binding-broker-osgi-registry;
config:java-name-prefix BindingBrokerImpl;
}
- identity binding-data-broker {
- base config:module-type;
- config:provided-service sal:binding-data-broker;
- config:provided-service sal:binding-data-consumer-broker;
- config:java-name-prefix DataBrokerImpl;
- }
-
identity binding-data-compatible-broker {
base config:module-type;
config:provided-service sal:binding-data-broker;
}
}
- augment "/config:modules/config:module/config:configuration" {
- case binding-data-broker {
- when "/config:modules/config:module/config:type = 'binding-data-broker'";
- container dom-broker {
- uses config:service-ref {
- refine type {
- mandatory true;
- config:required-identity dom:dom-broker-osgi-registry;
- }
- }
- }
-
- container mapping-service {
- uses config:service-ref {
- refine type {
- mandatory true;
- config:required-identity binding-dom-mapping-service;
- }
- }
- }
- }
- }
-
augment "/config:modules/config:module/config:configuration" {
case binding-data-compatible-broker {
when "/config:modules/config:module/config:type = 'binding-data-compatible-broker'";
}
}
- augment "/config:modules/config:module/config:state" {
- case binding-data-broker {
- when "/config:modules/config:module/config:type = 'binding-data-broker'";
- container data {
- uses common:data-state;
- }
- }
- }
augment "/config:modules/config:module/config:state" {
case binding-rpc-broker {
when "/config:modules/config:module/config:type = 'binding-rpc-broker'";
package org.opendaylight.controller.md.sal.binding.impl.test;
import static org.junit.Assert.assertTrue;
-import javassist.ClassPool;
+import javassist.ClassPool;
import org.junit.Test;
import org.opendaylight.controller.md.sal.binding.impl.BindingToNormalizedNodeCodec;
import org.opendaylight.controller.md.sal.binding.test.AbstractSchemaAwareTest;
import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.controller.md.sal.test.list.rev140701.Top;
import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.controller.md.sal.test.list.rev140701.two.level.list.TopLevelList;
import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.controller.md.sal.test.list.rev140701.two.level.list.TopLevelListKey;
+import org.opendaylight.yangtools.binding.data.codec.gen.impl.StreamWriterGenerator;
+import org.opendaylight.yangtools.binding.data.codec.impl.BindingNormalizedNodeCodecRegistry;
+import org.opendaylight.yangtools.sal.binding.generator.impl.GeneratedClassLoadingStrategy;
import org.opendaylight.yangtools.sal.binding.generator.impl.RuntimeGeneratedMappingServiceImpl;
+import org.opendaylight.yangtools.sal.binding.generator.util.JavassistUtils;
import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
import org.opendaylight.yangtools.yang.common.QName;
import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier.AugmentationIdentifier;
@Override
protected void setupWithSchema(final SchemaContext context) {
mappingService = new RuntimeGeneratedMappingServiceImpl(ClassPool.getDefault());
- codec = new BindingToNormalizedNodeCodec(mappingService);
+ StreamWriterGenerator streamWriter = new StreamWriterGenerator(JavassistUtils.forClassPool(ClassPool.getDefault()));
+ BindingNormalizedNodeCodecRegistry registry = new BindingNormalizedNodeCodecRegistry(streamWriter);
+ codec = new BindingToNormalizedNodeCodec(GeneratedClassLoadingStrategy.getTCCLClassLoadingStrategy(), mappingService, registry);
mappingService.onGlobalContextUpdated(context);
codec.onGlobalContextUpdated(context);
};
*/
package org.opendaylight.controller.md.sal.binding.test;
+import com.google.common.collect.ImmutableMap;
+import com.google.common.util.concurrent.ListeningExecutorService;
+import com.google.common.util.concurrent.MoreExecutors;
+
import javassist.ClassPool;
import org.opendaylight.controller.md.sal.binding.api.DataBroker;
+import org.opendaylight.controller.md.sal.binding.impl.BindingToNormalizedNodeCodec;
import org.opendaylight.controller.md.sal.binding.impl.ForwardedBackwardsCompatibleDataBroker;
import org.opendaylight.controller.md.sal.binding.impl.ForwardedBindingDataBroker;
import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType;
import org.opendaylight.controller.sal.binding.test.util.MockSchemaService;
import org.opendaylight.controller.sal.core.api.model.SchemaService;
import org.opendaylight.controller.sal.core.spi.data.DOMStore;
+import org.opendaylight.yangtools.binding.data.codec.gen.impl.DataObjectSerializerGenerator;
+import org.opendaylight.yangtools.binding.data.codec.gen.impl.StreamWriterGenerator;
+import org.opendaylight.yangtools.binding.data.codec.impl.BindingNormalizedNodeCodecRegistry;
+import org.opendaylight.yangtools.sal.binding.generator.impl.GeneratedClassLoadingStrategy;
import org.opendaylight.yangtools.sal.binding.generator.impl.RuntimeGeneratedMappingServiceImpl;
+import org.opendaylight.yangtools.sal.binding.generator.util.JavassistUtils;
import org.opendaylight.yangtools.yang.data.impl.codec.BindingIndependentMappingService;
import org.opendaylight.yangtools.yang.model.api.SchemaContext;
-import com.google.common.collect.ImmutableMap;
-import com.google.common.util.concurrent.ListeningExecutorService;
-import com.google.common.util.concurrent.MoreExecutors;
-
public class DataBrokerTestCustomizer {
private DOMDataBroker domDataBroker;
private final RuntimeGeneratedMappingServiceImpl mappingService;
private final MockSchemaService schemaService;
private ImmutableMap<LogicalDatastoreType, DOMStore> datastores;
+ private final BindingToNormalizedNodeCodec bindingToNormalized ;
public ImmutableMap<LogicalDatastoreType, DOMStore> createDatastores() {
return ImmutableMap.<LogicalDatastoreType, DOMStore>builder()
public DataBrokerTestCustomizer() {
schemaService = new MockSchemaService();
- mappingService = new RuntimeGeneratedMappingServiceImpl(ClassPool.getDefault());
+ ClassPool pool = ClassPool.getDefault();
+ mappingService = new RuntimeGeneratedMappingServiceImpl(pool);
+ DataObjectSerializerGenerator generator = StreamWriterGenerator.create(JavassistUtils.forClassPool(pool));
+ BindingNormalizedNodeCodecRegistry codecRegistry = new BindingNormalizedNodeCodecRegistry(generator);
+ GeneratedClassLoadingStrategy loading = GeneratedClassLoadingStrategy.getTCCLClassLoadingStrategy();
+ bindingToNormalized = new BindingToNormalizedNodeCodec(loading, mappingService, codecRegistry);
+ schemaService.registerSchemaContextListener(bindingToNormalized);
}
public DOMStore createConfigurationDatastore() {
}
public DataBroker createDataBroker() {
- return new ForwardedBindingDataBroker(getDOMDataBroker(), getMappingService(), getSchemaService());
+ return new ForwardedBindingDataBroker(getDOMDataBroker(), bindingToNormalized, schemaService );
}
public ForwardedBackwardsCompatibleDataBroker createBackwardsCompatibleDataBroker() {
- return new ForwardedBackwardsCompatibleDataBroker(getDOMDataBroker(), getMappingService(), getSchemaService(), MoreExecutors.sameThreadExecutor());
+ return new ForwardedBackwardsCompatibleDataBroker(getDOMDataBroker(), bindingToNormalized, getSchemaService(), MoreExecutors.sameThreadExecutor());
}
-
private SchemaService getSchemaService() {
return schemaService;
}
import java.util.Collections;
import java.util.List;
import java.util.Map;
-
import org.junit.Test;
import org.opendaylight.controller.md.sal.common.api.TransactionStatus;
import org.opendaylight.controller.md.sal.common.api.data.DataChangeEvent;
*
* @throws Exception
*/
- @Test( timeout = 15000)
+ @Test()
public void testAugmentSerialization() throws Exception {
baDataService.registerDataChangeListener(NODES_INSTANCE_ID_BA, this);
testNodeRemove();
}
- private <T extends Augmentation<Node>> Node createTestNode(Class<T> augmentationClass, T augmentation) {
+ private <T extends Augmentation<Node>> Node createTestNode(final Class<T> augmentationClass, final T augmentation) {
NodeBuilder nodeBuilder = new NodeBuilder();
nodeBuilder.setId(new NodeId(NODE_ID));
nodeBuilder.setKey(NODE_KEY);
return nodeBuilder.build();
}
- private DataModificationTransaction commitNodeAndVerifyTransaction(Node original) throws Exception {
+ private DataModificationTransaction commitNodeAndVerifyTransaction(final Node original) throws Exception {
DataModificationTransaction transaction = baDataService.beginTransaction();
transaction.putOperationalData(NODE_INSTANCE_ID_BA, original);
RpcResult<TransactionStatus> result = transaction.commit().get();
assertNull(node);
}
- private AugmentationVerifier<Node> verifyNode(Nodes nodes, Node original) {
+ private AugmentationVerifier<Node> verifyNode(final Nodes nodes, final Node original) {
assertNotNull(nodes);
assertNotNull(nodes.getNode());
assertEquals(1, nodes.getNode().size());
return new AugmentationVerifier<Node>(readedNode);
}
- private void assertBindingIndependentVersion(org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier nodeId) {
+ private void assertBindingIndependentVersion(final org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier nodeId) {
CompositeNode node = biDataService.readOperationalData(nodeId);
assertNotNull(node);
}
return nodeMeterStatistics(10, false);
}
- private NodeMeterStatistics nodeMeterStatistics(int count, boolean setDuration) {
+ private NodeMeterStatistics nodeMeterStatistics(final int count, final boolean setDuration) {
NodeMeterStatisticsBuilder nmsb = new NodeMeterStatisticsBuilder();
MeterStatisticsBuilder meterStats = new MeterStatisticsBuilder();
}
@Override
- public void onDataChanged(DataChangeEvent<InstanceIdentifier<?>, DataObject> change) {
+ public void onDataChanged(final DataChangeEvent<InstanceIdentifier<?>, DataObject> change) {
receivedChangeEvent = change;
}
import static com.google.common.base.Preconditions.checkState;
+import com.google.common.annotations.Beta;
+import com.google.common.collect.ClassToInstanceMap;
+import com.google.common.collect.ImmutableClassToInstanceMap;
+import com.google.common.collect.ImmutableMap;
+import com.google.common.collect.ImmutableSet;
+import com.google.common.collect.MutableClassToInstanceMap;
+import com.google.common.util.concurrent.ListeningExecutorService;
+import com.google.common.util.concurrent.MoreExecutors;
import java.util.Set;
import java.util.concurrent.Future;
-
import javassist.ClassPool;
-
import org.opendaylight.controller.md.sal.binding.api.DataBroker;
+import org.opendaylight.controller.md.sal.binding.impl.BindingToNormalizedNodeCodec;
import org.opendaylight.controller.md.sal.binding.impl.ForwardedBackwardsCompatibleDataBroker;
import org.opendaylight.controller.md.sal.binding.impl.ForwardedBindingDataBroker;
import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType;
import org.opendaylight.controller.sal.dom.broker.BrokerImpl;
import org.opendaylight.controller.sal.dom.broker.MountPointManagerImpl;
import org.opendaylight.controller.sal.dom.broker.impl.SchemaAwareRpcBroker;
+import org.opendaylight.yangtools.binding.data.codec.gen.impl.DataObjectSerializerGenerator;
+import org.opendaylight.yangtools.binding.data.codec.gen.impl.StreamWriterGenerator;
+import org.opendaylight.yangtools.binding.data.codec.impl.BindingNormalizedNodeCodecRegistry;
import org.opendaylight.yangtools.concepts.ListenerRegistration;
+import org.opendaylight.yangtools.sal.binding.generator.impl.GeneratedClassLoadingStrategy;
import org.opendaylight.yangtools.sal.binding.generator.impl.ModuleInfoBackedContext;
import org.opendaylight.yangtools.sal.binding.generator.impl.RuntimeGeneratedMappingServiceImpl;
+import org.opendaylight.yangtools.sal.binding.generator.util.JavassistUtils;
import org.opendaylight.yangtools.yang.binding.YangModuleInfo;
import org.opendaylight.yangtools.yang.binding.util.BindingReflections;
import org.opendaylight.yangtools.yang.common.QName;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
-import com.google.common.annotations.Beta;
-import com.google.common.collect.ClassToInstanceMap;
-import com.google.common.collect.ImmutableClassToInstanceMap;
-import com.google.common.collect.ImmutableMap;
-import com.google.common.collect.ImmutableSet;
-import com.google.common.collect.MutableClassToInstanceMap;
-import com.google.common.util.concurrent.ListeningExecutorService;
-import com.google.common.util.concurrent.MoreExecutors;
-
@Beta
public class BindingTestContext implements AutoCloseable {
private static final Logger LOG = LoggerFactory.getLogger(BindingTestContext.class);
private RuntimeGeneratedMappingServiceImpl mappingServiceImpl;
+ private BindingToNormalizedNodeCodec codec;
private DomForwardedBindingBrokerImpl baBrokerImpl;
private DataBrokerImpl baDataImpl;
public void startNewDataBroker() {
checkState(executor != null, "Executor needs to be set");
checkState(newDOMDataBroker != null, "DOM Data Broker must be set");
- dataBroker = new ForwardedBindingDataBroker(newDOMDataBroker, mappingServiceImpl, mockSchemaService);
+ dataBroker = new ForwardedBindingDataBroker(newDOMDataBroker, codec, mockSchemaService);
}
public void startNewDomDataBroker() {
checkState(classPool != null, "ClassPool needs to be present");
mappingServiceImpl = new RuntimeGeneratedMappingServiceImpl(classPool);
mockSchemaService.registerSchemaContextListener(mappingServiceImpl);
+
+ DataObjectSerializerGenerator generator = StreamWriterGenerator.create(JavassistUtils.forClassPool(classPool));
+ BindingNormalizedNodeCodecRegistry codecRegistry = new BindingNormalizedNodeCodecRegistry(generator);
+ GeneratedClassLoadingStrategy loading = GeneratedClassLoadingStrategy.getTCCLClassLoadingStrategy();
+ codec = new BindingToNormalizedNodeCodec(loading, mappingServiceImpl, codecRegistry);
+ mockSchemaService.registerSchemaContextListener(codec);
}
private void updateYangSchema(final ImmutableSet<YangModuleInfo> moduleInfos) {
}
public void startNewBindingDataBroker() {
- ForwardedBackwardsCompatibleDataBroker forwarded = new ForwardedBackwardsCompatibleDataBroker(newDOMDataBroker, mappingServiceImpl,mockSchemaService, executor);
+ ForwardedBackwardsCompatibleDataBroker forwarded = new ForwardedBackwardsCompatibleDataBroker(newDOMDataBroker, codec,mockSchemaService, executor);
baData = forwarded;
}
mavenBundle(YANGTOOLS, "binding-generator-api").versionAsInProject(), mavenBundle(YANGTOOLS,
"binding-generator-spi").versionAsInProject(), //
mavenBundle(YANGTOOLS, "binding-generator-impl").versionAsInProject(),
+ mavenBundle(YANGTOOLS, "binding-data-codec").versionAsInProject(),
mavenBundle(YANGTOOLS + ".thirdparty", "antlr4-runtime-osgi-nohead").versionAsInProject(), // //
mavenBundle(CONTROLLER, "sal-core-api").versionAsInProject().update(), //
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertNull;
+import com.google.inject.Inject;
import java.util.concurrent.Future;
-
import org.junit.Before;
+import org.junit.Ignore;
import org.junit.Test;
import org.opendaylight.controller.md.sal.common.api.TransactionStatus;
import org.opendaylight.controller.sal.binding.api.BindingAwareBroker.ConsumerContext;
import org.opendaylight.controller.sal.binding.api.data.DataModificationTransaction;
import org.opendaylight.controller.sal.core.api.Broker;
import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.NodeId;
-import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.NodeRef;
import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.Nodes;
import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.nodes.Node;
import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.nodes.NodeBuilder;
import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
import org.opendaylight.yangtools.yang.common.RpcResult;
-import com.google.inject.Inject;
-
public class DataServiceTest extends AbstractTest {
protected DataBrokerService consumerDataService;
public void setUp() throws Exception {
}
+ /*
+ *
+ * Ignored this, because classes here are constructed from
+ * very different class loader as MD-SAL is run into,
+ * this is code is run from different classloader.
+ *
+ */
@Test
+ @Ignore
public void test() throws Exception {
BindingAwareConsumer consumer1 = new BindingAwareConsumer() {
@Override
- public void onSessionInitialized(ConsumerContext session) {
+ public void onSessionInitialized(final ConsumerContext session) {
consumerDataService = session.getSALService(DataBrokerService.class);
}
};
DataModificationTransaction transaction = consumerDataService.beginTransaction();
assertNotNull(transaction);
- NodeRef node1 = createNodeRef("0");
- DataObject node = consumerDataService.readConfigurationData(node1.getValue());
+ InstanceIdentifier<Node> node1 = createNodeRef("0");
+ DataObject node = consumerDataService.readConfigurationData(node1);
assertNull(node);
Node nodeData1 = createNode("0");
- transaction.putConfigurationData(node1.getValue(), nodeData1);
+ transaction.putConfigurationData(node1, nodeData1);
Future<RpcResult<TransactionStatus>> commitResult = transaction.commit();
assertNotNull(commitResult);
assertNotNull(result.getResult());
assertEquals(TransactionStatus.COMMITED, result.getResult());
- Node readedData = (Node) consumerDataService.readConfigurationData(node1.getValue());
+ Node readedData = (Node) consumerDataService.readConfigurationData(node1);
assertNotNull(readedData);
assertEquals(nodeData1.getKey(), readedData.getKey());
DataModificationTransaction transaction2 = consumerDataService.beginTransaction();
assertNotNull(transaction);
- transaction2.removeConfigurationData(node1.getValue());
+ transaction2.removeConfigurationData(node1);
Future<RpcResult<TransactionStatus>> commitResult2 = transaction2.commit();
assertNotNull(commitResult2);
assertNotNull(result2.getResult());
assertEquals(TransactionStatus.COMMITED, result2.getResult());
- DataObject readedData2 = consumerDataService.readConfigurationData(node1.getValue());
+ DataObject readedData2 = consumerDataService.readConfigurationData(node1);
assertNull(readedData2);
}
- private static NodeRef createNodeRef(String string) {
+ private static InstanceIdentifier<Node> createNodeRef(final String string) {
NodeKey key = new NodeKey(new NodeId(string));
- InstanceIdentifier<Node> path = InstanceIdentifier.builder(Nodes.class).child(Node.class, key).build();
-
- return new NodeRef(path);
+ return InstanceIdentifier.builder(Nodes.class).child(Node.class, key).build();
}
- private static Node createNode(String string) {
+ private static Node createNode(final String string) {
NodeBuilder ret = new NodeBuilder();
NodeId id = new NodeId(string);
ret.setKey(new NodeKey(id));
<data xmlns="urn:ietf:params:xml:ns:netconf:base:1.0">
<modules xmlns="urn:opendaylight:params:xml:ns:yang:controller:config">
<module>
- <type xmlns:prefix="urn:opendaylight:params:xml:ns:yang:controller:md:sal:dom:impl">
- prefix:schema-service-singleton
- </type>
+ <type xmlns:prefix="urn:opendaylight:params:xml:ns:yang:controller:md:sal:dom:impl">prefix:schema-service-singleton</type>
<name>yang-schema-service</name>
</module>
<module>
- <type xmlns:prefix="urn:opendaylight:params:xml:ns:yang:controller:md:sal:dom:impl">
- prefix:hash-map-data-store
- </type>
- <name>hash-map-data-store</name>
+ <type xmlns:prefix="urn:opendaylight:params:xml:ns:yang:controller:md:sal:binding:impl">prefix:runtime-generated-mapping</type>
+ <name>runtime-mapping-singleton</name>
</module>
<module>
- <type xmlns:prefix="urn:opendaylight:params:xml:ns:yang:controller:md:sal:dom:impl">
- prefix:dom-broker-impl
- </type>
- <name>dom-broker</name>
- <data-store xmlns="urn:opendaylight:params:xml:ns:yang:controller:md:sal:dom:impl">
- <type xmlns:dom="urn:opendaylight:params:xml:ns:yang:controller:md:sal:dom">
- dom:dom-data-store
- </type>
- <name>ref_hash-map-data-store</name>
- </data-store>
+ <type xmlns:prefix="urn:opendaylight:params:xml:ns:yang:controller:md:sal:binding:impl">prefix:binding-notification-broker</type>
+ <name>binding-notification-broker</name>
</module>
<module>
- <type xmlns:prefix="urn:opendaylight:params:xml:ns:yang:controller:md:sal:binding:impl">
- prefix:binding-broker-impl
- </type>
+ <type xmlns:prefix="urn:opendaylight:params:xml:ns:yang:controller:md:sal:binding:impl">prefix:binding-broker-impl</type>
<name>binding-broker-impl</name>
- <notification-service
- xmlns="urn:opendaylight:params:xml:ns:yang:controller:md:sal:binding:impl">
- <type xmlns:binding="urn:opendaylight:params:xml:ns:yang:controller:md:sal:binding">
- binding:binding-notification-service
- </type>
- <name>ref_binding-notification-broker</name>
+ <notification-service xmlns="urn:opendaylight:params:xml:ns:yang:controller:md:sal:binding:impl">
+ <type xmlns:binding="urn:opendaylight:params:xml:ns:yang:controller:md:sal:binding">binding:binding-notification-service</type>
+ <name>binding-notification-broker</name>
</notification-service>
<data-broker xmlns="urn:opendaylight:params:xml:ns:yang:controller:md:sal:binding:impl">
- <type xmlns:binding="urn:opendaylight:params:xml:ns:yang:controller:md:sal:binding">
- binding:binding-data-broker
- </type>
- <name>ref_binding-data-broker</name>
+ <type xmlns:binding="urn:opendaylight:params:xml:ns:yang:controller:md:sal:binding">binding:binding-data-broker</type>
+ <name>binding-data-broker</name>
</data-broker>
</module>
+ <!--
+ Tree-based in-memory data store. This is the data store which is currently
+ recommended for single-node deployments.
+ -->
<module>
- <type xmlns:prefix="urn:opendaylight:params:xml:ns:yang:controller:md:sal:binding:impl">
- prefix:runtime-generated-mapping
- </type>
- <name>runtime-mapping-singleton</name>
+ <type xmlns:prefix="urn:opendaylight:params:xml:ns:yang:controller:md:sal:dom:impl">prefix:dom-inmemory-data-broker</type>
+ <name>inmemory-data-broker</name>
+ <schema-service>
+ <type xmlns:dom="urn:opendaylight:params:xml:ns:yang:controller:md:sal:dom">dom:schema-service</type>
+ <name>yang-schema-service</name>
+ </schema-service>
</module>
<module>
- <type xmlns:prefix="urn:opendaylight:params:xml:ns:yang:controller:md:sal:binding:impl">
- prefix:binding-notification-broker
- </type>
- <name>binding-notification-broker</name>
+ <type xmlns:prefix="urn:opendaylight:params:xml:ns:yang:controller:md:sal:dom:impl">prefix:dom-broker-impl</type>
+ <name>inmemory-dom-broker</name>
+ <async-data-broker>
+ <type xmlns:dom="urn:opendaylight:params:xml:ns:yang:controller:md:sal:dom">dom:dom-async-data-broker</type>
+ <name>inmemory-data-broker</name>
+ </async-data-broker>
</module>
<module>
- <type xmlns:prefix="urn:opendaylight:params:xml:ns:yang:controller:md:sal:binding:impl">
- prefix:binding-data-broker
- </type>
- <name>binding-data-broker</name>
- <dom-broker xmlns="urn:opendaylight:params:xml:ns:yang:controller:md:sal:binding:impl">
- <type xmlns:dom="urn:opendaylight:params:xml:ns:yang:controller:md:sal:dom">
- dom:dom-broker-osgi-registry
- </type>
- <name>ref_dom-broker</name>
- </dom-broker>
- <mapping-service xmlns="urn:opendaylight:params:xml:ns:yang:controller:md:sal:binding:impl">
- <type xmlns:binding="urn:opendaylight:params:xml:ns:yang:controller:md:sal:binding:impl">
- binding:binding-dom-mapping-service
- </type>
- <name>ref_runtime-mapping-singleton</name>
- </mapping-service>
+ <type xmlns:prefix="urn:opendaylight:params:xml:ns:yang:controller:md:sal:binding:impl">prefix:binding-data-compatible-broker</type>
+ <name>inmemory-binding-data-broker</name>
+ <dom-async-broker xmlns="urn:opendaylight:params:xml:ns:yang:controller:md:sal:binding:impl">
+ <type xmlns:dom="urn:opendaylight:params:xml:ns:yang:controller:md:sal:dom">dom:dom-broker-osgi-registry</type>
+ <name>dom-broker</name>
+ </dom-async-broker>
+ <binding-mapping-service xmlns="urn:opendaylight:params:xml:ns:yang:controller:md:sal:binding:impl">
+ <type xmlns:binding="urn:opendaylight:params:xml:ns:yang:controller:md:sal:binding:impl">binding:binding-dom-mapping-service</type>
+ <name>runtime-mapping-singleton</name>
+ </binding-mapping-service>
+ </module>
+ <module>
+ <type xmlns:prefix="urn:opendaylight:params:xml:ns:yang:controller:md:sal:binding:impl">prefix:binding-forwarded-data-broker</type>
+ <name>binding-async-data-broker</name>
+ <binding-forwarded-data-broker xmlns="urn:opendaylight:params:xml:ns:yang:controller:md:sal:binding:impl">
+ <dom-async-broker>
+ <type xmlns:dom="urn:opendaylight:params:xml:ns:yang:controller:md:sal:dom">dom:dom-broker-osgi-registry</type>
+ <name>dom-broker</name>
+ </dom-async-broker>
+ <binding-mapping-service>
+ <type xmlns:binding="urn:opendaylight:params:xml:ns:yang:controller:md:sal:binding:impl">binding:binding-dom-mapping-service</type>
+ <name>runtime-mapping-singleton</name>
+ </binding-mapping-service>
+ </binding-forwarded-data-broker>
</module>
</modules>
<services xmlns="urn:opendaylight:params:xml:ns:yang:controller:config">
<service>
- <type xmlns:dom="urn:opendaylight:params:xml:ns:yang:controller:md:sal:dom">
- dom:schema-service
- </type>
+ <type xmlns:dom="urn:opendaylight:params:xml:ns:yang:controller:md:sal:dom">dom:schema-service</type>
<instance>
- <name>ref_yang-schema-service</name>
- <provider>
- /config/modules/module[name='schema-service-singleton']/instance[name='yang-schema-service']
- </provider>
+ <name>yang-schema-service</name>
+ <provider>/modules/module[type='schema-service-singleton'][name='yang-schema-service']</provider>
</instance>
</service>
<service>
- <type xmlns:binding="urn:opendaylight:params:xml:ns:yang:controller:md:sal:binding">
- binding:binding-notification-service
- </type>
+ <type xmlns:binding-impl="urn:opendaylight:params:xml:ns:yang:controller:md:sal:binding:impl">binding-impl:binding-dom-mapping-service</type>
<instance>
- <name>ref_binding-notification-broker</name>
- <provider>
- /config/modules/module[name='binding-notification-broker']/instance[name='binding-notification-broker']
- </provider>
+ <name>runtime-mapping-singleton</name>
+ <provider>/modules/module[type='runtime-generated-mapping'][name='runtime-mapping-singleton']</provider>
</instance>
</service>
<service>
- <type xmlns:dom="urn:opendaylight:params:xml:ns:yang:controller:md:sal:dom">
- dom:dom-data-store
- </type>
+ <type xmlns:binding="urn:opendaylight:params:xml:ns:yang:controller:md:sal:binding">binding:binding-notification-service</type>
<instance>
- <name>ref_hash-map-data-store</name>
- <provider>
- /config/modules/module[name='hash-map-data-store']/instance[name='hash-map-data-store']
- </provider>
+ <name>binding-notification-broker</name>
+ <provider>/modules/module[type='binding-notification-broker'][name='binding-notification-broker']</provider>
</instance>
</service>
-
<service>
- <type xmlns:binding="urn:opendaylight:params:xml:ns:yang:controller:md:sal:binding">
- binding:binding-broker-osgi-registry
- </type>
+ <type xmlns:binding="urn:opendaylight:params:xml:ns:yang:controller:md:sal:binding">binding:binding-broker-osgi-registry</type>
<instance>
- <name>ref_binding-broker-impl</name>
- <provider>
- /config/modules/module[name='binding-broker-impl']/instance[name='binding-broker-impl']
- </provider>
+ <name>binding-osgi-broker</name>
+ <provider>/modules/module[type='binding-broker-impl'][name='binding-broker-impl']</provider>
</instance>
</service>
<service>
<provider>/modules/module[type='binding-broker-impl'][name='binding-broker-impl']</provider>
</instance>
</service>
+
+ <service>
+ <type xmlns:dom="urn:opendaylight:params:xml:ns:yang:controller:md:sal:dom">dom:dom-broker-osgi-registry</type>
+ <instance>
+ <name>dom-broker</name>
+ <provider>/modules/module[type='dom-broker-impl'][name='inmemory-dom-broker']</provider>
+ </instance>
+ </service>
+
<service>
- <type xmlns:binding-impl="urn:opendaylight:params:xml:ns:yang:controller:md:sal:binding:impl">
- binding-impl:binding-dom-mapping-service
- </type>
+ <type xmlns:binding="urn:opendaylight:params:xml:ns:yang:controller:md:sal:binding">binding:binding-data-broker</type>
<instance>
- <name>ref_runtime-mapping-singleton</name>
- <provider>
- /config/modules/module[name='runtime-generated-mapping']/instance[name='runtime-mapping-singleton']
- </provider>
+ <name>binding-data-broker</name>
+ <provider>/modules/module[type='binding-data-compatible-broker'][name='inmemory-binding-data-broker']</provider>
</instance>
</service>
+
<service>
- <type xmlns:dom="urn:opendaylight:params:xml:ns:yang:controller:md:sal:dom">
- dom:dom-broker-osgi-registry
- </type>
+ <type xmlns:binding="urn:opendaylight:params:xml:ns:yang:controller:md:sal:binding">binding:binding-async-data-broker</type>
<instance>
- <name>ref_dom-broker</name>
- <provider>/config/modules/module[name='dom-broker-impl']/instance[name='dom-broker']
- </provider>
+ <name>binding-data-broker</name>
+ <provider>/modules/module[type='binding-forwarded-data-broker'][name='binding-async-data-broker']</provider>
</instance>
</service>
+
<service>
- <type xmlns:binding="urn:opendaylight:params:xml:ns:yang:controller:md:sal:binding">
- binding:binding-data-broker
- </type>
+ <type xmlns:dom="urn:opendaylight:params:xml:ns:yang:controller:md:sal:dom">dom:dom-async-data-broker</type>
<instance>
- <name>ref_binding-data-broker</name>
- <provider>
- /config/modules/module[name='binding-data-broker']/instance[name='binding-data-broker']
- </provider>
+ <name>inmemory-data-broker</name>
+ <provider>/modules/module[type='dom-inmemory-data-broker'][name='inmemory-data-broker']</provider>
</instance>
</service>
</services>
new Function<Throwable, SupervisorStrategy.Directive>() {
@Override
public SupervisorStrategy.Directive apply(Throwable t) {
- LOG.warning("Supervisor Strategy of resume applied {}",t);
+ StringBuilder sb = new StringBuilder();
+ for(StackTraceElement element : t.getStackTrace()) {
+ sb.append("\n\tat ")
+ .append(element.toString());
+ }
+ LOG.warning("Supervisor Strategy of resume applied {}",sb.toString());
return SupervisorStrategy.resume();
}
}
public void onFailure(Throwable t) {
LOG.error(t, "An exception happened during abort");
sender
- .tell(new akka.actor.Status.Failure(t), getSelf());
+ .tell(new akka.actor.Status.Failure(t), self);
}
});
}
public void onFailure(Throwable t) {
LOG.error(t, "An exception happened during pre-commit");
sender
- .tell(new akka.actor.Status.Failure(t), getSelf());
+ .tell(new akka.actor.Status.Failure(t), self);
}
});
public void onFailure(Throwable t) {
LOG.error(t, "An exception happened during canCommit");
sender
- .tell(new akka.actor.Status.Failure(t), getSelf());
+ .tell(new akka.actor.Status.Failure(t), self);
}
});
store.onGlobalContextUpdated(testSchemaContext);
}
- private FiniteDuration ASK_RESULT_DURATION = Duration.create(3000, TimeUnit.MILLISECONDS);
+ private FiniteDuration ASK_RESULT_DURATION = Duration.create(5000, TimeUnit.MILLISECONDS);
@Test(expected = TestException.class)
*/
package org.opendaylight.controller.md.sal.dom.store.impl;
+import com.google.common.base.Preconditions;
+
import org.opendaylight.controller.md.sal.common.api.data.AsyncDataChangeEvent;
import org.opendaylight.controller.md.sal.common.api.data.AsyncDataChangeListener;
import org.opendaylight.yangtools.util.concurrent.NotificationManager;
import org.slf4j.LoggerFactory;
class ChangeListenerNotifyTask implements Runnable {
-
private static final Logger LOG = LoggerFactory.getLogger(ChangeListenerNotifyTask.class);
- private final Iterable<? extends DataChangeListenerRegistration<?>> listeners;
- private final AsyncDataChangeEvent<YangInstanceIdentifier, NormalizedNode<?, ?>> event;
-
@SuppressWarnings("rawtypes")
- private final NotificationManager<AsyncDataChangeListener,AsyncDataChangeEvent>
- notificationMgr;
+ private final NotificationManager<AsyncDataChangeListener,AsyncDataChangeEvent> notificationMgr;
+ private final AsyncDataChangeEvent<YangInstanceIdentifier, NormalizedNode<?, ?>> event;
+ private final DataChangeListenerRegistration<?> listener;
@SuppressWarnings("rawtypes")
- public ChangeListenerNotifyTask(final Iterable<? extends DataChangeListenerRegistration<?>> listeners,
+ public ChangeListenerNotifyTask(final DataChangeListenerRegistration<?> listener,
final AsyncDataChangeEvent<YangInstanceIdentifier, NormalizedNode<?, ?>> event,
final NotificationManager<AsyncDataChangeListener,AsyncDataChangeEvent> notificationMgr) {
- this.listeners = listeners;
- this.event = event;
- this.notificationMgr = notificationMgr;
+ this.notificationMgr = Preconditions.checkNotNull(notificationMgr);
+ this.listener = Preconditions.checkNotNull(listener);
+ this.event = Preconditions.checkNotNull(event);
}
@Override
public void run() {
-
- for (DataChangeListenerRegistration<?> listener : listeners) {
- notificationMgr.submitNotification(listener.getInstance(), event);
+ final AsyncDataChangeListener<YangInstanceIdentifier, NormalizedNode<?, ?>> l = listener.getInstance();
+ if (l == null) {
+ LOG.trace("Skipping event delivery to unregistered listener {}", l);
+ return;
}
+ LOG.trace("Listener {} event {}", l, event);
+
+ // FIXME: Yo dawg I heard you like queues, so this was queued to be queued
+ notificationMgr.submitNotification(l, event);
}
@Override
public String toString() {
- return "ChangeListenerNotifyTask [listeners=" + listeners + ", event=" + event + "]";
+ return "ChangeListenerNotifyTask [listener=" + listener + ", event=" + event + "]";
}
}
*/
package org.opendaylight.controller.md.sal.dom.store.impl;
+import com.google.common.base.Preconditions;
+
import java.util.Collections;
import java.util.HashMap;
import java.util.HashSet;
import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier.PathArgument;
import org.opendaylight.yangtools.yang.data.api.schema.NormalizedNode;
-import com.google.common.base.Preconditions;
-
public final class DOMImmutableDataChangeEvent implements
AsyncDataChangeEvent<YangInstanceIdentifier, NormalizedNode<?, ?>> {
updated.put(path, after);
return this;
}
+
+ public boolean isEmpty() {
+ return created.isEmpty() && removed.isEmpty() && updated.isEmpty();
+ }
}
private static final class RemoveEventFactory implements SimpleEventFactory {
import javax.annotation.concurrent.GuardedBy;
-import java.util.Collections;
import java.util.concurrent.Callable;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.TimeUnit;
.addCreated(path, data) //
.build();
- new ChangeListenerNotifyTask(Collections.singletonList(reg), event,
+ new ChangeListenerNotifyTask(reg, event,
dataChangeListenerNotificationManager).run();
}
}
*/
package org.opendaylight.controller.md.sal.dom.store.impl;
-import static org.opendaylight.controller.md.sal.dom.store.impl.DOMImmutableDataChangeEvent.builder;
-
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;
+import com.google.common.collect.ArrayListMultimap;
import com.google.common.collect.Multimap;
+import java.util.ArrayList;
import java.util.Collection;
-import java.util.Collections;
-import java.util.LinkedList;
-import java.util.List;
import java.util.Map.Entry;
-import java.util.Set;
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.AsyncDataChangeEvent;
import org.opendaylight.controller.md.sal.common.api.data.AsyncDataChangeListener;
-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.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.yangtools.util.concurrent.NotificationManager;
-import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier;
-import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier.NodeIdentifier;
-import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier.NodeIdentifierWithPredicates;
-import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier.NodeWithValue;
import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier.PathArgument;
import org.opendaylight.yangtools.yang.data.api.schema.NormalizedNode;
import org.opendaylight.yangtools.yang.data.api.schema.NormalizedNodeContainer;
*/
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 final Multimap<ListenerTree.Node, DOMImmutableDataChangeEvent> events = HashMultimap.create();
+ @SuppressWarnings("rawtypes")
+ private final NotificationManager<AsyncDataChangeListener, AsyncDataChangeEvent> notificationMgr;
private final DataTreeCandidate candidate;
private final ListenerTree listenerRoot;
- @SuppressWarnings("rawtypes")
- private final NotificationManager<AsyncDataChangeListener, AsyncDataChangeEvent> notificationMgr;
+ private Multimap<DataChangeListenerRegistration<?>, DOMImmutableDataChangeEvent> collectedEvents;
@SuppressWarnings("rawtypes")
public ResolveDataChangeEventsTask(final DataTreeCandidate candidate, final ListenerTree listenerTree,
* order to delivery data change events.
*/
@Override
- public Iterable<ChangeListenerNotifyTask> call() {
+ public synchronized Iterable<ChangeListenerNotifyTask> call() {
try (final Walker w = listenerRoot.getWalker()) {
- resolveAnyChangeEvent(candidate.getRootPath(), Collections.singleton(w.getRootNode()), candidate.getRootNode());
- return createNotificationTasks();
- }
- }
-
- /**
- *
- * Walks map of listeners to data change events, creates notification
- * delivery tasks.
- *
- * Walks map of registered and affected listeners and creates notification
- * tasks from set of listeners and events to be delivered.
- *
- * If set of listeners has more then one event (applicable to wildcarded
- * listeners), merges all data change events into one, final which contains
- * all separate updates.
- *
- * Dispatch between merge variant and reuse variant of notification task is
- * done in
- * {@link #addNotificationTask(com.google.common.collect.ImmutableList.Builder, Node, java.util.Collection)}
- *
- * @return Collection of notification tasks.
- */
- private Collection<ChangeListenerNotifyTask> createNotificationTasks() {
- ImmutableList.Builder<ChangeListenerNotifyTask> taskListBuilder = ImmutableList.builder();
- for (Entry<ListenerTree.Node, Collection<DOMImmutableDataChangeEvent>> entry : events.asMap().entrySet()) {
- addNotificationTask(taskListBuilder, entry.getKey(), entry.getValue());
- }
- return taskListBuilder.build();
- }
-
- /**
- * Adds notification task to task list.
- *
- * If entry collection contains one event, this event is reused and added to
- * notification tasks for listeners (see
- * {@link #addNotificationTaskByScope(com.google.common.collect.ImmutableList.Builder, Node, DOMImmutableDataChangeEvent)}
- * . Otherwise events are merged by scope and distributed between listeners
- * to particular scope. See
- * {@link #addNotificationTasksAndMergeEvents(com.google.common.collect.ImmutableList.Builder, Node, java.util.Collection)}
- * .
- *
- * @param taskListBuilder
- * @param listeners
- * @param entries
- */
- private void addNotificationTask(final ImmutableList.Builder<ChangeListenerNotifyTask> taskListBuilder,
- final ListenerTree.Node listeners, final Collection<DOMImmutableDataChangeEvent> entries) {
-
- if (!entries.isEmpty()) {
- if (entries.size() == 1) {
- addNotificationTaskByScope(taskListBuilder, listeners, Iterables.getOnlyElement(entries));
- } else {
- addNotificationTasksAndMergeEvents(taskListBuilder, listeners, entries);
- }
- }
- }
+ // Defensive: reset internal state
+ collectedEvents = ArrayListMultimap.create();
- /**
- *
- * Add notification deliveries task to the listener.
- *
- *
- * @param taskListBuilder
- * @param listeners
- * @param event
- */
- private void addNotificationTaskByScope(
- final ImmutableList.Builder<ChangeListenerNotifyTask> taskListBuilder, final ListenerTree.Node listeners,
- final DOMImmutableDataChangeEvent event) {
- DataChangeScope eventScope = event.getScope();
- for (DataChangeListenerRegistration<?> listenerReg : listeners.getListeners()) {
- DataChangeScope listenerScope = listenerReg.getScope();
- List<DataChangeListenerRegistration<?>> listenerSet = Collections
- .<DataChangeListenerRegistration<?>> singletonList(listenerReg);
- if (eventScope == DataChangeScope.BASE) {
- taskListBuilder.add(new ChangeListenerNotifyTask(listenerSet, event, notificationMgr));
- } else if (eventScope == DataChangeScope.ONE && listenerScope != DataChangeScope.BASE) {
- taskListBuilder.add(new ChangeListenerNotifyTask(listenerSet, event, notificationMgr));
- } else if (eventScope == DataChangeScope.SUBTREE && listenerScope == DataChangeScope.SUBTREE) {
- taskListBuilder.add(new ChangeListenerNotifyTask(listenerSet, event, notificationMgr));
- }
- }
- }
+ // Run through the tree
+ final ResolveDataChangeState s = ResolveDataChangeState.initial(candidate.getRootPath(), w.getRootNode());
+ resolveAnyChangeEvent(s, candidate.getRootNode());
- /**
- *
- * Add notification tasks with merged event
- *
- * Separate Events by scope and creates merged notification tasks for each
- * and every scope which is present.
- *
- * Adds merged events to task list based on scope requested by client.
- *
- * @param taskListBuilder
- * @param listeners
- * @param entries
- */
- private void addNotificationTasksAndMergeEvents(
- final ImmutableList.Builder<ChangeListenerNotifyTask> taskListBuilder, final ListenerTree.Node listeners,
- final Collection<DOMImmutableDataChangeEvent> entries) {
-
- final Builder baseBuilder = builder(DataChangeScope.BASE);
- final Builder oneBuilder = builder(DataChangeScope.ONE);
- final Builder subtreeBuilder = builder(DataChangeScope.SUBTREE);
-
- boolean baseModified = false;
- boolean oneModified = false;
- boolean subtreeModified = false;
- for (final DOMImmutableDataChangeEvent entry : entries) {
- switch (entry.getScope()) {
- // Absence of breaks is intentional here. Subtree contains base and
- // one, one also contains base
- case BASE:
- baseBuilder.merge(entry);
- baseModified = true;
- case ONE:
- oneBuilder.merge(entry);
- oneModified = true;
- case SUBTREE:
- subtreeBuilder.merge(entry);
- subtreeModified = true;
+ /*
+ * Convert to tasks, but be mindful of multiple values -- those indicate multiple
+ * wildcard matches, which need to be merged.
+ */
+ final Collection<ChangeListenerNotifyTask> ret = new ArrayList<>();
+ for (Entry<DataChangeListenerRegistration<?>, Collection<DOMImmutableDataChangeEvent>> e : collectedEvents.asMap().entrySet()) {
+ final Collection<DOMImmutableDataChangeEvent> col = e.getValue();
+ final DOMImmutableDataChangeEvent event;
+
+ if (col.size() != 1) {
+ final Builder b = DOMImmutableDataChangeEvent.builder(DataChangeScope.BASE);
+ for (DOMImmutableDataChangeEvent i : col) {
+ b.merge(i);
+ }
+
+ event = b.build();
+ LOG.trace("Merged events {} into event {}", col, event);
+ } else {
+ event = col.iterator().next();
+ }
+
+ ret.add(new ChangeListenerNotifyTask(e.getKey(), event, notificationMgr));
}
- }
- if (baseModified) {
- addNotificationTaskExclusively(taskListBuilder, listeners, baseBuilder.build());
- }
- if (oneModified) {
- addNotificationTaskExclusively(taskListBuilder, listeners, oneBuilder.build());
- }
- if (subtreeModified) {
- addNotificationTaskExclusively(taskListBuilder, listeners, subtreeBuilder.build());
- }
- }
-
- private void addNotificationTaskExclusively(
- final ImmutableList.Builder<ChangeListenerNotifyTask> taskListBuilder, final Node listeners,
- final DOMImmutableDataChangeEvent event) {
- for (DataChangeListenerRegistration<?> listener : listeners.getListeners()) {
- if (listener.getScope() == event.getScope()) {
- Set<DataChangeListenerRegistration<?>> listenerSet = Collections
- .<DataChangeListenerRegistration<?>> singleton(listener);
- taskListBuilder.add(new ChangeListenerNotifyTask(listenerSet, event, notificationMgr));
- }
+ // FIXME: so now we have tasks to submit tasks... Inception-style!
+ LOG.debug("Created tasks {}", ret);
+ return ret;
}
}
* - Original (before) state of current node
* @param after
* - After state of current node
- * @return Data Change Event of this node and all it's children
+ * @return True if the subtree changed, false otherwise
*/
- private DOMImmutableDataChangeEvent resolveAnyChangeEvent(final YangInstanceIdentifier path,
- final Collection<ListenerTree.Node> listeners, final DataTreeCandidateNode node) {
-
+ private boolean resolveAnyChangeEvent(final ResolveDataChangeState state, 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;
+ state.getPath(), node.getModificationType());
+ return false;
}
// no before and after state is present
switch (node.getModificationType()) {
case SUBTREE_MODIFIED:
- return resolveSubtreeChangeEvent(path, listeners, node);
+ return resolveSubtreeChangeEvent(state, node);
case MERGE:
case WRITE:
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, node.getDataAfter().get());
+ "Modification at {} has type {} but no after-data", state.getPath(), node.getModificationType());
+ if (!node.getDataBefore().isPresent()) {
+ resolveCreateEvent(state, node.getDataAfter().get());
+ return true;
}
+
+ return resolveReplacedEvent(state, node.getDataBefore().get(), node.getDataAfter().get());
case DELETE:
Preconditions.checkArgument(node.getDataBefore().isPresent(),
- "Modification at {} has type {} but no before-data", path, node.getModificationType());
- return resolveDeleteEvent(path, listeners, node.getDataBefore().get());
+ "Modification at {} has type {} but no before-data", state.getPath(), node.getModificationType());
+ resolveDeleteEvent(state, node.getDataBefore().get());
+ return true;
case UNMODIFIED:
- return NO_CHANGE;
+ return false;
}
- throw new IllegalStateException(String.format("Unhandled node state %s at %s", node.getModificationType(), path));
+ throw new IllegalStateException(String.format("Unhandled node state %s at %s", node.getModificationType(), state.getPath()));
}
- private DOMImmutableDataChangeEvent resolveReplacedEvent(final YangInstanceIdentifier path,
- final Collection<Node> listeners, final NormalizedNode<?, ?> beforeData,
- final NormalizedNode<?, ?> afterData) {
-
- // FIXME: BUG-1493: check the listeners to prune unneeded changes:
- // for subtrees, we have to do all
- // for one, we need to expand children
- // for base, we just report replacement
+ private boolean resolveReplacedEvent(final ResolveDataChangeState state,
+ final NormalizedNode<?, ?> beforeData, final NormalizedNode<?, ?> afterData) {
if (beforeData instanceof NormalizedNodeContainer<?, ?, ?>) {
- // Node is container (contains child) and we have interested
- // listeners registered for it, that means we need to do
- // resolution of changes on children level and can not
- // shortcut resolution.
- LOG.trace("Resolving subtree replace event for {} before {}, after {}",path,beforeData,afterData);
+ /*
+ * Node is a container (contains a child) and we have interested
+ * listeners registered for it, that means we need to do
+ * resolution of changes on children level and can not
+ * shortcut resolution.
+ */
+ LOG.trace("Resolving subtree replace event for {} before {}, after {}", state.getPath(), beforeData, afterData);
@SuppressWarnings("unchecked")
NormalizedNodeContainer<?, PathArgument, NormalizedNode<PathArgument, ?>> beforeCont = (NormalizedNodeContainer<?, PathArgument, NormalizedNode<PathArgument, ?>>) beforeData;
@SuppressWarnings("unchecked")
NormalizedNodeContainer<?, PathArgument, NormalizedNode<PathArgument, ?>> afterCont = (NormalizedNodeContainer<?, PathArgument, NormalizedNode<PathArgument, ?>>) afterData;
- return resolveNodeContainerReplaced(path, listeners, beforeCont, afterCont);
- } else if (!beforeData.equals(afterData)) {
- // Node is Leaf type (does not contain child nodes)
- // so normal equals method is sufficient for determining change.
- LOG.trace("Resolving leaf replace event for {} , before {}, after {}",path,beforeData,afterData);
- DOMImmutableDataChangeEvent event = builder(DataChangeScope.BASE).setBefore(beforeData).setAfter(afterData)
- .addUpdated(path, beforeData, afterData).build();
- addPartialTask(listeners, event);
- return event;
- } else {
- return NO_CHANGE;
+ return resolveNodeContainerReplaced(state, beforeCont, afterCont);
}
+
+ // Node is a Leaf type (does not contain child nodes)
+ // so normal equals method is sufficient for determining change.
+ if (beforeData.equals(afterData)) {
+ LOG.trace("Skipping equal leaf {}", state.getPath());
+ return false;
+ }
+
+ LOG.trace("Resolving leaf replace event for {} , before {}, after {}", state.getPath(), beforeData, afterData);
+ DOMImmutableDataChangeEvent event = DOMImmutableDataChangeEvent.builder(DataChangeScope.BASE).addUpdated(state.getPath(), beforeData, afterData).build();
+ state.addEvent(event);
+ state.collectEvents(beforeData, afterData, collectedEvents);
+ return true;
}
- private DOMImmutableDataChangeEvent resolveNodeContainerReplaced(final YangInstanceIdentifier path,
- final Collection<Node> listeners,
+ private boolean resolveNodeContainerReplaced(final ResolveDataChangeState state,
final NormalizedNodeContainer<?, PathArgument, NormalizedNode<PathArgument, ?>> beforeCont,
final NormalizedNodeContainer<?, PathArgument, NormalizedNode<PathArgument, ?>> afterCont) {
- final List<DOMImmutableDataChangeEvent> childChanges = new LinkedList<>();
+ if (!state.needsProcessing()) {
+ LOG.trace("Not processing replaced container {}", state.getPath());
+ return true;
+ }
// We look at all children from before and compare it with after state.
+ boolean childChanged = false;
for (NormalizedNode<PathArgument, ?> beforeChild : beforeCont.getValue()) {
final PathArgument childId = beforeChild.getIdentifier();
- YangInstanceIdentifier childPath = path.node(childId);
- Collection<ListenerTree.Node> childListeners = getListenerChildrenWildcarded(listeners, childId);
- Optional<NormalizedNode<PathArgument, ?>> afterChild = afterCont.getChild(childId);
- DOMImmutableDataChangeEvent childChange = resolveNodeContainerChildUpdated(childPath, childListeners,
- beforeChild, afterChild);
- // If change is empty (equals to NO_CHANGE)
- if (childChange != NO_CHANGE) {
- childChanges.add(childChange);
+ if (resolveNodeContainerChildUpdated(state.child(childId), beforeChild, afterCont.getChild(childId))) {
+ childChanged = true;
}
}
* created.
*/
if (!beforeCont.getChild(childId).isPresent()) {
- Collection<ListenerTree.Node> childListeners = getListenerChildrenWildcarded(listeners, childId);
- YangInstanceIdentifier childPath = path.node(childId);
- childChanges.add(resolveSameEventRecursivelly(childPath , childListeners, afterChild,
- DOMImmutableDataChangeEvent.getCreateEventFactory()));
+ resolveSameEventRecursivelly(state.child(childId), afterChild, DOMImmutableDataChangeEvent.getCreateEventFactory());
+ childChanged = true;
}
}
- if (childChanges.isEmpty()) {
- return NO_CHANGE;
- }
- Builder eventBuilder = builder(DataChangeScope.BASE) //
- .setBefore(beforeCont) //
- .setAfter(afterCont)
- .addUpdated(path, beforeCont, afterCont);
- for (DOMImmutableDataChangeEvent childChange : childChanges) {
- eventBuilder.merge(childChange);
+ if (childChanged) {
+ DOMImmutableDataChangeEvent event = DOMImmutableDataChangeEvent.builder(DataChangeScope.BASE)
+ .addUpdated(state.getPath(), beforeCont, afterCont).build();
+ state.addEvent(event);
}
- DOMImmutableDataChangeEvent replaceEvent = eventBuilder.build();
- addPartialTask(listeners, replaceEvent);
- return replaceEvent;
+ state.collectEvents(beforeCont, afterCont, collectedEvents);
+ return childChanged;
}
- private DOMImmutableDataChangeEvent resolveNodeContainerChildUpdated(final YangInstanceIdentifier path,
- final Collection<Node> listeners, final NormalizedNode<PathArgument, ?> before,
- final Optional<NormalizedNode<PathArgument, ?>> after) {
-
+ private boolean resolveNodeContainerChildUpdated(final ResolveDataChangeState state,
+ final NormalizedNode<PathArgument, ?> before, final Optional<NormalizedNode<PathArgument, ?>> after) {
if (after.isPresent()) {
// REPLACE or SUBTREE Modified
- return resolveReplacedEvent(path, listeners, before, after.get());
-
- } else {
- // AFTER state is not present - child was deleted.
- return resolveSameEventRecursivelly(path, listeners, before,
- DOMImmutableDataChangeEvent.getRemoveEventFactory());
+ return resolveReplacedEvent(state, before, after.get());
}
+
+ // AFTER state is not present - child was deleted.
+ resolveSameEventRecursivelly(state, before, DOMImmutableDataChangeEvent.getRemoveEventFactory());
+ return true;
}
/**
* Resolves create events deep down the interest listener tree.
*
- *
* @param path
* @param listeners
* @param afterState
* @return
*/
- private DOMImmutableDataChangeEvent resolveCreateEvent(final YangInstanceIdentifier path,
- final Collection<ListenerTree.Node> listeners, final NormalizedNode<?, ?> afterState) {
+ private void resolveCreateEvent(final ResolveDataChangeState state, final NormalizedNode<?, ?> afterState) {
@SuppressWarnings({ "unchecked", "rawtypes" })
final NormalizedNode<PathArgument, ?> node = (NormalizedNode) afterState;
- return resolveSameEventRecursivelly(path, listeners, node, DOMImmutableDataChangeEvent.getCreateEventFactory());
+ resolveSameEventRecursivelly(state, node, DOMImmutableDataChangeEvent.getCreateEventFactory());
}
- private DOMImmutableDataChangeEvent resolveDeleteEvent(final YangInstanceIdentifier path,
- final Collection<ListenerTree.Node> listeners, final NormalizedNode<?, ?> beforeState) {
-
+ private void resolveDeleteEvent(final ResolveDataChangeState state, final NormalizedNode<?, ?> beforeState) {
@SuppressWarnings({ "unchecked", "rawtypes" })
final NormalizedNode<PathArgument, ?> node = (NormalizedNode) beforeState;
- return resolveSameEventRecursivelly(path, listeners, node, DOMImmutableDataChangeEvent.getRemoveEventFactory());
+ resolveSameEventRecursivelly(state, node, DOMImmutableDataChangeEvent.getRemoveEventFactory());
}
- private DOMImmutableDataChangeEvent resolveSameEventRecursivelly(final YangInstanceIdentifier path,
- final Collection<Node> listeners, final NormalizedNode<PathArgument, ?> node,
- final SimpleEventFactory eventFactory) {
- final DOMImmutableDataChangeEvent event = eventFactory.create(path, node);
- DOMImmutableDataChangeEvent propagateEvent = event;
+ private void resolveSameEventRecursivelly(final ResolveDataChangeState state,
+ final NormalizedNode<PathArgument, ?> node, final SimpleEventFactory eventFactory) {
+ if (!state.needsProcessing()) {
+ LOG.trace("Skipping child {}", state.getPath());
+ return;
+ }
+
// We have listeners for this node or it's children, so we will try
// to do additional processing
if (node instanceof NormalizedNodeContainer<?, ?, ?>) {
- LOG.trace("Resolving subtree recursive event for {}, type {}", path, eventFactory);
-
- Builder eventBuilder = builder(DataChangeScope.BASE);
- eventBuilder.merge(event);
- eventBuilder.setBefore(event.getOriginalSubtree());
- eventBuilder.setAfter(event.getUpdatedSubtree());
+ LOG.trace("Resolving subtree recursive event for {}, type {}", state.getPath(), eventFactory);
// Node has children, so we will try to resolve it's children
// changes.
@SuppressWarnings("unchecked")
NormalizedNodeContainer<?, PathArgument, NormalizedNode<PathArgument, ?>> container = (NormalizedNodeContainer<?, PathArgument, NormalizedNode<PathArgument, ?>>) node;
for (NormalizedNode<PathArgument, ?> child : container.getValue()) {
- PathArgument childId = child.getIdentifier();
+ final PathArgument childId = child.getIdentifier();
+
LOG.trace("Resolving event for child {}", childId);
- Collection<Node> childListeners = getListenerChildrenWildcarded(listeners, childId);
- eventBuilder.merge(resolveSameEventRecursivelly(path.node(childId), childListeners, child, eventFactory));
+ resolveSameEventRecursivelly(state.child(childId), child, eventFactory);
}
- propagateEvent = eventBuilder.build();
}
- if (!listeners.isEmpty()) {
- addPartialTask(listeners, propagateEvent);
- }
- return propagateEvent;
- }
- private DOMImmutableDataChangeEvent resolveSubtreeChangeEvent(final YangInstanceIdentifier path,
- final Collection<ListenerTree.Node> listeners, final DataTreeCandidateNode modification) {
+ final DOMImmutableDataChangeEvent event = eventFactory.create(state.getPath(), node);
+ LOG.trace("Adding event {} at path {}", event, state.getPath());
+ state.addEvent(event);
+ state.collectEvents(event.getOriginalSubtree(), event.getUpdatedSubtree(), collectedEvents);
+ }
- 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);
+ private boolean resolveSubtreeChangeEvent(final ResolveDataChangeState state, final DataTreeCandidateNode modification) {
+ Preconditions.checkArgument(modification.getDataBefore().isPresent(), "Subtree change with before-data not present at path %s", state.getPath());
+ Preconditions.checkArgument(modification.getDataAfter().isPresent(), "Subtree change with after-data not present at path %s", state.getPath());
- 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());
- boolean oneModified = false;
+ DataChangeScope scope = null;
for (DataTreeCandidateNode childMod : modification.getChildNodes()) {
- PathArgument childId = childMod.getIdentifier();
- YangInstanceIdentifier childPath = path.node(childId);
- Collection<ListenerTree.Node> childListeners = getListenerChildrenWildcarded(listeners, childId);
-
+ final ResolveDataChangeState childState = state.child(childMod.getIdentifier());
switch (childMod.getModificationType()) {
case WRITE:
case MERGE:
case DELETE:
- one.merge(resolveAnyChangeEvent(childPath, childListeners, childMod));
- oneModified = true;
+ if (resolveAnyChangeEvent(childState, childMod)) {
+ scope = DataChangeScope.ONE;
+ }
break;
case SUBTREE_MODIFIED:
- subtree.merge(resolveSubtreeChangeEvent(childPath, childListeners, childMod));
+ if (resolveSubtreeChangeEvent(childState, childMod) && scope == null) {
+ scope = DataChangeScope.SUBTREE;
+ }
break;
case UNMODIFIED:
// no-op
break;
}
}
- final DOMImmutableDataChangeEvent oneChangeEvent;
- if(oneModified) {
- one.addUpdated(path, modification.getDataBefore().get(), modification.getDataAfter().get());
- oneChangeEvent = one.build();
- subtree.merge(oneChangeEvent);
- } else {
- oneChangeEvent = null;
- subtree.addUpdated(path, modification.getDataBefore().get(), modification.getDataAfter().get());
- }
- DOMImmutableDataChangeEvent subtreeEvent = subtree.build();
- if (!listeners.isEmpty()) {
- if(oneChangeEvent != null) {
- addPartialTask(listeners, oneChangeEvent);
- }
- addPartialTask(listeners, subtreeEvent);
- }
- return subtreeEvent;
- }
- private DOMImmutableDataChangeEvent addPartialTask(final Collection<ListenerTree.Node> listeners,
- final DOMImmutableDataChangeEvent event) {
- for (ListenerTree.Node listenerNode : listeners) {
- if (!listenerNode.getListeners().isEmpty()) {
- LOG.trace("Adding event {} for listeners {}",event,listenerNode);
- events.put(listenerNode, event);
- }
- }
- return event;
- }
+ final NormalizedNode<?, ?> before = modification.getDataBefore().get();
+ final NormalizedNode<?, ?> after = modification.getDataAfter().get();
- private static Collection<ListenerTree.Node> getListenerChildrenWildcarded(final Collection<ListenerTree.Node> parentNodes,
- final PathArgument child) {
- if (parentNodes.isEmpty()) {
- return Collections.emptyList();
- }
- com.google.common.collect.ImmutableList.Builder<ListenerTree.Node> result = ImmutableList.builder();
- if (child instanceof NodeWithValue || child instanceof NodeIdentifierWithPredicates) {
- NodeIdentifier wildcardedIdentifier = new NodeIdentifier(child.getNodeType());
- addChildrenNodesToBuilder(result, parentNodes, wildcardedIdentifier);
+ if (scope != null) {
+ DOMImmutableDataChangeEvent one = DOMImmutableDataChangeEvent.builder(scope).addUpdated(state.getPath(), before, after).build();
+ state.addEvent(one);
}
- addChildrenNodesToBuilder(result, parentNodes, child);
- return result.build();
- }
- private static void addChildrenNodesToBuilder(final ImmutableList.Builder<ListenerTree.Node> result,
- final Collection<ListenerTree.Node> parentNodes, final PathArgument childIdentifier) {
- for (ListenerTree.Node node : parentNodes) {
- Optional<ListenerTree.Node> child = node.getChild(childIdentifier);
- if (child.isPresent()) {
- result.add(child.get());
- }
- }
+ state.collectEvents(before, after, collectedEvents);
+ return scope != null;
}
@SuppressWarnings("rawtypes")
--- /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 com.google.common.base.Optional;
+import com.google.common.base.Preconditions;
+import com.google.common.collect.Iterables;
+import com.google.common.collect.Multimap;
+
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.Map.Entry;
+
+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.tree.ListenerTree.Node;
+import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier;
+import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier.NodeIdentifier;
+import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier.NodeIdentifierWithPredicates;
+import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier.NodeWithValue;
+import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier.PathArgument;
+import org.opendaylight.yangtools.yang.data.api.schema.NormalizedNode;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ * Recursion state used in {@link ResolveDataChangeEventsTask}. Instances of this
+ * method track which listeners are affected by a particular change node. It takes
+ * care of properly inheriting SUB/ONE listeners and also provides a means to
+ * understand when actual processing need not occur.
+ */
+final class ResolveDataChangeState {
+ private static final Logger LOG = LoggerFactory.getLogger(ResolveDataChangeState.class);
+ /**
+ * Inherited from all parents
+ */
+ private final Iterable<Builder> inheritedSub;
+ /**
+ * Inherited from immediate parent
+ */
+ private final Iterable<Builder> inheritedOne;
+ private final YangInstanceIdentifier nodeId;
+ private final Collection<Node> nodes;
+
+ private final Map<DataChangeListenerRegistration<?>, Builder> subBuilders = new HashMap<>();
+ private final Map<DataChangeListenerRegistration<?>, Builder> oneBuilders = new HashMap<>();
+ private final Map<DataChangeListenerRegistration<?>, Builder> baseBuilders = new HashMap<>();
+
+ private ResolveDataChangeState(final YangInstanceIdentifier nodeId,
+ final Iterable<Builder> inheritedSub, final Iterable<Builder> inheritedOne,
+ final Collection<Node> nodes) {
+ this.nodeId = Preconditions.checkNotNull(nodeId);
+ this.nodes = Preconditions.checkNotNull(nodes);
+ this.inheritedSub = Preconditions.checkNotNull(inheritedSub);
+ this.inheritedOne = Preconditions.checkNotNull(inheritedOne);
+
+ /*
+ * Collect the nodes which need to be propagated from us to the child.
+ */
+ for (Node n : nodes) {
+ for (DataChangeListenerRegistration<?> l : n.getListeners()) {
+ final Builder b = DOMImmutableDataChangeEvent.builder(DataChangeScope.BASE);
+ switch (l.getScope()) {
+ case BASE:
+ baseBuilders.put(l, b);
+ break;
+ case ONE:
+ oneBuilders.put(l, b);
+ break;
+ case SUBTREE:
+ subBuilders.put(l, b);
+ break;
+ }
+ }
+ }
+ }
+
+ /**
+ * Create an initial state handle at a particular root node.
+ *
+ * @param rootId root instance identifier
+ * @param root root node
+ * @return
+ */
+ public static ResolveDataChangeState initial(final YangInstanceIdentifier rootId, final Node root) {
+ return new ResolveDataChangeState(rootId, Collections.<Builder>emptyList(),
+ Collections.<Builder>emptyList(), Collections.singletonList(root));
+ }
+
+ /**
+ * Create a state handle for iterating over a particular child.
+ *
+ * @param childId ID of the child
+ * @return State handle
+ */
+ public ResolveDataChangeState child(final PathArgument childId) {
+ return new ResolveDataChangeState(nodeId.node(childId),
+ Iterables.concat(inheritedSub, subBuilders.values()),
+ oneBuilders.values(), getListenerChildrenWildcarded(nodes, childId));
+ }
+
+ /**
+ * Get the current path
+ *
+ * @return Current path.
+ */
+ public YangInstanceIdentifier getPath() {
+ return nodeId;
+ }
+
+ /**
+ * Check if this child needs processing.
+ *
+ * @return True if processing needs to occur, false otherwise.
+ */
+ public boolean needsProcessing() {
+ // May have underlying listeners, so we need to process
+ if (!nodes.isEmpty()) {
+ return true;
+ }
+ // Have SUBTREE listeners
+ if (!Iterables.isEmpty(inheritedSub)) {
+ return true;
+ }
+ // Have ONE listeners
+ if (!Iterables.isEmpty(inheritedOne)) {
+ return true;
+ }
+
+ // FIXME: do we need anything else? If not, flip this to 'false'
+ return true;
+ }
+
+ /**
+ * Add an event to all current listeners.
+ *
+ * @param event
+ */
+ public void addEvent(final DOMImmutableDataChangeEvent event) {
+ // Subtree builders get always notified
+ for (Builder b : subBuilders.values()) {
+ b.merge(event);
+ }
+ for (Builder b : inheritedSub) {
+ b.merge(event);
+ }
+
+ if (event.getScope() == DataChangeScope.ONE || event.getScope() == DataChangeScope.BASE) {
+ for (Builder b : oneBuilders.values()) {
+ b.merge(event);
+ }
+ }
+
+ if (event.getScope() == DataChangeScope.BASE) {
+ for (Builder b : inheritedOne) {
+ b.merge(event);
+ }
+ for (Builder b : baseBuilders.values()) {
+ b.merge(event);
+ }
+ }
+ }
+
+ /**
+ * Gather all non-empty events into the provided map.
+ *
+ * @param before before-image
+ * @param after after-image
+ * @param map target map
+ */
+ public void collectEvents(final NormalizedNode<?, ?> before, final NormalizedNode<?, ?> after,
+ final Multimap<DataChangeListenerRegistration<?>, DOMImmutableDataChangeEvent> map) {
+ for (Entry<DataChangeListenerRegistration<?>, Builder> e : baseBuilders.entrySet()) {
+ final Builder b = e.getValue();
+ if (!b.isEmpty()) {
+ map.put(e.getKey(), b.setBefore(before).setAfter(after).build());
+ }
+ }
+ for (Entry<DataChangeListenerRegistration<?>, Builder> e : oneBuilders.entrySet()) {
+ final Builder b = e.getValue();
+ if (!b.isEmpty()) {
+ map.put(e.getKey(), b.setBefore(before).setAfter(after).build());
+ }
+ }
+ for (Entry<DataChangeListenerRegistration<?>, Builder> e : subBuilders.entrySet()) {
+ final Builder b = e.getValue();
+ if (!b.isEmpty()) {
+ map.put(e.getKey(), b.setBefore(before).setAfter(after).build());
+ }
+ }
+
+ LOG.trace("Collected events {}", map);
+ }
+
+ private static Collection<Node> getListenerChildrenWildcarded(final Collection<Node> parentNodes,
+ final PathArgument child) {
+ if (parentNodes.isEmpty()) {
+ return Collections.emptyList();
+ }
+
+ final List<Node> result = new ArrayList<>();
+ if (child instanceof NodeWithValue || child instanceof NodeIdentifierWithPredicates) {
+ NodeIdentifier wildcardedIdentifier = new NodeIdentifier(child.getNodeType());
+ addChildNodes(result, parentNodes, wildcardedIdentifier);
+ }
+ addChildNodes(result, parentNodes, child);
+ return result;
+ }
+
+ private static void addChildNodes(final List<Node> result, final Collection<Node> parentNodes, final PathArgument childIdentifier) {
+ for (Node node : parentNodes) {
+ Optional<Node> child = node.getChild(childIdentifier);
+ if (child.isPresent()) {
+ result.add(child.get());
+ }
+ }
+ }
+}
*/
package org.opendaylight.controller.md.sal.dom.store.impl;
+import com.google.common.util.concurrent.MoreExecutors;
+
import java.util.Collection;
import java.util.Map;
+
import org.junit.After;
import org.junit.Assert;
import org.junit.Before;
import org.opendaylight.yangtools.yang.data.impl.schema.builder.api.DataContainerNodeBuilder;
import org.opendaylight.yangtools.yang.model.api.SchemaContext;
-import com.google.common.util.concurrent.MoreExecutors;
-
public abstract class AbstractDataChangeListenerTest {
protected static final YangInstanceIdentifier TOP_LEVEL = YangInstanceIdentifier
}
}
+ /**
+ * Create a new test task. The task will operate on the backed database,
+ * and will use the proper background executor service.
+ *
+ * @return Test task initialized to clean up {@value #TOP_LEVEL} and its
+ * children.
+ */
public final DatastoreTestTask newTestTask() {
return new DatastoreTestTask(datastore, dclExecutorService).cleanup(DatastoreTestTask
.simpleDelete(TOP_LEVEL));
import org.opendaylight.controller.md.sal.dom.store.impl.DatastoreTestTask.WriteTransactionCustomizer;
import org.opendaylight.controller.sal.core.spi.data.DOMStoreReadWriteTransaction;
+/**
+ * Base template for a test suite for testing DataChangeListener functionality.
+ */
public abstract class DefaultDataChangeListenerTestSuite extends AbstractDataChangeListenerTest {
protected static final String FOO_SIBLING = "foo-sibling";
+ /**
+ * Callback invoked when the test suite can modify task parameters.
+ *
+ * @param task Update task configuration as needed
+ */
abstract protected void customizeTask(DatastoreTestTask task);
@Test
assertNotNull(change);
- assertNotContains(change.getCreatedData(), TOP_LEVEL);
- assertContains(change.getCreatedData(), path(FOO), path(FOO, BAR));
+ /*
+ * Created data must not contain nested-list item, since that is two-level deep.
+ */
+ assertNotContains(change.getCreatedData(), TOP_LEVEL,path(FOO, BAR));
+ assertContains(change.getCreatedData(), path(FOO) );
assertEmpty(change.getUpdatedData());
assertEmpty(change.getRemovedPaths());
AsyncDataChangeEvent<YangInstanceIdentifier, NormalizedNode<?, ?>> change = task.getChangeEvent();
assertNotNull(change);
-
- assertContains(change.getCreatedData(), path(FOO, BAZ));
+ /*
+ * Created data must NOT contain nested-list item since scope is base, and change is two
+ * level deep.
+ */
+ assertNotContains(change.getCreatedData(), path(FOO, BAZ));
assertContains(change.getUpdatedData(), path(FOO));
assertNotContains(change.getUpdatedData(), TOP_LEVEL);
- assertContains(change.getRemovedPaths(), path(FOO, BAR));
+ /*
+ * Removed data must NOT contain nested-list item since scope is base, and change is two
+ * level deep.
+ */
+ assertNotContains(change.getRemovedPaths(), path(FOO, BAR));
}
assertNotNull(change);
assertFalse(change.getCreatedData().isEmpty());
- assertContains(change.getCreatedData(), path(FOO), path(FOO, BAR), path(FOO, BAZ));
- assertNotContains(change.getCreatedData(), TOP_LEVEL);
+ // Base event should contain only changed item, no details about child.
+ assertContains(change.getCreatedData(), path(FOO));
+ assertNotContains(change.getCreatedData(), TOP_LEVEL,path(FOO, BAR), path(FOO, BAZ));
assertEmpty(change.getUpdatedData());
assertEmpty(change.getRemovedPaths());
assertEmpty(change.getUpdatedData());
assertNotContains(change.getUpdatedData(), TOP_LEVEL);
- assertContains(change.getRemovedPaths(), path(FOO),path(FOO, BAZ),path(FOO,BAR));
+ /*
+ * Scope base listener event should contain top-level-list item and nested list path
+ * and should not contain baz, bar which are two-level deep
+ */
+ assertContains(change.getRemovedPaths(), path(FOO));
+ assertNotContains(change.getRemovedPaths(),path(FOO, BAZ),path(FOO,BAR));
}
@Override
import org.opendaylight.controller.md.sal.common.api.data.AsyncDataBroker.DataChangeScope;
import org.opendaylight.controller.md.sal.common.api.data.AsyncDataChangeEvent;
import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.controller.md.sal.test.list.rev140701.two.level.list.TopLevelList;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.controller.md.sal.test.list.rev140701.two.level.list.top.level.list.NestedList;
import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier;
import org.opendaylight.yangtools.yang.data.api.schema.NormalizedNode;
assertNotNull(change);
- assertNotContains(change.getCreatedData(), TOP_LEVEL);
- assertContains(change.getCreatedData(), path(FOO), path(FOO, BAR));
+ assertNotContains(change.getCreatedData(), TOP_LEVEL,path(FOO, BAR));
+ assertContains(change.getCreatedData(), path(FOO), path(FOO).node(NestedList.QNAME));
assertEmpty(change.getUpdatedData());
assertEmpty(change.getRemovedPaths());
AsyncDataChangeEvent<YangInstanceIdentifier, NormalizedNode<?, ?>> change = task.getChangeEvent();
assertNotNull(change);
-
- assertContains(change.getCreatedData(), path(FOO, BAZ));
- assertContains(change.getUpdatedData(), path(FOO));
+ /*
+ * Created data must NOT contain nested-list item since scope is base, and change is two
+ * level deep.
+ */
+ assertNotContains(change.getCreatedData(), path(FOO, BAZ));
+ assertContains(change.getUpdatedData(), path(FOO),path(FOO).node(NestedList.QNAME));
assertNotContains(change.getUpdatedData(), TOP_LEVEL);
- assertContains(change.getRemovedPaths(), path(FOO, BAR));
+ /*
+ * Removed data must NOT contain nested-list item since scope is base, and change is two
+ * level deep.
+ */
+ assertNotContains(change.getRemovedPaths(), path(FOO, BAR));
}
assertNotNull(change);
assertFalse(change.getCreatedData().isEmpty());
- assertContains(change.getCreatedData(), path(FOO), path(FOO, BAR), path(FOO, BAZ));
- assertNotContains(change.getCreatedData(), TOP_LEVEL);
+ // Base event should contain only changed item, and details about immediate child.
+ assertContains(change.getCreatedData(), path(FOO),path(FOO).node(NestedList.QNAME));
+ assertNotContains(change.getCreatedData(), TOP_LEVEL,path(FOO, BAR), path(FOO, BAZ));
assertEmpty(change.getUpdatedData());
assertEmpty(change.getRemovedPaths());
assertEmpty(change.getUpdatedData());
assertNotContains(change.getUpdatedData(), TOP_LEVEL);
- assertContains(change.getRemovedPaths(), path(FOO),path(FOO, BAZ),path(FOO,BAR));
+ assertContains(change.getRemovedPaths(), path(FOO),path(FOO).node(NestedList.QNAME));
+ assertNotContains(change.getRemovedPaths(), path(FOO, BAZ),path(FOO,BAR));
}
@Override
import com.google.common.base.Splitter;
import com.google.common.collect.ImmutableSet;
import com.google.common.collect.Iterables;
-
import com.google.common.collect.Sets;
+
import java.util.Collection;
import java.util.HashSet;
import java.util.Set;
}
// FIXME: do we really want to continue here?
- moduleBasedCaps.add(QName.create(namespace, revision, moduleName));
+ moduleBasedCaps.add(QName.cachedReference(QName.create(namespace, revision, moduleName)));
nonModuleCaps.remove(capability);
}
public RpcRegistry() {
bucketStore = getContext().actorOf(Props.create(BucketStore.class), "store");
+
+ log.info("Bucket store path = {}", bucketStore.path().toString());
}
public RpcRegistry(ActorRef bucketStore) {
import akka.cluster.Cluster;
import akka.event.Logging;
import akka.event.LoggingAdapter;
+import org.opendaylight.controller.utils.ConditionalProbe;
import java.util.HashMap;
import java.util.Map;
*/
private ActorRef gossiper;
+ private ConditionalProbe probe;
+
public BucketStore(){
gossiper = getContext().actorOf(Props.create(Gossiper.class), "gossiper");
}
@Override
public void onReceive(Object message) throws Exception {
- log.debug("Received message: node[{}], message[{}]", selfAddress, message);
+ log.debug("Received message: node[{}], message[{}]", selfAddress,
+ message);
- if (message instanceof UpdateBucket)
- receiveUpdateBucket(((UpdateBucket) message).getBucket());
+ if (probe != null) {
- else if (message instanceof GetAllBuckets)
- receiveGetAllBucket();
+ probe.tell(message, getSelf());
+ }
- else if (message instanceof GetLocalBucket)
+ if (message instanceof ConditionalProbe) {
+ log.info("Received probe {} {}", getSelf(), message);
+ probe = (ConditionalProbe) message;
+ } else if (message instanceof UpdateBucket) {
+ receiveUpdateBucket(((UpdateBucket) message).getBucket());
+ } else if (message instanceof GetAllBuckets) {
+ receiveGetAllBucket();
+ } else if (message instanceof GetLocalBucket) {
receiveGetLocalBucket();
-
- else if (message instanceof GetBucketsByMembers)
- receiveGetBucketsByMembers(((GetBucketsByMembers) message).getMembers());
-
- else if (message instanceof GetBucketVersions)
+ } else if (message instanceof GetBucketsByMembers) {
+ receiveGetBucketsByMembers(
+ ((GetBucketsByMembers) message).getMembers());
+ } else if (message instanceof GetBucketVersions) {
receiveGetBucketVersions();
-
- else if (message instanceof UpdateRemoteBuckets)
- receiveUpdateRemoteBuckets(((UpdateRemoteBuckets) message).getBuckets());
-
- else {
+ } else if (message instanceof UpdateRemoteBuckets) {
+ receiveUpdateRemoteBuckets(
+ ((UpdateRemoteBuckets) message).getBuckets());
+ } else {
log.debug("Unhandled message [{}]", message);
unhandled(message);
}
Address getSelfAddress() {
return selfAddress;
}
+
}
--- /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.utils;
+
+import akka.actor.ActorRef;
+import com.google.common.base.Predicate;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+public class ConditionalProbe {
+ private final ActorRef actorRef;
+ private final Predicate predicate;
+ Logger log = LoggerFactory.getLogger(ConditionalProbe.class);
+
+ public ConditionalProbe(ActorRef actorRef, Predicate predicate) {
+ this.actorRef = actorRef;
+ this.predicate = predicate;
+ }
+
+ public void tell(Object message, ActorRef sender){
+ if(predicate.apply(message)) {
+ log.info("sending message to probe {}", message);
+ actorRef.tell(message, sender);
+ }
+ }
+}
package org.opendaylight.controller.remote.rpc.registry;
+
import akka.actor.ActorPath;
import akka.actor.ActorRef;
import akka.actor.ActorSelection;
import akka.actor.ActorSystem;
import akka.actor.ChildActorPath;
import akka.actor.Props;
-import akka.japi.Pair;
import akka.testkit.JavaTestKit;
+import com.google.common.base.Predicate;
import com.typesafe.config.ConfigFactory;
+
import org.junit.After;
import org.junit.AfterClass;
import org.junit.Assert;
import org.junit.BeforeClass;
import org.junit.Test;
import org.opendaylight.controller.remote.rpc.RouteIdentifierImpl;
+import org.opendaylight.controller.remote.rpc.registry.gossip.Messages;
import org.opendaylight.controller.sal.connector.api.RpcRouter;
+import org.opendaylight.controller.utils.ConditionalProbe;
import org.opendaylight.yangtools.yang.common.QName;
import scala.concurrent.Await;
import scala.concurrent.Future;
import scala.concurrent.duration.FiniteDuration;
+import javax.annotation.Nullable;
import java.net.URI;
import java.net.URISyntaxException;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.TimeUnit;
+import static org.opendaylight.controller.remote.rpc.registry.RpcRegistry.Messages.SetLocalRouter;
import static org.opendaylight.controller.remote.rpc.registry.RpcRegistry.Messages.AddOrUpdateRoutes;
import static org.opendaylight.controller.remote.rpc.registry.RpcRegistry.Messages.RemoveRoutes;
-import static org.opendaylight.controller.remote.rpc.registry.RpcRegistry.Messages.FindRouters;
-import static org.opendaylight.controller.remote.rpc.registry.RpcRegistry.Messages.FindRoutersReply;
-import static org.opendaylight.controller.remote.rpc.registry.RpcRegistry.Messages.SetLocalRouter;
public class RpcRegistryTest {
- private static ActorSystem node1;
- private static ActorSystem node2;
- private static ActorSystem node3;
-
- private ActorRef registry1;
- private ActorRef registry2;
- private ActorRef registry3;
-
- @BeforeClass
- public static void setup() throws InterruptedException {
- Thread.sleep(1000); //give some time for previous test to close netty ports
- node1 = ActorSystem.create("opendaylight-rpc", ConfigFactory.load().getConfig("memberA"));
- node2 = ActorSystem.create("opendaylight-rpc", ConfigFactory.load().getConfig("memberB"));
- node3 = ActorSystem.create("opendaylight-rpc", ConfigFactory.load().getConfig("memberC"));
- }
-
- @AfterClass
- public static void teardown(){
- JavaTestKit.shutdownActorSystem(node1);
- JavaTestKit.shutdownActorSystem(node2);
- JavaTestKit.shutdownActorSystem(node3);
- if (node1 != null)
- node1.shutdown();
- if (node2 != null)
- node2.shutdown();
- if (node3 != null)
- node3.shutdown();
-
- }
-
- @Before
- public void createRpcRegistry() throws InterruptedException {
- registry1 = node1.actorOf(Props.create(RpcRegistry.class));
- registry2 = node2.actorOf(Props.create(RpcRegistry.class));
- registry3 = node3.actorOf(Props.create(RpcRegistry.class));
- }
-
- @After
- public void stopRpcRegistry() throws InterruptedException {
- if (registry1 != null)
- node1.stop(registry1);
- if (registry2 != null)
- node2.stop(registry2);
- if (registry3 != null)
- node3.stop(registry3);
- }
+ private static ActorSystem node1;
+ private static ActorSystem node2;
+ private static ActorSystem node3;
+
+ private ActorRef registry1;
+ private ActorRef registry2;
+ private ActorRef registry3;
+
+ @BeforeClass
+ public static void setup() throws InterruptedException {
+ node1 = ActorSystem.create("opendaylight-rpc", ConfigFactory.load().getConfig("memberA"));
+ node2 = ActorSystem.create("opendaylight-rpc", ConfigFactory.load().getConfig("memberB"));
+ node3 = ActorSystem.create("opendaylight-rpc", ConfigFactory.load().getConfig("memberC"));
+ }
+
+ @AfterClass
+ public static void teardown() {
+ JavaTestKit.shutdownActorSystem(node1);
+ JavaTestKit.shutdownActorSystem(node2);
+ JavaTestKit.shutdownActorSystem(node3);
+ if (node1 != null)
+ node1.shutdown();
+ if (node2 != null)
+ node2.shutdown();
+ if (node3 != null)
+ node3.shutdown();
+
+ }
+
+ @Before
+ public void createRpcRegistry() throws InterruptedException {
+ registry1 = node1.actorOf(Props.create(RpcRegistry.class));
+ registry2 = node2.actorOf(Props.create(RpcRegistry.class));
+ registry3 = node3.actorOf(Props.create(RpcRegistry.class));
+ }
+
+ @After
+ public void stopRpcRegistry() throws InterruptedException {
+ if (registry1 != null)
+ node1.stop(registry1);
+ if (registry2 != null)
+ node2.stop(registry2);
+ if (registry3 != null)
+ node3.stop(registry3);
+ }
+
+ /**
+ * One node cluster.
+ * 1. Register rpc, ensure router can be found
+ * 2. Then remove rpc, ensure its deleted
+ *
+ * @throws URISyntaxException
+ * @throws InterruptedException
+ */
+ @Test
+ public void testAddRemoveRpcOnSameNode() throws URISyntaxException, InterruptedException {
+ validateSystemStartup();
+
+ final JavaTestKit mockBroker = new JavaTestKit(node1);
+
+ final ActorPath bucketStorePath = new ChildActorPath(registry1.path(), "store");
+
+ //install probe
+ final JavaTestKit probe1 = createProbeForMessage(
+ node1, bucketStorePath, Messages.BucketStoreMessages.UpdateBucket.class);
+
+ //Add rpc on node 1
+ registry1.tell(new SetLocalRouter(mockBroker.getRef()), mockBroker.getRef());
+ registry1.tell(getAddRouteMessage(), mockBroker.getRef());
+
+ //Bucket store should get an update bucket message. Updated bucket contains added rpc.
+ probe1.expectMsgClass(
+ FiniteDuration.apply(10, TimeUnit.SECONDS),
+ Messages.BucketStoreMessages.UpdateBucket.class);
+
+ //Now remove rpc
+ registry1.tell(getRemoveRouteMessage(), mockBroker.getRef());
+
+ //Bucket store should get an update bucket message. Rpc is removed in the updated bucket
+ probe1.expectMsgClass(
+ FiniteDuration.apply(10, TimeUnit.SECONDS),
+ Messages.BucketStoreMessages.UpdateBucket.class);
+
+
+ }
+
+
+ /**
+ * Three node cluster.
+ * 1. Register rpc on 1 node, ensure 2nd node gets updated
+ * 2. Remove rpc on 1 node, ensure 2nd node gets updated
+ *
+ * @throws URISyntaxException
+ * @throws InterruptedException
+ */
+ @Test
+ public void testRpcAddRemoveInCluster() throws URISyntaxException, InterruptedException {
- /**
- * One node cluster.
- * 1. Register rpc, ensure router can be found
- * 2. Then remove rpc, ensure its deleted
- *
- * @throws URISyntaxException
- * @throws InterruptedException
- */
- @Test
- public void testAddRemoveRpcOnSameNode() throws URISyntaxException, InterruptedException {
-
- final JavaTestKit mockBroker = new JavaTestKit(node1);
-
- //Add rpc on node 1
- registry1.tell(new SetLocalRouter(mockBroker.getRef()), mockBroker.getRef());
- registry1.tell(getAddRouteMessage(), mockBroker.getRef());
-
- Thread.sleep(1000);//
-
- //find the route on node 1's registry
- registry1.tell(new FindRouters(createRouteId()), mockBroker.getRef());
- FindRoutersReply message = mockBroker.expectMsgClass(JavaTestKit.duration("10 second"), FindRoutersReply.class);
- List<Pair<ActorRef, Long>> pairs = message.getRouterWithUpdateTime();
-
- validateRouterReceived(pairs, mockBroker.getRef());
-
- //Now remove rpc
- registry1.tell(getRemoveRouteMessage(), mockBroker.getRef());
- Thread.sleep(1000);
- //find the route on node 1's registry
- registry1.tell(new FindRouters(createRouteId()), mockBroker.getRef());
- message = mockBroker.expectMsgClass(JavaTestKit.duration("10 second"), FindRoutersReply.class);
- pairs = message.getRouterWithUpdateTime();
-
- Assert.assertTrue(pairs.isEmpty());
- }
+ validateSystemStartup();
+
+ final JavaTestKit mockBroker1 = new JavaTestKit(node1);
+
+ //install probe on node2's bucket store
+ final ActorPath bucketStorePath = new ChildActorPath(registry2.path(), "store");
+ final JavaTestKit probe2 = createProbeForMessage(
+ node2, bucketStorePath, Messages.BucketStoreMessages.UpdateRemoteBuckets.class);
- /**
- * Three node cluster.
- * 1. Register rpc on 1 node, ensure its router can be found on other 2.
- * 2. Remove rpc on 1 node, ensure its removed on other 2.
- *
- * @throws URISyntaxException
- * @throws InterruptedException
- */
- @Test
- public void testRpcAddRemoveInCluster() throws URISyntaxException, InterruptedException {
- validateSystemStartup();
+ //Add rpc on node 1
+ registry1.tell(new SetLocalRouter(mockBroker1.getRef()), mockBroker1.getRef());
+ registry1.tell(getAddRouteMessage(), mockBroker1.getRef());
- final JavaTestKit mockBroker1 = new JavaTestKit(node1);
- final JavaTestKit mockBroker2 = new JavaTestKit(node2);
- final JavaTestKit mockBroker3 = new JavaTestKit(node3);
+ //Bucket store on node2 should get a message to update its local copy of remote buckets
+ probe2.expectMsgClass(
+ FiniteDuration.apply(10, TimeUnit.SECONDS),
+ Messages.BucketStoreMessages.UpdateRemoteBuckets.class);
- //Add rpc on node 1
- registry1.tell(new SetLocalRouter(mockBroker1.getRef()), mockBroker1.getRef());
- registry1.tell(getAddRouteMessage(), mockBroker1.getRef());
+ //Now remove
+ registry1.tell(getRemoveRouteMessage(), mockBroker1.getRef());
- Thread.sleep(1000);// give some time for bucket store data sync
+ //Bucket store on node2 should get a message to update its local copy of remote buckets
+ probe2.expectMsgClass(
+ FiniteDuration.apply(10, TimeUnit.SECONDS),
+ Messages.BucketStoreMessages.UpdateRemoteBuckets.class);
- //find the route in node 2's registry
- List<Pair<ActorRef, Long>> pairs = findRouters(registry2, mockBroker2);
- validateRouterReceived(pairs, mockBroker1.getRef());
+ }
- //find the route in node 3's registry
- pairs = findRouters(registry3, mockBroker3);
- validateRouterReceived(pairs, mockBroker1.getRef());
+ /**
+ * Three node cluster.
+ * Register rpc on 2 nodes. Ensure 3rd gets updated.
+ *
+ * @throws Exception
+ */
+ @Test
+ public void testRpcAddedOnMultiNodes() throws Exception {
- //Now remove
- registry1.tell(getRemoveRouteMessage(), mockBroker1.getRef());
- Thread.sleep(1000);// give some time for bucket store data sync
+ validateSystemStartup();
- pairs = findRouters(registry2, mockBroker2);
- Assert.assertTrue(pairs.isEmpty());
+ final JavaTestKit mockBroker1 = new JavaTestKit(node1);
+ final JavaTestKit mockBroker2 = new JavaTestKit(node2);
+ final JavaTestKit mockBroker3 = new JavaTestKit(node3);
- pairs = findRouters(registry3, mockBroker3);
- Assert.assertTrue(pairs.isEmpty());
- }
+ registry3.tell(new SetLocalRouter(mockBroker3.getRef()), mockBroker3.getRef());
- /**
- * Three node cluster.
- * Register rpc on 2 nodes. Ensure 2 routers are found on 3rd.
- *
- * @throws Exception
- */
- @Test
- public void testAnRpcAddedOnMultiNodesShouldReturnMultiRouter() throws Exception {
+ //install probe on node 3
+ final ActorPath bucketStorePath = new ChildActorPath(registry3.path(), "store");
+ final JavaTestKit probe3 = createProbeForMessage(
+ node3, bucketStorePath, Messages.BucketStoreMessages.UpdateRemoteBuckets.class);
- validateSystemStartup();
- final JavaTestKit mockBroker1 = new JavaTestKit(node1);
- final JavaTestKit mockBroker2 = new JavaTestKit(node2);
- final JavaTestKit mockBroker3 = new JavaTestKit(node3);
+ //Add rpc on node 1
+ registry1.tell(new SetLocalRouter(mockBroker1.getRef()), mockBroker1.getRef());
+ registry1.tell(getAddRouteMessage(), mockBroker1.getRef());
- //Thread.sleep(5000);//let system come up
+ probe3.expectMsgClass(
+ FiniteDuration.apply(10, TimeUnit.SECONDS),
+ Messages.BucketStoreMessages.UpdateRemoteBuckets.class);
- //Add rpc on node 1
- registry1.tell(new SetLocalRouter(mockBroker1.getRef()), mockBroker1.getRef());
- registry1.tell(getAddRouteMessage(), mockBroker1.getRef());
- //Add same rpc on node 2
- registry2.tell(new SetLocalRouter(mockBroker2.getRef()), mockBroker2.getRef());
- registry2.tell(getAddRouteMessage(), mockBroker2.getRef());
+ //Add same rpc on node 2
+ registry2.tell(new SetLocalRouter(mockBroker2.getRef()), mockBroker2.getRef());
+ registry2.tell(getAddRouteMessage(), mockBroker2.getRef());
- registry3.tell(new SetLocalRouter(mockBroker3.getRef()), mockBroker3.getRef());
- Thread.sleep(1000);// give some time for bucket store data sync
+ probe3.expectMsgClass(
+ FiniteDuration.apply(10, TimeUnit.SECONDS),
+ Messages.BucketStoreMessages.UpdateRemoteBuckets.class);
+ }
- //find the route in node 3's registry
- registry3.tell(new FindRouters(createRouteId()), mockBroker3.getRef());
- FindRoutersReply message = mockBroker3.expectMsgClass(JavaTestKit.duration("10 second"), FindRoutersReply.class);
- List<Pair<ActorRef, Long>> pairs = message.getRouterWithUpdateTime();
+ private JavaTestKit createProbeForMessage(ActorSystem node, ActorPath subjectPath, final Class clazz) {
+ final JavaTestKit probe = new JavaTestKit(node);
- validateMultiRouterReceived(pairs, mockBroker1.getRef(), mockBroker2.getRef());
+ ConditionalProbe conditionalProbe =
+ new ConditionalProbe(probe.getRef(), new Predicate() {
+ @Override
+ public boolean apply(@Nullable Object input) {
+ return clazz.equals(input.getClass());
+ }
+ });
- }
+ ActorSelection subject = node.actorSelection(subjectPath);
+ subject.tell(conditionalProbe, ActorRef.noSender());
- private List<Pair<ActorRef, Long>> findRouters(ActorRef registry, JavaTestKit receivingActor) throws URISyntaxException {
- registry.tell(new FindRouters(createRouteId()), receivingActor.getRef());
- FindRoutersReply message = receivingActor.expectMsgClass(JavaTestKit.duration("10 second"), FindRoutersReply.class);
- return message.getRouterWithUpdateTime();
- }
+ return probe;
- private void validateMultiRouterReceived(List<Pair<ActorRef, Long>> actual, ActorRef... expected) {
- Assert.assertTrue(actual != null);
- Assert.assertTrue(actual.size() == expected.length);
- }
+ }
- private void validateRouterReceived(List<Pair<ActorRef, Long>> actual, ActorRef expected){
- Assert.assertTrue(actual != null);
- Assert.assertTrue(actual.size() == 1);
+ private void validateSystemStartup() throws InterruptedException {
- for (Pair<ActorRef, Long> pair : actual){
- Assert.assertTrue(expected.path().uid() == pair.first().path().uid());
- }
- }
+ ActorPath gossiper1Path = new ChildActorPath(new ChildActorPath(registry1.path(), "store"), "gossiper");
+ ActorPath gossiper2Path = new ChildActorPath(new ChildActorPath(registry2.path(), "store"), "gossiper");
+ ActorPath gossiper3Path = new ChildActorPath(new ChildActorPath(registry3.path(), "store"), "gossiper");
- private void validateSystemStartup() throws InterruptedException {
+ ActorSelection gossiper1 = node1.actorSelection(gossiper1Path);
+ ActorSelection gossiper2 = node2.actorSelection(gossiper2Path);
+ ActorSelection gossiper3 = node3.actorSelection(gossiper3Path);
- Thread.sleep(5000);
- ActorPath gossiper1Path = new ChildActorPath(new ChildActorPath(registry1.path(), "store"), "gossiper");
- ActorPath gossiper2Path = new ChildActorPath(new ChildActorPath(registry2.path(), "store"), "gossiper");
- ActorPath gossiper3Path = new ChildActorPath(new ChildActorPath(registry3.path(), "store"), "gossiper");
- ActorSelection gossiper1 = node1.actorSelection(gossiper1Path);
- ActorSelection gossiper2 = node2.actorSelection(gossiper2Path);
- ActorSelection gossiper3 = node3.actorSelection(gossiper3Path);
+ if (!resolveReference(gossiper1, gossiper2, gossiper3))
+ Assert.fail("Could not find gossipers");
+ }
+ private Boolean resolveReference(ActorSelection... gossipers) {
- if (!resolveReference(gossiper1, gossiper2, gossiper3))
- Assert.fail("Could not find gossipers");
- }
+ Boolean resolved = true;
+ for (int i = 0; i < 5; i++) {
- private Boolean resolveReference(ActorSelection... gossipers) throws InterruptedException {
+ resolved = true;
+ System.out.println(System.currentTimeMillis() + " Resolving gossipers; trial #" + i);
- Boolean resolved = true;
+ for (ActorSelection gossiper : gossipers) {
+ ActorRef ref = null;
- for (int i=0; i< 5; i++) {
- Thread.sleep(1000);
- for (ActorSelection gossiper : gossipers) {
- Future<ActorRef> future = gossiper.resolveOne(new FiniteDuration(5000, TimeUnit.MILLISECONDS));
+ try {
+ Future<ActorRef> future = gossiper.resolveOne(new FiniteDuration(15000, TimeUnit.MILLISECONDS));
+ ref = Await.result(future, new FiniteDuration(10000, TimeUnit.MILLISECONDS));
+ } catch (Exception e) {
+ System.out.println("Could not find gossiper in attempt#" + i + ". Got exception " + e.getMessage());
+ }
- ActorRef ref = null;
- try {
- ref = Await.result(future, new FiniteDuration(10000, TimeUnit.MILLISECONDS));
- } catch (Exception e) {
- e.printStackTrace();
- }
+ if (ref == null)
+ resolved = false;
+ }
- if (ref == null)
- resolved = false;
- }
+ if (resolved) break;
- if (resolved) break;
- }
- return resolved;
}
+ return resolved;
+ }
- private AddOrUpdateRoutes getAddRouteMessage() throws URISyntaxException {
- return new AddOrUpdateRoutes(createRouteIds());
- }
+ private AddOrUpdateRoutes getAddRouteMessage() throws URISyntaxException {
+ return new AddOrUpdateRoutes(createRouteIds());
+ }
- private RemoveRoutes getRemoveRouteMessage() throws URISyntaxException {
- return new RemoveRoutes(createRouteIds());
- }
+ private RemoveRoutes getRemoveRouteMessage() throws URISyntaxException {
+ return new RemoveRoutes(createRouteIds());
+ }
- private List<RpcRouter.RouteIdentifier<?,?,?>> createRouteIds() throws URISyntaxException {
- QName type = new QName(new URI("/mockrpc"), "mockrpc");
- List<RpcRouter.RouteIdentifier<?,?,?>> routeIds = new ArrayList<>();
- routeIds.add(new RouteIdentifierImpl(null, type, null));
- return routeIds;
- }
+ private List<RpcRouter.RouteIdentifier<?, ?, ?>> createRouteIds() throws URISyntaxException {
+ QName type = new QName(new URI("/mockrpc"), "mockrpc");
+ List<RpcRouter.RouteIdentifier<?, ?, ?>> routeIds = new ArrayList<>();
+ routeIds.add(new RouteIdentifierImpl(null, type, null));
+ return routeIds;
+ }
- private RpcRouter.RouteIdentifier<?,?,?> createRouteId() throws URISyntaxException {
- QName type = new QName(new URI("/mockrpc"), "mockrpc");
- return new RouteIdentifierImpl(null, type, null);
- }
-}
\ No newline at end of file
+}
odl-cluster{
akka {
- loglevel = "INFO"
+ loglevel = "DEBUG"
#log-config-on-start = on
actor {
loggers = ["akka.event.slf4j.Slf4jLogger"]
actor {
provider = "akka.cluster.ClusterActorRefProvider"
+ debug {
+ #lifecycle = on
+ }
}
remote {
log-received-messages = off
--- /dev/null
+<configuration scan="true">
+
+ <appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender">
+ <encoder>
+ <pattern>%d{HH:mm:ss.SSS} [%thread] %-5level %logger{36} - %msg%n
+ </pattern>
+ </encoder>
+ </appender>
+
+ <root level="debug">
+ <appender-ref ref="STDOUT" />
+ </root>
+</configuration>
* Constructs an instance with the given errors.
*/
public RestconfDocumentedException(String message, Throwable cause, List<RestconfError> errors) {
- super(message, cause);
+ // FIXME: We override getMessage so supplied message is lost for any public access
+ // this was lost also in original code.
+ super(cause);
if(!errors.isEmpty()) {
this.errors = ImmutableList.copyOf(errors);
} else {
public void applyOperation(final ReadWriteTransaction transaction) {
final Node node = toTopologyNode(toTopologyNodeId(notification.getId()), notification.getNodeRef());
final InstanceIdentifier<Node> path = getNodePath(toTopologyNodeId(notification.getId()));
- transaction.put(LogicalDatastoreType.OPERATIONAL, path, node);
+ transaction.merge(LogicalDatastoreType.OPERATIONAL, path, node, true);
}
});
}
TerminationPoint point = toTerminationPoint(toTerminationPointId(notification.getId()),
notification.getNodeConnectorRef());
final InstanceIdentifier<TerminationPoint> path = tpPath(nodeId, point.getKey().getTpId());
- transaction.put(LogicalDatastoreType.OPERATIONAL, path, point);
+ transaction.merge(LogicalDatastoreType.OPERATIONAL, path, point, true);
if ((fcncu.getState() != null && fcncu.getState().isLinkDown())
|| (fcncu.getConfiguration() != null && fcncu.getConfiguration().isPORTDOWN())) {
removeAffectedLinks(point.getTpId());
package org.opendaylight.controller.netconf.client;
import io.netty.channel.Channel;
+
import java.util.Collection;
+
import org.opendaylight.controller.netconf.nettyutil.AbstractNetconfSession;
import org.opendaylight.controller.netconf.nettyutil.handler.NetconfEXICodec;
import org.opendaylight.controller.netconf.nettyutil.handler.NetconfEXIToMessageDecoder;
private static final Logger logger = LoggerFactory.getLogger(NetconfClientSession.class);
private final Collection<String> capabilities;
- public NetconfClientSession(NetconfClientSessionListener sessionListener, Channel channel, long sessionId,
- Collection<String> capabilities) {
+ /**
+ * Construct a new session.
+ *
+ * @param sessionListener
+ * @param channel
+ * @param sessionId
+ * @param capabilities set of advertised capabilities. Expected to be immutable.
+ */
+ public NetconfClientSession(final NetconfClientSessionListener sessionListener, final Channel channel, final long sessionId,
+ final Collection<String> capabilities) {
super(sessionListener, channel, sessionId);
this.capabilities = capabilities;
logger.debug("Client Session {} created", toString());
}
@Override
- protected void addExiHandlers(NetconfEXICodec exiCodec) {
+ protected void addExiHandlers(final NetconfEXICodec exiCodec) {
// TODO used only in negotiator, client supports only auto start-exi
replaceMessageDecoder(new NetconfEXIToMessageDecoder(exiCodec));
replaceMessageEncoder(new NetconfMessageToEXIEncoder(exiCodec));
package org.opendaylight.controller.netconf.client;
+import com.google.common.collect.ImmutableList;
+
import io.netty.channel.Channel;
import io.netty.channel.ChannelFuture;
import io.netty.channel.ChannelFutureListener;
private static final String EXI_1_0_CAPABILITY_MARKER = "exi:1.0";
- protected NetconfClientSessionNegotiator(NetconfClientSessionPreferences sessionPreferences,
- Promise<NetconfClientSession> promise,
- Channel channel,
- Timer timer,
- NetconfClientSessionListener sessionListener,
- long connectionTimeoutMillis) {
+ protected NetconfClientSessionNegotiator(final NetconfClientSessionPreferences sessionPreferences,
+ final Promise<NetconfClientSession> promise,
+ final Channel channel,
+ final Timer timer,
+ final NetconfClientSessionListener sessionListener,
+ final long connectionTimeoutMillis) {
super(sessionPreferences, promise, channel, timer, sessionListener, connectionTimeoutMillis);
}
@Override
- protected void handleMessage(NetconfHelloMessage netconfMessage) throws NetconfDocumentedException {
+ protected void handleMessage(final NetconfHelloMessage netconfMessage) throws NetconfDocumentedException {
final NetconfClientSession session = getSessionForHelloMessage(netconfMessage);
replaceHelloMessageInboundHandler(session);
});
}
- private boolean shouldUseExi(NetconfHelloMessage helloMsg) {
+ private boolean shouldUseExi(final NetconfHelloMessage helloMsg) {
return containsExi10Capability(helloMsg.getDocument())
&& containsExi10Capability(sessionPreferences.getHelloMessage().getDocument());
}
return false;
}
- private long extractSessionId(Document doc) {
+ private long extractSessionId(final Document doc) {
final Node sessionIdNode = (Node) XmlUtil.evaluateXPath(sessionIdXPath, doc, XPathConstants.NODE);
String textContent = sessionIdNode.getTextContent();
if (textContent == null || textContent.equals("")) {
}
@Override
- protected NetconfClientSession getSession(NetconfClientSessionListener sessionListener, Channel channel,
- NetconfHelloMessage message) throws NetconfDocumentedException {
+ protected NetconfClientSession getSession(final NetconfClientSessionListener sessionListener, final Channel channel,
+ final NetconfHelloMessage message) throws NetconfDocumentedException {
long sessionId = extractSessionId(message.getDocument());
- Collection<String> capabilities = NetconfMessageUtil.extractCapabilitiesFromHello(message.getDocument());
+
+ // Copy here is important: it disconnects the strings from the document
+ Collection<String> capabilities = ImmutableList.copyOf(NetconfMessageUtil.extractCapabilitiesFromHello(message.getDocument()));
+
+ // FIXME: scalability: we could instantiate a cache to share the same collections
return new NetconfClientSession(sessionListener, channel, sessionId, capabilities);
}
private static final String EXI_CONFIRMED_HANDLER = "exiConfirmedHandler";
private final NetconfClientSession session;
- private NetconfStartExiMessage startExiMessage;
+ private final NetconfStartExiMessage startExiMessage;
- ExiConfirmationInboundHandler(NetconfClientSession session, final NetconfStartExiMessage startExiMessage) {
+ ExiConfirmationInboundHandler(final NetconfClientSession session, final NetconfStartExiMessage startExiMessage) {
this.session = session;
this.startExiMessage = startExiMessage;
}
@Override
- public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception {
+ public void channelRead(final ChannelHandlerContext ctx, final Object msg) throws Exception {
ctx.pipeline().remove(ExiConfirmationInboundHandler.EXI_CONFIRMED_HANDLER);
NetconfMessage netconfMessage = (NetconfMessage) msg;
private OutputStream stdIn;
- private Queue<ByteBuf> postponed = new LinkedList<>();
+ private final Queue<ByteBuf> postponed = new LinkedList<>();
private ChannelHandlerContext ctx;
private ChannelPromise disconnectPromise;
private final Object lock = new Object();
- public SshClientAdapter(SshClient sshClient, Invoker invoker) {
+ public SshClientAdapter(final SshClient sshClient, final Invoker invoker) {
this.sshClient = sshClient;
this.invoker = invoker;
}
- // TODO: refactor
+ // TODO ganymed spawns a Thread that receives the data from remote inside TransportManager
+ // Get rid of this thread and reuse Ganymed internal thread (not sure if its possible without modifications in ganymed)
public void run() {
try {
- SshSession session = sshClient.openSession();
+ final SshSession session = sshClient.openSession();
invoker.invoke(session);
- InputStream stdOut = session.getStdout();
- session.getStderr();
+ final InputStream stdOut = session.getStdout();
synchronized (lock) {
-
stdIn = session.getStdin();
- ByteBuf message;
- while ((message = postponed.poll()) != null) {
- writeImpl(message);
+ while (postponed.peek() != null) {
+ writeImpl(postponed.poll());
}
}
while (!stopRequested.get()) {
- byte[] readBuff = new byte[BUFFER_SIZE];
- int c = stdOut.read(readBuff);
+ final byte[] readBuff = new byte[BUFFER_SIZE];
+ final int c = stdOut.read(readBuff);
if (c == -1) {
continue;
}
- byte[] tranBuff = new byte[c];
- System.arraycopy(readBuff, 0, tranBuff, 0, c);
- ByteBuf byteBuf = Unpooled.buffer(c);
- byteBuf.writeBytes(tranBuff);
- ctx.fireChannelRead(byteBuf);
+ ctx.fireChannelRead(Unpooled.copiedBuffer(readBuff, 0, c));
}
- } catch (Exception e) {
+ } catch (final Exception e) {
logger.error("Unexpected exception", e);
} finally {
sshClient.close();
}
// TODO: needs rework to match netconf framer API.
- public void write(ByteBuf message) throws IOException {
+ public void write(final ByteBuf message) throws IOException {
synchronized (lock) {
if (stdIn == null) {
postponed.add(message);
}
}
- private void writeImpl(ByteBuf message) throws IOException {
+ private void writeImpl(final ByteBuf message) throws IOException {
message.getBytes(0, stdIn, message.readableBytes());
message.release();
stdIn.flush();
}
- public void stop(ChannelPromise promise) {
+ public void stop(final ChannelPromise promise) {
synchronized (lock) {
stopRequested.set(true);
disconnectPromise = promise;
}
}
- public Thread start(ChannelHandlerContext ctx, ChannelFuture channelFuture) {
+ public Thread start(final ChannelHandlerContext ctx, final ChannelFuture channelFuture) {
checkArgument(channelFuture.isSuccess());
checkNotNull(ctx.channel().remoteAddress());
synchronized (this) {
checkState(this.ctx == null);
this.ctx = ctx;
}
- String threadName = toString();
- Thread thread = new Thread(this, threadName);
+ final String threadName = toString();
+ final Thread thread = new Thread(this, threadName);
thread.start();
return thread;
}
package org.opendaylight.controller.netconf.nettyutil.handler.ssh.client;
import ch.ethz.ssh2.Session;
-import ch.ethz.ssh2.StreamGobbler;
-
import ch.ethz.ssh2.channel.Channel;
import java.io.Closeable;
import java.io.IOException;
class SshSession implements Closeable {
private final Session session;
- public SshSession(Session session) {
+ public SshSession(final Session session) {
this.session = session;
}
-
- public void startSubSystem(String name) throws IOException {
+ public void startSubSystem(final String name) throws IOException {
session.startSubSystem(name);
}
public InputStream getStdout() {
- return new StreamGobbler(session.getStdout());
+ return session.getStdout();
}
+ // FIXME according to http://www.ganymed.ethz.ch/ssh2/FAQ.html#blocking you should read data from both stdout and stderr to prevent window filling up (since stdout and stderr share a window)
+ // FIXME stdErr is not used anywhere
public InputStream getStderr() {
return session.getStderr();
}
ChannelFuture clientChannelFuture = initializeNettyConnection(localAddress, bossGroup, sshClientHandler);
// get channel
final Channel channel = clientChannelFuture.awaitUninterruptibly().channel();
+
+ // write additional header before polling thread is started
+ // polling thread could process and forward data before additional header is written
+ // This will result into unexpected state: hello message without additional header and the next message with additional header
+ channel.writeAndFlush(Unpooled.copiedBuffer(additionalHeader.getBytes()));
+
new ClientInputStreamPoolingThread(session, ss.getStdout(), channel, new AutoCloseable() {
@Override
public void close() throws Exception {
}
}
}, sshClientHandler.getChannelHandlerContext()).start();
-
- // write additional header
- channel.writeAndFlush(Unpooled.copiedBuffer(additionalHeader.getBytes()));
} else {
logger.debug("{} Wrong subsystem requested:'{}', closing ssh session", serverSession, subsystem);
String reason = "Only netconf subsystem is supported, requested:" + subsystem;
import java.io.InputStreamReader;
import java.util.List;
+import java.util.concurrent.TimeUnit;
import net.sourceforge.argparse4j.ArgumentParsers;
import net.sourceforge.argparse4j.annotation.Arg;
import net.sourceforge.argparse4j.inf.ArgumentParser;
@Arg(dest = "starting-port")
public int startingPort;
+ @Arg(dest = "generate-config-connection-timeout")
+ public int generateConfigsTimeout;
+
@Arg(dest = "generate-configs-dir")
public File generateConfigsDir;
@Arg(dest = "ssh")
public boolean ssh;
+ @Arg(dest = "exi")
+ public boolean exi;
+
static ArgumentParser getParser() {
final ArgumentParser parser = ArgumentParsers.newArgumentParser("netconf testool");
parser.addArgument("--devices-count")
.help("First port for simulated device. Each other device will have previous+1 port number")
.dest("starting-port");
+ parser.addArgument("--generate-config-connection-timeout")
+ .type(Integer.class)
+ .setDefault((int)TimeUnit.MINUTES.toMillis(5))
+ .help("Timeout to be generated in initial config files")
+ .dest("generate-config-connection-timeout");
+
parser.addArgument("--generate-configs-batch-size")
.type(Integer.class)
.setDefault(100)
.help("Whether to use ssh for transport or just pure tcp")
.dest("ssh");
+ parser.addArgument("--exi")
+ .type(Boolean.class)
+ .setDefault(false)
+ .help("Whether to use exi to transport xml content")
+ .dest("exi");
+
return parser;
}
}
public static void main(final String[] args) {
+ ch.ethz.ssh2.log.Logger.enabled = true;
+
final Params params = parseArgs(args, Params.getParser());
params.validate();
try {
final List<Integer> openDevices = netconfDeviceSimulator.start(params);
if(params.generateConfigsDir != null) {
- new ConfigGenerator(params.generateConfigsDir, openDevices).generate(params.ssh, params.generateConfigBatchSize);
+ new ConfigGenerator(params.generateConfigsDir, openDevices).generate(params.ssh, params.generateConfigBatchSize, params.generateConfigsTimeout);
}
} catch (final Exception e) {
LOG.error("Unhandled exception", e);
this.openDevices = openDevices;
}
- public void generate(final boolean useSsh, final int batchSize) {
+ public void generate(final boolean useSsh, final int batchSize, final int generateConfigsTimeout) {
if(directory.exists() == false) {
checkState(directory.mkdirs(), "Unable to create folder %s" + directory);
}
configBlueprint = configBlueprint.replace(NETCONF_USE_SSH, "%s");
final String before = configBlueprint.substring(0, configBlueprint.indexOf("<module>"));
- final String middleBlueprint = configBlueprint.substring(configBlueprint.indexOf("<module>"), configBlueprint.indexOf("</module>") + "</module>".length());
+ final String middleBlueprint = configBlueprint.substring(configBlueprint.indexOf("<module>"), configBlueprint.indexOf("</module>"));
final String after = configBlueprint.substring(configBlueprint.indexOf("</module>") + "</module>".length());
int connectorCount = 0;
}
final String name = String.valueOf(openDevice) + SIM_DEVICE_SUFFIX;
- final String configContent = String.format(middleBlueprint, name, String.valueOf(openDevice), String.valueOf(!useSsh));
+ String configContent = String.format(middleBlueprint, name, String.valueOf(openDevice), String.valueOf(!useSsh));
+ configContent = String.format("%s%s%d%s\n%s\n", configContent, "<connection-timeout-millis>", generateConfigsTimeout, "</connection-timeout-millis>", "</module>");
+
b.append(configContent);
connectorCount++;
if(connectorCount == batchSize) {
import io.netty.util.HashedWheelTimer;
import java.io.Closeable;
import java.io.IOException;
-import java.io.InputStream;
import java.io.InputStreamReader;
import java.lang.management.ManagementFactory;
import java.net.Inet4Address;
import org.antlr.v4.runtime.ParserRuleContext;
import org.antlr.v4.runtime.tree.ParseTreeWalker;
import org.opendaylight.controller.netconf.api.monitoring.NetconfManagementSession;
+import org.opendaylight.controller.netconf.api.xml.XmlNetconfConstants;
import org.opendaylight.controller.netconf.impl.DefaultCommitNotificationProducer;
import org.opendaylight.controller.netconf.impl.NetconfServerDispatcher;
import org.opendaylight.controller.netconf.impl.NetconfServerSessionNegotiatorFactory;
this.hashedWheelTimer = hashedWheelTimer;
}
- private NetconfServerDispatcher createDispatcher(final Map<ModuleBuilder, String> moduleBuilders) {
+ private NetconfServerDispatcher createDispatcher(final Map<ModuleBuilder, String> moduleBuilders, final boolean exi) {
final Set<Capability> capabilities = Sets.newHashSet(Collections2.transform(moduleBuilders.keySet(), new Function<ModuleBuilder, Capability>() {
@Override
final DefaultCommitNotificationProducer commitNotifier = new DefaultCommitNotificationProducer(ManagementFactory.getPlatformMBeanServer());
+ final Set<String> serverCapabilities = exi
+ ? NetconfServerSessionNegotiatorFactory.DEFAULT_BASE_CAPABILITIES
+ : Sets.newHashSet(XmlNetconfConstants.URN_IETF_PARAMS_NETCONF_BASE_1_0, XmlNetconfConstants.URN_IETF_PARAMS_NETCONF_BASE_1_1);
+
final NetconfServerSessionNegotiatorFactory serverNegotiatorFactory = new NetconfServerSessionNegotiatorFactory(
- hashedWheelTimer, simulatedOperationProvider, idProvider, CONNECTION_TIMEOUT_MILLIS, commitNotifier, new LoggingMonitoringService());
+ hashedWheelTimer, simulatedOperationProvider, idProvider, CONNECTION_TIMEOUT_MILLIS, commitNotifier, new LoggingMonitoringService(), serverCapabilities);
final NetconfServerDispatcher.ServerChannelInitializer serverChannelInitializer = new NetconfServerDispatcher.ServerChannelInitializer(
serverNegotiatorFactory);
public List<Integer> start(final Main.Params params) {
final Map<ModuleBuilder, String> moduleBuilders = parseSchemasToModuleBuilders(params);
- final NetconfServerDispatcher dispatcher = createDispatcher(moduleBuilders);
+ final NetconfServerDispatcher dispatcher = createDispatcher(moduleBuilders, params.exi);
int currentPort = params.startingPort;