From 19ec3dcf73b675ff204bb222ca909447ebcd3d21 Mon Sep 17 00:00:00 2001 From: Maros Marsalek Date: Mon, 19 May 2014 11:10:14 +0200 Subject: [PATCH] BUG-1018 Implement BackwardsCompatible BI broker data notifications Finish support for notifying BI data change listeners in backwards compatible broker. Change-Id: I221a1e6937c8f9c493444afd0756e6c23fd4b18f Signed-off-by: Maros Marsalek --- .../compat/BackwardsCompatibleDataBroker.java | 59 ++--- .../compat/TranslatingDataChangeEvent.java | 233 ++++++++++++++++++ .../compat/TranslatingListenerInvoker.java | 99 ++++++++ .../netconf/NetconfConnectorModule.java | 6 + 4 files changed, 369 insertions(+), 28 deletions(-) create mode 100644 opendaylight/md-sal/sal-dom-broker/src/main/java/org/opendaylight/controller/md/sal/dom/broker/impl/compat/TranslatingDataChangeEvent.java create mode 100644 opendaylight/md-sal/sal-dom-broker/src/main/java/org/opendaylight/controller/md/sal/dom/broker/impl/compat/TranslatingListenerInvoker.java diff --git a/opendaylight/md-sal/sal-dom-broker/src/main/java/org/opendaylight/controller/md/sal/dom/broker/impl/compat/BackwardsCompatibleDataBroker.java b/opendaylight/md-sal/sal-dom-broker/src/main/java/org/opendaylight/controller/md/sal/dom/broker/impl/compat/BackwardsCompatibleDataBroker.java index b2217a6f0a..5b34fba69a 100644 --- a/opendaylight/md-sal/sal-dom-broker/src/main/java/org/opendaylight/controller/md/sal/dom/broker/impl/compat/BackwardsCompatibleDataBroker.java +++ b/opendaylight/md-sal/sal-dom-broker/src/main/java/org/opendaylight/controller/md/sal/dom/broker/impl/compat/BackwardsCompatibleDataBroker.java @@ -1,36 +1,28 @@ package org.opendaylight.controller.md.sal.dom.broker.impl.compat; import org.opendaylight.controller.md.sal.common.api.RegistrationListener; -import org.opendaylight.controller.md.sal.common.api.data.AsyncDataChangeEvent; -import org.opendaylight.controller.md.sal.common.api.data.DataChangeEvent; import org.opendaylight.controller.md.sal.common.api.data.DataCommitHandler; import org.opendaylight.controller.md.sal.common.api.data.DataCommitHandlerRegistration; import org.opendaylight.controller.md.sal.common.api.data.DataReader; import org.opendaylight.controller.md.sal.common.impl.util.compat.DataNormalizer; import org.opendaylight.controller.md.sal.dom.api.DOMDataBroker; -import org.opendaylight.controller.md.sal.dom.api.DOMDataChangeListener; import org.opendaylight.controller.sal.common.DataStoreIdentifier; import org.opendaylight.controller.sal.core.api.data.DataChangeListener; import org.opendaylight.controller.sal.core.api.data.DataModificationTransaction; import org.opendaylight.controller.sal.core.api.data.DataProviderService; import org.opendaylight.controller.sal.core.api.data.DataValidator; import org.opendaylight.yangtools.concepts.AbstractObjectRegistration; -import org.opendaylight.yangtools.concepts.Delegator; import org.opendaylight.yangtools.concepts.ListenerRegistration; import org.opendaylight.yangtools.concepts.Registration; -import org.opendaylight.yangtools.concepts.util.ListenerRegistry; import org.opendaylight.yangtools.yang.data.api.CompositeNode; import org.opendaylight.yangtools.yang.data.api.InstanceIdentifier; -import org.opendaylight.yangtools.yang.data.api.schema.NormalizedNode; import org.opendaylight.yangtools.yang.model.api.SchemaContext; import org.opendaylight.yangtools.yang.model.api.SchemaContextListener; public class BackwardsCompatibleDataBroker implements DataProviderService, SchemaContextListener { - DOMDataBroker backingBroker; - DataNormalizer normalizer; - private final ListenerRegistry fakeRegistry = ListenerRegistry.create(); - + private final DOMDataBroker backingBroker; + private DataNormalizer normalizer; public BackwardsCompatibleDataBroker(final DOMDataBroker newBiDataImpl) { backingBroker = newBiDataImpl; @@ -43,7 +35,7 @@ public class BackwardsCompatibleDataBroker implements DataProviderService, Schem @Override public CompositeNode readConfigurationData(final InstanceIdentifier legacyPath) { - BackwardsCompatibleTransaction tx = BackwardsCompatibleTransaction.readOnlyTransaction(backingBroker.newReadOnlyTransaction(),normalizer); + final BackwardsCompatibleTransaction tx = BackwardsCompatibleTransaction.readOnlyTransaction(backingBroker.newReadOnlyTransaction(),normalizer); try { return tx.readConfigurationData(legacyPath); } finally { @@ -53,7 +45,7 @@ public class BackwardsCompatibleDataBroker implements DataProviderService, Schem @Override public CompositeNode readOperationalData(final InstanceIdentifier legacyPath) { - BackwardsCompatibleTransaction tx = BackwardsCompatibleTransaction.readOnlyTransaction(backingBroker.newReadOnlyTransaction(),normalizer); + final BackwardsCompatibleTransaction tx = BackwardsCompatibleTransaction.readOnlyTransaction(backingBroker.newReadOnlyTransaction(),normalizer); try { return tx.readOperationalData(legacyPath); } finally { @@ -67,9 +59,19 @@ public class BackwardsCompatibleDataBroker implements DataProviderService, Schem } @Override - public ListenerRegistration registerDataChangeListener(final InstanceIdentifier path, + public ListenerRegistration registerDataChangeListener(final InstanceIdentifier legacyPath, final DataChangeListener listener) { - return fakeRegistry .register(listener); + final InstanceIdentifier normalizedPath = normalizer.toNormalized(legacyPath); + + final TranslatingListenerInvoker translatingCfgListener = + TranslatingListenerInvoker.createConfig(listener, normalizer); + translatingCfgListener.register(backingBroker, normalizedPath); + + final TranslatingListenerInvoker translatingOpListener = + TranslatingListenerInvoker.createOperational(listener, normalizer); + translatingOpListener.register(backingBroker, normalizedPath); + + return new DelegateListenerRegistration(translatingCfgListener, translatingOpListener, listener); } @Override @@ -90,7 +92,7 @@ public class BackwardsCompatibleDataBroker implements DataProviderService, Schem return null; } - // Obsolote functionality + // Obsolete functionality @Override public void addValidator(final DataStoreIdentifier store, final DataValidator validator) { @@ -124,25 +126,26 @@ public class BackwardsCompatibleDataBroker implements DataProviderService, Schem throw new UnsupportedOperationException("Data Reader contract is not supported."); } - private final class TranslatingListenerInvoker implements DOMDataChangeListener, Delegator { - + private static class DelegateListenerRegistration implements ListenerRegistration { + private final TranslatingListenerInvoker translatingCfgListener; + private final TranslatingListenerInvoker translatingOpListener; + private final DataChangeListener listener; - private DataChangeListener delegate; + public DelegateListenerRegistration(final TranslatingListenerInvoker translatingCfgListener, final TranslatingListenerInvoker translatingOpListener, final DataChangeListener listener) { + this.translatingCfgListener = translatingCfgListener; + this.translatingOpListener = translatingOpListener; + this.listener = listener; + } @Override - public void onDataChanged(final AsyncDataChangeEvent> normalizedChange) { - - DataChangeEvent legacyChange = null; - delegate.onDataChanged(legacyChange); + public void close() { + translatingCfgListener.close(); + translatingOpListener.close(); } @Override - public DataChangeListener getDelegate() { - - return delegate; + public DataChangeListener getInstance() { + return listener; } - - } - } diff --git a/opendaylight/md-sal/sal-dom-broker/src/main/java/org/opendaylight/controller/md/sal/dom/broker/impl/compat/TranslatingDataChangeEvent.java b/opendaylight/md-sal/sal-dom-broker/src/main/java/org/opendaylight/controller/md/sal/dom/broker/impl/compat/TranslatingDataChangeEvent.java new file mode 100644 index 0000000000..827e4ca63d --- /dev/null +++ b/opendaylight/md-sal/sal-dom-broker/src/main/java/org/opendaylight/controller/md/sal/dom/broker/impl/compat/TranslatingDataChangeEvent.java @@ -0,0 +1,233 @@ +/* + * Copyright (c) 2014 Cisco Systems, Inc. and others. All rights reserved. + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License v1.0 which accompanies this distribution, + * and is available at http://www.eclipse.org/legal/epl-v10.html + */ +package org.opendaylight.controller.md.sal.dom.broker.impl.compat; + +import java.util.Collections; +import java.util.HashMap; +import java.util.Map; +import java.util.Set; + +import org.opendaylight.controller.md.sal.common.api.data.AsyncDataChangeEvent; +import org.opendaylight.controller.md.sal.common.api.data.DataChangeEvent; +import org.opendaylight.controller.md.sal.common.impl.util.compat.DataNormalizationException; +import org.opendaylight.controller.md.sal.common.impl.util.compat.DataNormalizer; +import org.opendaylight.yangtools.yang.data.api.CompositeNode; +import org.opendaylight.yangtools.yang.data.api.InstanceIdentifier; +import org.opendaylight.yangtools.yang.data.api.schema.NormalizedNode; + +import com.google.common.collect.Maps; + +public abstract class TranslatingDataChangeEvent implements + DataChangeEvent { + + private TranslatingDataChangeEvent() { + } + + public static DataChangeEvent createOperational( + final AsyncDataChangeEvent> change, final DataNormalizer normalizer) { + return new OperationalChangeEvent(change, normalizer); + } + + public static DataChangeEvent createConfiguration( + final AsyncDataChangeEvent> change, final DataNormalizer normalizer) { + return new ConfigurationChangeEvent(change, normalizer); + } + + @Override + public Map getCreatedOperationalData() { + return Collections.emptyMap(); + } + + @Override + public Map getCreatedConfigurationData() { + return Collections.emptyMap(); + } + + @Override + public Map getUpdatedOperationalData() { + return Collections.emptyMap(); + } + + @Override + public Map getUpdatedConfigurationData() { + return Collections.emptyMap(); + } + + @Override + public Set getRemovedConfigurationData() { + return Collections.emptySet(); + } + + @Override + public Set getRemovedOperationalData() { + return Collections.emptySet(); + } + + @Override + public Map getOriginalConfigurationData() { + return Collections.emptyMap(); + } + + @Override + public Map getOriginalOperationalData() { + return Collections.emptyMap(); + } + + @Override + public CompositeNode getOriginalConfigurationSubtree() { + return null; + } + + @Override + public CompositeNode getOriginalOperationalSubtree() { + return null; + } + + @Override + public CompositeNode getUpdatedConfigurationSubtree() { + return null; + } + + @Override + public CompositeNode getUpdatedOperationalSubtree() { + return null; + } + + @SuppressWarnings({ "rawtypes", "unchecked" }) + private final static class OperationalChangeEvent extends TranslatingDataChangeEvent { + + private final AsyncDataChangeEvent> delegate; + private final DataNormalizer normalizer; + private Map updatedCache; + + public OperationalChangeEvent(final AsyncDataChangeEvent> change, + final DataNormalizer normalizer) { + this.delegate = change; + this.normalizer = normalizer; + } + + @Override + public Map getCreatedOperationalData() { + return transformToLegacy(normalizer, delegate.getCreatedData()); + } + + + @Override + public Set getRemovedOperationalData() { + return delegate.getRemovedPaths(); + } + + @Override + public CompositeNode getOriginalOperationalSubtree() { + // first argument is unused + return normalizer.toLegacy(null, delegate.getOriginalSubtree()); + } + + @Override + public CompositeNode getUpdatedOperationalSubtree() { + // first argument is unused + return normalizer.toLegacy(null, delegate.getUpdatedSubtree()); + } + + @Override + public Map getOriginalOperationalData() { + return transformToLegacy(normalizer, delegate.getOriginalData()); + } + + @Override + public Map getUpdatedOperationalData() { + if(updatedCache == null) { + final Map updated = transformToLegacy(normalizer, delegate.getUpdatedData()); + final Map created = getCreatedConfigurationData(); + final HashMap updatedComposite = new HashMap<>(created.size() + updated.size()); + updatedComposite.putAll(created); + updatedComposite.putAll(updated); + updatedCache = Collections.unmodifiableMap(updatedComposite); + } + return updatedCache; + } + + @Override + public String toString() { + return "OperationalChangeEvent [delegate=" + delegate + "]"; + } + + } + + private static Map transformToLegacy(final DataNormalizer normalizer, final Map> nodes) { + final Map legacy = Maps.newHashMap(); + + for (final Map.Entry> entry : nodes.entrySet()) { + try { + legacy.put(normalizer.toLegacy(entry.getKey()), normalizer.toLegacy(entry.getKey(), entry.getValue())); + } catch (final DataNormalizationException e) { + throw new IllegalStateException("Unable to transform data change event to legacy format", e); + } + } + return legacy; + } + + private final static class ConfigurationChangeEvent extends TranslatingDataChangeEvent { + + private final AsyncDataChangeEvent> delegate; + private final DataNormalizer normalizer; + private Map updatedCache; + + public ConfigurationChangeEvent(final AsyncDataChangeEvent> change, + final DataNormalizer normalizer) { + this.delegate = change; + this.normalizer = normalizer; + } + + @Override + public Map getCreatedConfigurationData() { + return transformToLegacy(normalizer, delegate.getCreatedData()); + } + + + @Override + public Set getRemovedConfigurationData() { + return delegate.getRemovedPaths(); + } + + @Override + public CompositeNode getOriginalConfigurationSubtree() { + // first argument is unused + return normalizer.toLegacy(null, delegate.getOriginalSubtree()); + } + + @Override + public CompositeNode getUpdatedConfigurationSubtree() { + // first argument is unused + return normalizer.toLegacy(null, delegate.getUpdatedSubtree()); + } + + @Override + public Map getOriginalConfigurationData() { + return transformToLegacy(normalizer, delegate.getOriginalData()); + } + + @Override + public Map getUpdatedConfigurationData() { + if(updatedCache == null) { + final Map updated = transformToLegacy(normalizer, delegate.getUpdatedData()); + final Map created = getCreatedConfigurationData(); + final HashMap updatedComposite = new HashMap<>(created.size() + updated.size()); + updatedComposite.putAll(created); + updatedComposite.putAll(updated); + updatedCache = Collections.unmodifiableMap(updatedComposite); + } + return updatedCache; + } + + @Override + public String toString() { + return "ConfigurationChangeEvent [delegate=" + delegate + "]"; + } + } +} diff --git a/opendaylight/md-sal/sal-dom-broker/src/main/java/org/opendaylight/controller/md/sal/dom/broker/impl/compat/TranslatingListenerInvoker.java b/opendaylight/md-sal/sal-dom-broker/src/main/java/org/opendaylight/controller/md/sal/dom/broker/impl/compat/TranslatingListenerInvoker.java new file mode 100644 index 0000000000..1ce252df98 --- /dev/null +++ b/opendaylight/md-sal/sal-dom-broker/src/main/java/org/opendaylight/controller/md/sal/dom/broker/impl/compat/TranslatingListenerInvoker.java @@ -0,0 +1,99 @@ +/* + * Copyright (c) 2014 Cisco Systems, Inc. and others. All rights reserved. + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License v1.0 which accompanies this distribution, + * and is available at http://www.eclipse.org/legal/epl-v10.html + */ +package org.opendaylight.controller.md.sal.dom.broker.impl.compat; + +import org.opendaylight.controller.md.sal.common.api.data.AsyncDataBroker; +import org.opendaylight.controller.md.sal.common.api.data.AsyncDataChangeEvent; +import org.opendaylight.controller.md.sal.common.api.data.DataChangeEvent; +import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType; +import org.opendaylight.controller.md.sal.common.impl.util.compat.DataNormalizer; +import org.opendaylight.controller.md.sal.dom.api.DOMDataBroker; +import org.opendaylight.controller.md.sal.dom.api.DOMDataChangeListener; +import org.opendaylight.controller.sal.core.api.data.DataChangeListener; +import org.opendaylight.yangtools.concepts.Delegator; +import org.opendaylight.yangtools.concepts.ListenerRegistration; +import org.opendaylight.yangtools.yang.data.api.CompositeNode; +import org.opendaylight.yangtools.yang.data.api.InstanceIdentifier; +import org.opendaylight.yangtools.yang.data.api.schema.NormalizedNode; + +abstract class TranslatingListenerInvoker implements AutoCloseable, DOMDataChangeListener, Delegator { + + private final DataChangeListener delegate; + private final DataNormalizer normalizer; + protected ListenerRegistration reg; + + protected TranslatingListenerInvoker(final DataChangeListener listener, final DataNormalizer normalizer) { + this.delegate = listener; + this.normalizer = normalizer; + } + + static TranslatingListenerInvoker createConfig(final DataChangeListener listener, final DataNormalizer normalizer) { + return new TranslatingConfigListenerInvoker(listener, normalizer); + } + + static TranslatingListenerInvoker createOperational(final DataChangeListener listener, final DataNormalizer normalizer) { + return new TranslatingOperationalListenerInvoker(listener, normalizer); + } + + @Override + public void onDataChanged(final AsyncDataChangeEvent> normalizedChange) { + delegate.onDataChanged(getLegacyEvent(normalizer, normalizedChange)); + } + + abstract DataChangeEvent getLegacyEvent(final DataNormalizer normalizer, + final AsyncDataChangeEvent> normalizedChange); + + @Override + public DataChangeListener getDelegate() { + return delegate; + } + + abstract void register(final DOMDataBroker backingBroker, final InstanceIdentifier normalizedPath); + + @Override + public void close() { + if (reg != null) { + reg.close(); + } + } + + static final class TranslatingConfigListenerInvoker extends TranslatingListenerInvoker { + + public TranslatingConfigListenerInvoker(final DataChangeListener listener, final DataNormalizer normalizer) { + super(listener, normalizer); + } + + DataChangeEvent getLegacyEvent(final DataNormalizer normalizer, final AsyncDataChangeEvent> normalizedChange) { + return TranslatingDataChangeEvent.createConfiguration(normalizedChange, normalizer); + } + + @Override + void register(final DOMDataBroker backingBroker, final InstanceIdentifier normalizedPath) { + reg = backingBroker.registerDataChangeListener(LogicalDatastoreType.CONFIGURATION, normalizedPath, this, + AsyncDataBroker.DataChangeScope.SUBTREE); + } + } + + static final class TranslatingOperationalListenerInvoker extends TranslatingListenerInvoker { + + public TranslatingOperationalListenerInvoker(final DataChangeListener listener, final DataNormalizer normalizer) { + super(listener, normalizer); + } + + DataChangeEvent getLegacyEvent(final DataNormalizer normalizer, final AsyncDataChangeEvent> normalizedChange) { + return TranslatingDataChangeEvent.createOperational(normalizedChange, normalizer); + } + + @Override + void register(final DOMDataBroker backingBroker, final InstanceIdentifier normalizedPath) { + reg = backingBroker.registerDataChangeListener(LogicalDatastoreType.OPERATIONAL, normalizedPath, this, + AsyncDataBroker.DataChangeScope.SUBTREE); + } + } + +} diff --git a/opendaylight/md-sal/sal-netconf-connector/src/main/java/org/opendaylight/controller/config/yang/md/sal/connector/netconf/NetconfConnectorModule.java b/opendaylight/md-sal/sal-netconf-connector/src/main/java/org/opendaylight/controller/config/yang/md/sal/connector/netconf/NetconfConnectorModule.java index de3c18db69..feeab1a4b7 100644 --- a/opendaylight/md-sal/sal-netconf-connector/src/main/java/org/opendaylight/controller/config/yang/md/sal/connector/netconf/NetconfConnectorModule.java +++ b/opendaylight/md-sal/sal-netconf-connector/src/main/java/org/opendaylight/controller/config/yang/md/sal/connector/netconf/NetconfConnectorModule.java @@ -17,8 +17,10 @@ import java.io.File; import java.io.InputStream; import java.net.InetAddress; import java.net.InetSocketAddress; +import java.net.URI; import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; +import org.opendaylight.controller.md.sal.common.api.data.DataChangeEvent; import org.opendaylight.controller.netconf.client.NetconfClientDispatcher; import org.opendaylight.controller.netconf.client.NetconfClientDispatcherImpl; import org.opendaylight.controller.netconf.client.conf.NetconfClientConfiguration; @@ -27,8 +29,10 @@ import org.opendaylight.controller.netconf.client.conf.NetconfReconnectingClient import org.opendaylight.controller.netconf.client.conf.NetconfReconnectingClientConfigurationBuilder; import org.opendaylight.controller.netconf.util.handler.ssh.authentication.LoginPassword; import org.opendaylight.controller.sal.binding.api.data.DataProviderService; +import org.opendaylight.controller.sal.connect.netconf.InventoryUtils; import org.opendaylight.controller.sal.connect.netconf.NetconfDevice; import org.opendaylight.controller.sal.connect.netconf.NetconfDeviceListener; +import org.opendaylight.controller.sal.core.api.data.DataChangeListener; import org.opendaylight.protocol.framework.ReconnectStrategy; import org.opendaylight.protocol.framework.ReconnectStrategyFactory; import org.opendaylight.protocol.framework.TimedReconnectStrategy; @@ -36,6 +40,8 @@ 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.netconf.node.inventory.rev140108.NetconfNode; import org.opendaylight.yangtools.yang.binding.InstanceIdentifier; +import org.opendaylight.yangtools.yang.common.QName; +import org.opendaylight.yangtools.yang.data.api.CompositeNode; import org.opendaylight.yangtools.yang.model.util.repo.AbstractCachingSchemaSourceProvider; import org.opendaylight.yangtools.yang.model.util.repo.FilesystemSchemaCachingProvider; import org.opendaylight.yangtools.yang.model.util.repo.SchemaSourceProvider; -- 2.36.6