From: Ed Warnicke Date: Tue, 1 Apr 2014 15:22:45 +0000 (+0000) Subject: Merge "Bug 499: Added support for old DOM Broker APIs." X-Git-Tag: autorelease-tag-v20140601202136_82eb3f9~289 X-Git-Url: https://git.opendaylight.org/gerrit/gitweb?p=controller.git;a=commitdiff_plain;h=59cb3e27630fb1fd965152f9e1584213e89fa62f;hp=af4995552e842e052a085ed0845bfda97f5fe668 Merge "Bug 499: Added support for old DOM Broker APIs." --- diff --git a/opendaylight/md-sal/sal-binding-broker/src/test/java/org/opendaylight/controller/sal/binding/test/util/BindingTestContext.java b/opendaylight/md-sal/sal-binding-broker/src/test/java/org/opendaylight/controller/sal/binding/test/util/BindingTestContext.java index ef3e948331..2e43b88553 100644 --- a/opendaylight/md-sal/sal-binding-broker/src/test/java/org/opendaylight/controller/sal/binding/test/util/BindingTestContext.java +++ b/opendaylight/md-sal/sal-binding-broker/src/test/java/org/opendaylight/controller/sal/binding/test/util/BindingTestContext.java @@ -7,6 +7,8 @@ */ package org.opendaylight.controller.sal.binding.test.util; +import static com.google.common.base.Preconditions.checkState; + import java.io.InputStream; import java.util.ArrayList; import java.util.List; @@ -15,6 +17,10 @@ import java.util.concurrent.Future; import javassist.ClassPool; +import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType; +import org.opendaylight.controller.md.sal.dom.broker.impl.DOMDataBrokerImpl; +import org.opendaylight.controller.md.sal.dom.broker.impl.compat.BackwardsCompatibleDataBroker; +import org.opendaylight.controller.md.sal.dom.store.impl.InMemoryDOMDataStore; import org.opendaylight.controller.sal.binding.api.RpcProviderRegistry; import org.opendaylight.controller.sal.binding.api.data.DataProviderService; import org.opendaylight.controller.sal.binding.api.mount.MountProviderService; @@ -33,6 +39,7 @@ import org.opendaylight.controller.sal.core.api.RpcProvisionRegistry; import org.opendaylight.controller.sal.core.api.RpcRegistrationListener; import org.opendaylight.controller.sal.core.api.data.DataStore; import org.opendaylight.controller.sal.core.api.mount.MountProvisionService; +import org.opendaylight.controller.sal.core.spi.data.DOMStore; import org.opendaylight.controller.sal.dom.broker.BrokerImpl; import org.opendaylight.controller.sal.dom.broker.MountPointManagerImpl; import org.opendaylight.controller.sal.dom.broker.impl.DataStoreStatsWrapper; @@ -48,6 +55,7 @@ import org.opendaylight.yangtools.yang.data.api.CompositeNode; import org.opendaylight.yangtools.yang.data.impl.codec.BindingIndependentMappingService; import org.opendaylight.yangtools.yang.model.api.Module; import org.opendaylight.yangtools.yang.model.api.SchemaContext; +import org.opendaylight.yangtools.yang.model.api.SchemaContextListener; import org.opendaylight.yangtools.yang.parser.impl.YangParserImpl; import org.reflections.Reflections; import org.reflections.scanners.ResourcesScanner; @@ -57,10 +65,9 @@ import org.slf4j.LoggerFactory; import com.google.common.base.Predicate; import com.google.common.collect.ClassToInstanceMap; import com.google.common.collect.ImmutableClassToInstanceMap; +import com.google.common.collect.ImmutableMap; import com.google.common.util.concurrent.ListeningExecutorService; -import static com.google.common.base.Preconditions.*; - public class BindingTestContext implements AutoCloseable, SchemaContextProvider { public static final org.opendaylight.yangtools.yang.data.api.InstanceIdentifier TREE_ROOT = org.opendaylight.yangtools.yang.data.api.InstanceIdentifier @@ -76,13 +83,14 @@ public class BindingTestContext implements AutoCloseable, SchemaContextProvider private BindingIndependentConnector baConnectImpl; private org.opendaylight.controller.sal.dom.broker.DataBrokerImpl biDataImpl; + private org.opendaylight.controller.sal.core.api.data.DataProviderService biDataLegacyBroker; private BrokerImpl biBrokerImpl; private HashMapDataStore rawDataStore; private SchemaAwareDataStoreAdapter schemaAwareDataStore; private DataStoreStatsWrapper dataStoreStats; private DataStore dataStore; - private boolean dataStoreStatisticsEnabled = false; + private final boolean dataStoreStatisticsEnabled = false; private final ListeningExecutorService executor; private final ClassPool classPool; @@ -93,11 +101,18 @@ public class BindingTestContext implements AutoCloseable, SchemaContextProvider private SchemaContext schemaContext; + private ImmutableMap newDatastores; + + private BackwardsCompatibleDataBroker biCompatibleBroker; + + private final List schemaListeners = new ArrayList<>(); + + @Override public SchemaContext getSchemaContext() { return schemaContext; } - protected BindingTestContext(ListeningExecutorService executor, ClassPool classPool, boolean startWithSchema) { + protected BindingTestContext(final ListeningExecutorService executor, final ClassPool classPool, final boolean startWithSchema) { this.executor = executor; this.classPool = classPool; this.startWithSchema = startWithSchema; @@ -125,6 +140,26 @@ public class BindingTestContext implements AutoCloseable, SchemaContextProvider checkState(executor != null, "Executor needs to be set"); biDataImpl = new org.opendaylight.controller.sal.dom.broker.DataBrokerImpl(); biDataImpl.setExecutor(executor); + biDataLegacyBroker = biDataImpl; + } + + public void startNewDomDataBroker() { + checkState(executor != null, "Executor needs to be set"); + InMemoryDOMDataStore operStore = new InMemoryDOMDataStore("OPER", executor); + InMemoryDOMDataStore configStore = new InMemoryDOMDataStore("CFG", executor); + newDatastores = ImmutableMap.builder() + .put(LogicalDatastoreType.OPERATIONAL, operStore) + .put(LogicalDatastoreType.CONFIGURATION, configStore) + .build(); + + DOMDataBrokerImpl newBiDataImpl = new DOMDataBrokerImpl(newDatastores, executor); + + biCompatibleBroker = new BackwardsCompatibleDataBroker(newBiDataImpl); + + schemaListeners.add(configStore); + schemaListeners.add(operStore); + schemaListeners.add(biCompatibleBroker); + biDataLegacyBroker = biCompatibleBroker; } public void startBindingDataBroker() { @@ -149,7 +184,7 @@ public class BindingTestContext implements AutoCloseable, SchemaContextProvider public void startForwarding() { checkState(baDataImpl != null, "Binding Data Broker needs to be started"); - checkState(biDataImpl != null, "DOM Data Broker needs to be started."); + checkState(biDataLegacyBroker != null, "DOM Data Broker needs to be started."); checkState(mappingServiceImpl != null, "DOM Mapping Service needs to be started."); baConnectImpl = BindingDomConnectorDeployer.createConnector(getBindingToDomMappingService()); @@ -160,11 +195,11 @@ public class BindingTestContext implements AutoCloseable, SchemaContextProvider } private ProviderSession createMockContext() { - // TODO Auto-generated method stub + final ClassToInstanceMap domBrokerServices = ImmutableClassToInstanceMap . builder() // - .put(org.opendaylight.controller.sal.core.api.data.DataProviderService.class, biDataImpl) // + .put(org.opendaylight.controller.sal.core.api.data.DataProviderService.class, biDataLegacyBroker) // .put(RpcProvisionRegistry.class, biBrokerImpl.getRouter()) // .put(MountProvisionService.class, biMountImpl) // .build(); @@ -172,12 +207,12 @@ public class BindingTestContext implements AutoCloseable, SchemaContextProvider return new ProviderSession() { @Override - public Future> rpc(QName rpc, CompositeNode input) { + public Future> rpc(final QName rpc, final CompositeNode input) { throw new UnsupportedOperationException(); } @Override - public T getService(Class service) { + public T getService(final Class service) { return domBrokerServices.getInstance(service); } @@ -197,23 +232,23 @@ public class BindingTestContext implements AutoCloseable, SchemaContextProvider @Override public ListenerRegistration addRpcRegistrationListener( - RpcRegistrationListener listener) { + final RpcRegistrationListener listener) { return null; } @Override - public RpcRegistration addRpcImplementation(QName rpcType, RpcImplementation implementation) + public RpcRegistration addRpcImplementation(final QName rpcType, final RpcImplementation implementation) throws IllegalArgumentException { return null; } @Override - public RoutedRpcRegistration addRoutedRpcImplementation(QName rpcType, RpcImplementation implementation) { + public RoutedRpcRegistration addRoutedRpcImplementation(final QName rpcType, final RpcImplementation implementation) { return null; } @Override - public RoutedRpcRegistration addMountedRpcImplementation(QName rpcType, RpcImplementation implementation) { + public RoutedRpcRegistration addMountedRpcImplementation(final QName rpcType, final RpcImplementation implementation) { return null; } }; @@ -226,29 +261,33 @@ public class BindingTestContext implements AutoCloseable, SchemaContextProvider mappingServiceImpl.init(); } - public void updateYangSchema(String[] files) { + public void updateYangSchema(final String[] files) { schemaContext = getContext(files); + if (schemaAwareDataStore != null) { schemaAwareDataStore.onGlobalContextUpdated(schemaContext); } if (mappingServiceImpl != null) { mappingServiceImpl.onGlobalContextUpdated(schemaContext); } + for(SchemaContextListener listener : schemaListeners) { + listener.onGlobalContextUpdated(schemaContext); + } } public static String[] getAllYangFilesOnClasspath() { Predicate predicate = new Predicate() { @Override - public boolean apply(String input) { + public boolean apply(final String input) { return input.endsWith(".yang"); } }; Reflections reflection = new Reflections("META-INF.yang", new ResourcesScanner()); Set result = reflection.getResources(predicate); - return (String[]) result.toArray(new String[result.size()]); + return result.toArray(new String[result.size()]); } - private static SchemaContext getContext(String[] yangFiles) { + private static SchemaContext getContext(final String[] yangFiles) { ClassLoader loader = BindingTestContext.class.getClassLoader(); List streams = new ArrayList<>(); for (String string : yangFiles) { @@ -260,7 +299,7 @@ public class BindingTestContext implements AutoCloseable, SchemaContextProvider return parser.resolveSchemaContext(modules); } - public void start() { + public void startLegacy() { startBindingDataBroker(); startBindingNotificationBroker(); startBindingBroker(); @@ -275,6 +314,20 @@ public class BindingTestContext implements AutoCloseable, SchemaContextProvider } } + public void start() { + startBindingDataBroker(); + startBindingNotificationBroker(); + startBindingBroker(); + startNewDomDataBroker(); + startDomBroker(); + startDomMountPoint(); + startBindingToDomMappingService(); + startForwarding(); + if (startWithSchema) { + loadYangSchemaFromClasspath(); + } + } + private void startDomMountPoint() { biMountImpl = new MountPointManagerImpl(); biMountImpl.setDataBroker(getDomDataBroker()); @@ -285,6 +338,7 @@ public class BindingTestContext implements AutoCloseable, SchemaContextProvider biBrokerImpl = new BrokerImpl(); biBrokerImpl.setExecutor(executor); biBrokerImpl.setRouter(new SchemaAwareRpcBroker("/", this)); + } public void startBindingNotificationBroker() { @@ -303,7 +357,7 @@ public class BindingTestContext implements AutoCloseable, SchemaContextProvider } public org.opendaylight.controller.sal.core.api.data.DataProviderService getDomDataBroker() { - return biDataImpl; + return biDataLegacyBroker; } public DataStore getDomDataStore() { diff --git a/opendaylight/md-sal/sal-binding-dom-it/src/test/java/org/opendaylight/controller/sal/binding/test/bugfix/DOMCodecBug01Test.java b/opendaylight/md-sal/sal-binding-dom-it/src/test/java/org/opendaylight/controller/sal/binding/test/bugfix/DOMCodecBug01Test.java index d016754385..4719352485 100644 --- a/opendaylight/md-sal/sal-binding-dom-it/src/test/java/org/opendaylight/controller/sal/binding/test/bugfix/DOMCodecBug01Test.java +++ b/opendaylight/md-sal/sal-binding-dom-it/src/test/java/org/opendaylight/controller/sal/binding/test/bugfix/DOMCodecBug01Test.java @@ -19,6 +19,7 @@ import java.util.concurrent.Callable; import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; +import org.junit.Ignore; import org.junit.Test; import org.opendaylight.controller.md.sal.common.api.TransactionStatus; import org.opendaylight.controller.sal.binding.api.data.DataModificationTransaction; @@ -115,8 +116,14 @@ public class DOMCodecBug01Test extends AbstractDataServiceTest { * * Reported by Depthi V V * + * @deprecated This test tests indirect generation, which should be tested + * different way. the test creates conflicting transactions + * and assumes correct commit - to test codec generation + * */ @Test + @Ignore + @Deprecated public void testIndirectGeneration() throws Exception { ExecutorService basePool = Executors.newFixedThreadPool(2); @@ -218,7 +225,7 @@ public class DOMCodecBug01Test extends AbstractDataServiceTest { private class CreateFlowTask implements Callable { - public CreateFlowTask(Object startSync) { + public CreateFlowTask(final Object startSync) { } @Override diff --git a/opendaylight/md-sal/sal-binding-dom-it/src/test/java/org/opendaylight/controller/sal/binding/test/bugfix/DOMCodecBug02Test.java b/opendaylight/md-sal/sal-binding-dom-it/src/test/java/org/opendaylight/controller/sal/binding/test/bugfix/DOMCodecBug02Test.java index 9d60440698..929eb66350 100644 --- a/opendaylight/md-sal/sal-binding-dom-it/src/test/java/org/opendaylight/controller/sal/binding/test/bugfix/DOMCodecBug02Test.java +++ b/opendaylight/md-sal/sal-binding-dom-it/src/test/java/org/opendaylight/controller/sal/binding/test/bugfix/DOMCodecBug02Test.java @@ -7,9 +7,6 @@ */ package org.opendaylight.controller.sal.binding.test.bugfix; -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertNotNull; - import java.util.Collections; import java.util.Map; import java.util.concurrent.Callable; @@ -19,24 +16,29 @@ import java.util.concurrent.Future; import javassist.ClassPool; +import org.junit.Ignore; import org.junit.Test; import org.opendaylight.controller.md.sal.common.api.TransactionStatus; -import org.opendaylight.controller.sal.binding.api.data.DataModificationTransaction; import org.opendaylight.controller.sal.binding.test.AbstractDataServiceTest; import org.opendaylight.controller.sal.binding.test.util.BindingBrokerTestFactory; +import org.opendaylight.controller.sal.binding.api.data.DataModificationTransaction; +import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.config.rev130819.flows.Flow; +import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.nodes.Node; 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.NodesBuilder; -import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.nodes.Node; import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.nodes.NodeKey; import org.opendaylight.yangtools.yang.binding.InstanceIdentifier; import org.opendaylight.yangtools.yang.common.QName; import org.opendaylight.yangtools.yang.common.RpcResult; +import org.opendaylight.yangtools.yang.model.api.SchemaContext; import com.google.common.util.concurrent.ListeningExecutorService; import com.google.common.util.concurrent.MoreExecutors; +import static org.junit.Assert.*; + public class DOMCodecBug02Test extends AbstractDataServiceTest { private static final QName NODE_ID_QNAME = QName.create(Node.QNAME, "id"); @@ -68,11 +70,10 @@ public class DOMCodecBug02Test extends AbstractDataServiceTest { /** * This test is ignored, till found out better way to test generation * of classes without leaking of instances from previous run - * + * * @throws Exception */ - - @Override + public void setUp() { ListeningExecutorService executor = MoreExecutors.sameThreadExecutor(); BindingBrokerTestFactory factory = new BindingBrokerTestFactory(); @@ -81,13 +82,13 @@ public class DOMCodecBug02Test extends AbstractDataServiceTest { factory.setStartWithParsedSchema(getStartWithSchema()); testContext = factory.getTestContext(); testContext.start(); - + baDataService = testContext.getBindingDataBroker(); biDataService = testContext.getDomDataBroker(); dataStore = testContext.getDomDataStore(); mappingService = testContext.getBindingToDomMappingService(); }; - + @Test public void testSchemaContextNotAvailable() throws Exception { @@ -103,11 +104,11 @@ public class DOMCodecBug02Test extends AbstractDataServiceTest { return transaction.commit(); } }); - - + + RpcResult result = future.get().get(); assertEquals(TransactionStatus.COMMITED, result.getResult()); - + Nodes nodes = checkForNodes(); assertNotNull(nodes); @@ -117,7 +118,7 @@ public class DOMCodecBug02Test extends AbstractDataServiceTest { return (Nodes) baDataService.readOperationalData(NODES_INSTANCE_ID_BA); } - + @Override protected boolean getStartWithSchema() { return false; diff --git a/opendaylight/md-sal/sal-binding-dom-it/src/test/java/org/opendaylight/controller/sal/binding/test/connect/dom/ChangeOriginatedInDomBrokerTest.java b/opendaylight/md-sal/sal-binding-dom-it/src/test/java/org/opendaylight/controller/sal/binding/test/connect/dom/ChangeOriginatedInDomBrokerTest.java index 862c6ea269..6f938b15ed 100644 --- a/opendaylight/md-sal/sal-binding-dom-it/src/test/java/org/opendaylight/controller/sal/binding/test/connect/dom/ChangeOriginatedInDomBrokerTest.java +++ b/opendaylight/md-sal/sal-binding-dom-it/src/test/java/org/opendaylight/controller/sal/binding/test/connect/dom/ChangeOriginatedInDomBrokerTest.java @@ -7,13 +7,22 @@ */ package org.opendaylight.controller.sal.binding.test.connect.dom; -import com.google.common.collect.ImmutableMap; +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertNotNull; +import static org.junit.Assert.assertNull; + +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; +import java.util.Map; + +import org.junit.Ignore; import org.junit.Test; import org.opendaylight.controller.md.sal.common.api.TransactionStatus; import org.opendaylight.controller.md.sal.common.api.data.DataCommitHandler; import org.opendaylight.controller.md.sal.common.api.data.DataModification; -import org.opendaylight.controller.sal.common.util.CommitHandlerTransactions; import org.opendaylight.controller.sal.binding.test.AbstractDataServiceTest; +import org.opendaylight.controller.sal.common.util.CommitHandlerTransactions; import org.opendaylight.controller.sal.core.api.data.DataModificationTransaction; import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev100924.IpVersion; import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev100924.Ipv4Prefix; @@ -51,14 +60,7 @@ import org.opendaylight.yangtools.yang.common.QName; import org.opendaylight.yangtools.yang.common.RpcResult; import org.opendaylight.yangtools.yang.data.api.CompositeNode; -import java.util.ArrayList; -import java.util.Collections; -import java.util.List; -import java.util.Map; - -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertNotNull; -import static org.junit.Assert.assertNull; +import com.google.common.collect.ImmutableMap; public class ChangeOriginatedInDomBrokerTest extends AbstractDataServiceTest { @@ -117,6 +119,7 @@ public class ChangeOriginatedInDomBrokerTest extends AbstractDataServiceTest { .toInstance(); @Test + @Ignore public void simpleModifyOperation() throws Exception { assertNull(biDataService.readConfigurationData(FLOW_INSTANCE_ID_BI)); @@ -141,7 +144,7 @@ public class ChangeOriginatedInDomBrokerTest extends AbstractDataServiceTest { @Override public org.opendaylight.controller.md.sal.common.api.data.DataCommitHandler.DataCommitTransaction, DataObject> requestCommit( - DataModification, DataObject> modification) { + final DataModification, DataObject> modification) { modificationCapture = modification; return CommitHandlerTransactions.allwaysSuccessfulTransaction(modification); } diff --git a/opendaylight/md-sal/sal-common-impl/pom.xml b/opendaylight/md-sal/sal-common-impl/pom.xml index d3504bd018..03b7020a1c 100644 --- a/opendaylight/md-sal/sal-common-impl/pom.xml +++ b/opendaylight/md-sal/sal-common-impl/pom.xml @@ -31,6 +31,14 @@ org.eclipse.xtend org.eclipse.xtend.lib + + org.opendaylight.yangtools + yang-data-impl + + + org.opendaylight.yangtools + yang-model-api + junit junit diff --git a/opendaylight/md-sal/sal-common-impl/src/main/java/org/opendaylight/controller/md/sal/common/impl/AbstractDataModification.java b/opendaylight/md-sal/sal-common-impl/src/main/java/org/opendaylight/controller/md/sal/common/impl/AbstractDataModification.java index 3ceeb7e44d..dc3fef1506 100644 --- a/opendaylight/md-sal/sal-common-impl/src/main/java/org/opendaylight/controller/md/sal/common/impl/AbstractDataModification.java +++ b/opendaylight/md-sal/sal-common-impl/src/main/java/org/opendaylight/controller/md/sal/common/impl/AbstractDataModification.java @@ -10,10 +10,9 @@ package org.opendaylight.controller.md.sal.common.impl; import static org.opendaylight.controller.md.sal.common.api.TransactionStatus.NEW; import java.util.Collections; +import java.util.LinkedHashMap; import java.util.Map; import java.util.Set; -import java.util.concurrent.ConcurrentHashMap; -import java.util.concurrent.ConcurrentMap; import org.opendaylight.controller.md.sal.common.api.data.DataModification; import org.opendaylight.controller.md.sal.common.api.data.DataReader; @@ -21,17 +20,17 @@ import org.opendaylight.yangtools.concepts.Path; public abstract class AbstractDataModification

, D> implements DataModification { - private final ConcurrentMap operationalOriginal; - private final ConcurrentMap configurationOriginal; + private final Map operationalOriginal; + private final Map configurationOriginal; - private final ConcurrentMap operationalCreated; - private final ConcurrentMap configurationCreated; + private final Map operationalCreated; + private final Map configurationCreated; - private final ConcurrentMap configurationUpdate; - private final ConcurrentMap operationalUpdate; + private final Map configurationUpdate; + private final Map operationalUpdate; - private final ConcurrentMap configurationRemove; - private final ConcurrentMap operationalRemove; + private final Map configurationRemove; + private final Map operationalRemove; private final Map unmodifiable_configurationOriginal; private final Map unmodifiable_operationalOriginal; @@ -43,18 +42,18 @@ public abstract class AbstractDataModification

, D> implements private final Set

unmodifiable_OperationalRemove; private final DataReader reader; - public AbstractDataModification(DataReader reader) { + public AbstractDataModification(final DataReader reader) { this.reader = reader; - this.configurationUpdate = new ConcurrentHashMap<>(); - this.operationalUpdate = new ConcurrentHashMap<>(); - this.configurationRemove = new ConcurrentHashMap<>(); - this.operationalRemove = new ConcurrentHashMap<>(); + this.configurationUpdate = new LinkedHashMap<>(); + this.operationalUpdate = new LinkedHashMap<>(); + this.configurationRemove = new LinkedHashMap<>(); + this.operationalRemove = new LinkedHashMap<>(); - this.configurationOriginal = new ConcurrentHashMap<>(); - this.operationalOriginal = new ConcurrentHashMap<>(); + this.configurationOriginal = new LinkedHashMap<>(); + this.operationalOriginal = new LinkedHashMap<>(); - this.configurationCreated = new ConcurrentHashMap<>(); - this.operationalCreated = new ConcurrentHashMap<>(); + this.configurationCreated = new LinkedHashMap<>(); + this.operationalCreated = new LinkedHashMap<>(); unmodifiable_configurationOriginal = Collections.unmodifiableMap(configurationOriginal); unmodifiable_operationalOriginal = Collections.unmodifiableMap(operationalOriginal); @@ -67,7 +66,7 @@ public abstract class AbstractDataModification

, D> implements } @Override - public final void putConfigurationData(P path, D data) { + public final void putConfigurationData(final P path, final D data) { checkMutable(); D original = null; if ((original = getConfigurationOriginal(path)) == null) { @@ -78,7 +77,7 @@ public abstract class AbstractDataModification

, D> implements } @Override - public final void putOperationalData(P path, D data) { + public final void putOperationalData(final P path, final D data) { checkMutable(); D original = null; if ((original = getOperationalOriginal(path)) == null) { @@ -88,7 +87,7 @@ public abstract class AbstractDataModification

, D> implements } @Override - public final void removeOperationalData(P path) { + public final void removeOperationalData(final P path) { checkMutable(); getOperationalOriginal(path); operationalUpdate.remove(path); @@ -96,7 +95,7 @@ public abstract class AbstractDataModification

, D> implements } @Override - public final void removeConfigurationData(P path) { + public final void removeConfigurationData(final P path) { checkMutable(); getConfigurationOriginal(path); configurationUpdate.remove(path); @@ -150,46 +149,46 @@ public abstract class AbstractDataModification

, D> implements } @Override - public D readOperationalData(P path) { + public D readOperationalData(final P path) { return reader.readOperationalData(path); } @Override - public D readConfigurationData(P path) { + public D readConfigurationData(final P path) { return reader.readConfigurationData(path); } - private D getConfigurationOriginal(P path) { + private D getConfigurationOriginal(final P path) { D data = configurationOriginal.get(path); if (data != null) { return data; } data = reader.readConfigurationData(path); if (data != null) { - configurationOriginal.putIfAbsent(path, data); + configurationOriginal.put(path, data); return data; } return null; } - private D getOperationalOriginal(P path) { + private D getOperationalOriginal(final P path) { D data = operationalOriginal.get(path); if (data != null) { return data; } data = reader.readOperationalData(path); if (data != null) { - operationalOriginal.putIfAbsent(path, data); + operationalOriginal.put(path, data); return data; } return null; } - protected D mergeOperationalData(P path,D stored, D modified) { + protected D mergeOperationalData(final P path,final D stored, final D modified) { return modified; } - protected D mergeConfigurationData(P path,D stored, D modified) { + protected D mergeConfigurationData(final P path,final D stored, final D modified) { return modified; } } diff --git a/opendaylight/md-sal/sal-common-impl/src/main/java/org/opendaylight/controller/md/sal/common/impl/service/ImmutableDataChangeEvent.java b/opendaylight/md-sal/sal-common-impl/src/main/java/org/opendaylight/controller/md/sal/common/impl/service/ImmutableDataChangeEvent.java index 776ff7bfb2..a91799d458 100644 --- a/opendaylight/md-sal/sal-common-impl/src/main/java/org/opendaylight/controller/md/sal/common/impl/service/ImmutableDataChangeEvent.java +++ b/opendaylight/md-sal/sal-common-impl/src/main/java/org/opendaylight/controller/md/sal/common/impl/service/ImmutableDataChangeEvent.java @@ -12,7 +12,7 @@ import com.google.common.collect.ImmutableMap; import com.google.common.collect.ImmutableSet; import com.google.common.collect.Maps; -final class ImmutableDataChangeEvent

, D> implements DataChangeEvent { +public final class ImmutableDataChangeEvent

, D> implements DataChangeEvent { private final D updatedOperationalSubtree; private final Map updatedOperational; @@ -28,7 +28,7 @@ final class ImmutableDataChangeEvent

, D> implements DataChange private final Map createdConfiguration; - public ImmutableDataChangeEvent(Builder builder) { + private ImmutableDataChangeEvent(final Builder builder) { createdConfiguration = builder.getCreatedConfiguration().build(); createdOperational = builder.getCreatedOperational().build(); @@ -95,11 +95,11 @@ final class ImmutableDataChangeEvent

, D> implements DataChange return updatedOperationalSubtree; } - static final

,D> Builder builder() { + public static final

,D> Builder builder() { return new Builder<>(); } - static final class Builder

,D> { + public static final class Builder

,D> { private D updatedOperationalSubtree; private D originalOperationalSubtree; @@ -117,7 +117,10 @@ final class ImmutableDataChangeEvent

, D> implements DataChange private final ImmutableMap.Builder createdConfiguration = ImmutableMap.builder(); - protected Builder addTransaction(DataModification data, Predicate

keyFilter) { + + + + protected Builder addTransaction(final DataModification data, final Predicate

keyFilter) { updatedOperational.putAll(Maps.filterKeys(data.getUpdatedOperationalData(), keyFilter)); updatedConfiguration.putAll(Maps.filterKeys(data.getUpdatedConfigurationData(), keyFilter)); originalConfiguration.putAll(Maps.filterKeys(data.getOriginalConfigurationData(), keyFilter)); @@ -127,7 +130,7 @@ final class ImmutableDataChangeEvent

, D> implements DataChange return this; } - protected Builder addConfigurationChangeSet(RootedChangeSet changeSet) { + protected Builder addConfigurationChangeSet(final RootedChangeSet changeSet) { if(changeSet == null) { return this; } @@ -139,7 +142,7 @@ final class ImmutableDataChangeEvent

, D> implements DataChange return this; } - protected Builder addOperationalChangeSet(RootedChangeSet changeSet) { + protected Builder addOperationalChangeSet(final RootedChangeSet changeSet) { if(changeSet == null) { return this; } @@ -150,7 +153,7 @@ final class ImmutableDataChangeEvent

, D> implements DataChange return this; } - protected ImmutableDataChangeEvent build() { + public ImmutableDataChangeEvent build() { return new ImmutableDataChangeEvent(this); } @@ -158,7 +161,7 @@ final class ImmutableDataChangeEvent

, D> implements DataChange return updatedOperationalSubtree; } - protected Builder setUpdatedOperationalSubtree(D updatedOperationalSubtree) { + public Builder setUpdatedOperationalSubtree(final D updatedOperationalSubtree) { this.updatedOperationalSubtree = updatedOperationalSubtree; return this; } @@ -167,7 +170,7 @@ final class ImmutableDataChangeEvent

, D> implements DataChange return originalOperationalSubtree; } - protected Builder setOriginalOperationalSubtree(D originalOperationalSubtree) { + public Builder setOriginalOperationalSubtree(final D originalOperationalSubtree) { this.originalOperationalSubtree = originalOperationalSubtree; return this; } @@ -176,7 +179,7 @@ final class ImmutableDataChangeEvent

, D> implements DataChange return originalConfigurationSubtree; } - protected Builder setOriginalConfigurationSubtree(D originalConfigurationSubtree) { + public Builder setOriginalConfigurationSubtree(final D originalConfigurationSubtree) { this.originalConfigurationSubtree = originalConfigurationSubtree; return this; } @@ -185,7 +188,7 @@ final class ImmutableDataChangeEvent

, D> implements DataChange return updatedConfigurationSubtree; } - protected Builder setUpdatedConfigurationSubtree(D updatedConfigurationSubtree) { + public Builder setUpdatedConfigurationSubtree(final D updatedConfigurationSubtree) { this.updatedConfigurationSubtree = updatedConfigurationSubtree; return this; } @@ -221,6 +224,26 @@ final class ImmutableDataChangeEvent

, D> implements DataChange protected ImmutableMap.Builder getCreatedConfiguration() { return createdConfiguration; } + + public Builder putOriginalOperational(final Map originalData) { + originalOperational.putAll(originalData); + return this; + } + + public Builder putCreatedOperational(final Map originalData) { + createdOperational.putAll(originalData); + return this; + } + + public Builder putUpdatedOperational(final Map originalData) { + updatedOperational.putAll(originalData); + return this; + } + + public Builder putRemovedOperational(final Set originalData) { + removedOperational.addAll(originalData); + return this; + } } } diff --git a/opendaylight/md-sal/sal-common-impl/src/main/java/org/opendaylight/controller/md/sal/common/impl/util/compat/DataNormalizationOperation.java b/opendaylight/md-sal/sal-common-impl/src/main/java/org/opendaylight/controller/md/sal/common/impl/util/compat/DataNormalizationOperation.java new file mode 100644 index 0000000000..de90f48b35 --- /dev/null +++ b/opendaylight/md-sal/sal-common-impl/src/main/java/org/opendaylight/controller/md/sal/common/impl/util/compat/DataNormalizationOperation.java @@ -0,0 +1,554 @@ +package org.opendaylight.controller.md.sal.common.impl.util.compat; + +import static com.google.common.base.Preconditions.checkArgument; +import static com.google.common.base.Preconditions.checkNotNull; + +import java.util.Collections; +import java.util.HashSet; +import java.util.List; +import java.util.Map; +import java.util.Map.Entry; +import java.util.Set; +import java.util.concurrent.ConcurrentHashMap; + +import org.opendaylight.yangtools.concepts.Identifiable; +import org.opendaylight.yangtools.yang.common.QName; +import org.opendaylight.yangtools.yang.data.api.CompositeNode; +import org.opendaylight.yangtools.yang.data.api.InstanceIdentifier.AugmentationIdentifier; +import org.opendaylight.yangtools.yang.data.api.InstanceIdentifier.NodeIdentifier; +import org.opendaylight.yangtools.yang.data.api.InstanceIdentifier.NodeIdentifierWithPredicates; +import org.opendaylight.yangtools.yang.data.api.InstanceIdentifier.NodeWithValue; +import org.opendaylight.yangtools.yang.data.api.InstanceIdentifier.PathArgument; +import org.opendaylight.yangtools.yang.data.api.Node; +import org.opendaylight.yangtools.yang.data.api.SimpleNode; +import org.opendaylight.yangtools.yang.data.api.schema.MapEntryNode; +import org.opendaylight.yangtools.yang.data.api.schema.NormalizedNode; +import org.opendaylight.yangtools.yang.data.api.schema.NormalizedNodeContainer; +import org.opendaylight.yangtools.yang.data.impl.schema.Builders; +import org.opendaylight.yangtools.yang.data.impl.schema.ImmutableNodes; +import org.opendaylight.yangtools.yang.data.impl.schema.builder.api.DataContainerNodeAttrBuilder; +import org.opendaylight.yangtools.yang.data.impl.schema.builder.api.NormalizedNodeContainerBuilder; +import org.opendaylight.yangtools.yang.model.api.AugmentationSchema; +import org.opendaylight.yangtools.yang.model.api.AugmentationTarget; +import org.opendaylight.yangtools.yang.model.api.ChoiceCaseNode; +import org.opendaylight.yangtools.yang.model.api.ContainerSchemaNode; +import org.opendaylight.yangtools.yang.model.api.DataNodeContainer; +import org.opendaylight.yangtools.yang.model.api.DataSchemaNode; +import org.opendaylight.yangtools.yang.model.api.LeafListSchemaNode; +import org.opendaylight.yangtools.yang.model.api.LeafSchemaNode; +import org.opendaylight.yangtools.yang.model.api.ListSchemaNode; +import org.opendaylight.yangtools.yang.model.api.SchemaContext; + +import com.google.common.collect.FluentIterable; +import com.google.common.collect.ImmutableMap; +import com.google.common.collect.ImmutableSet; + +public abstract class DataNormalizationOperation implements Identifiable { + + private final T identifier; + + @Override + public T getIdentifier() { + return identifier; + }; + + protected DataNormalizationOperation(final T identifier) { + super(); + this.identifier = identifier; + } + + public boolean isMixin() { + return false; + } + + protected Set getQNameIdentifiers() { + return Collections.singleton(identifier.getNodeType()); + } + + public abstract DataNormalizationOperation getChild(final PathArgument child); + + public abstract DataNormalizationOperation getChild(QName child); + + public abstract NormalizedNode normalize(Node legacyData); + + private static abstract class SimpleTypeNormalization extends DataNormalizationOperation { + + protected SimpleTypeNormalization(final T identifier) { + super(identifier); + } + + @Override + public NormalizedNode normalize(final Node legacyData) { + checkArgument(legacyData != null); + checkArgument(legacyData instanceof SimpleNode); + return normalizeImpl((SimpleNode) legacyData); + } + + protected abstract NormalizedNode normalizeImpl(SimpleNode node); + + @Override + public DataNormalizationOperation getChild(final PathArgument child) { + return null; + } + + @Override + public DataNormalizationOperation getChild(final QName child) { + return null; + } + + @Override + public NormalizedNode createDefault(final PathArgument currentArg) { + // TODO Auto-generated method stub + return null; + } + + } + + private static final class LeafNormalization extends SimpleTypeNormalization { + + protected LeafNormalization(final NodeIdentifier identifier) { + super(identifier); + } + + @Override + protected NormalizedNode normalizeImpl(final SimpleNode node) { + return ImmutableNodes.leafNode(node.getNodeType(), node.getValue()); + } + + } + + private static final class LeafListEntryNormalization extends SimpleTypeNormalization { + + public LeafListEntryNormalization(final LeafListSchemaNode potential) { + super(new NodeWithValue(potential.getQName(), null)); + } + + @Override + protected NormalizedNode normalizeImpl(final SimpleNode node) { + NodeWithValue nodeId = new NodeWithValue(node.getNodeType(), node.getValue()); + return Builders.leafSetEntryBuilder().withNodeIdentifier(nodeId).withValue(node.getValue()).build(); + } + + } + + private static abstract class CompositeNodeNormalizationOpertation extends + DataNormalizationOperation { + + protected CompositeNodeNormalizationOpertation(final T identifier) { + super(identifier); + } + + @SuppressWarnings({ "rawtypes", "unchecked" }) + @Override + public final NormalizedNodeContainer normalize(final Node legacyData) { + checkArgument(legacyData != null); + if (!isMixin() && getIdentifier().getNodeType() != null) { + checkArgument(getIdentifier().getNodeType().equals(legacyData.getNodeType()), + "Node QName must be %s was %s", getIdentifier().getNodeType(), legacyData.getNodeType()); + } + checkArgument(legacyData instanceof CompositeNode, "Node %s should be composite", legacyData); + CompositeNode compositeNode = (CompositeNode) legacyData; + NormalizedNodeContainerBuilder builder = createBuilder(compositeNode); + + Set> usedMixins = new HashSet<>(); + for (Node childLegacy : compositeNode.getValue()) { + DataNormalizationOperation childOp = getChild(childLegacy.getNodeType()); + + // We skip unknown nodes if this node is mixin since + // it's nodes and parent nodes are interleaved + if (childOp == null && isMixin()) { + continue; + } + + checkArgument(childOp != null, "Node %s is not allowed inside %s", childLegacy.getNodeType(), + getIdentifier()); + if (childOp.isMixin()) { + if (usedMixins.contains(childOp)) { + // We already run / processed that mixin, so to avoid + // dupliciry we are + // skiping next nodes. + continue; + } + builder.addChild(childOp.normalize(compositeNode)); + usedMixins.add(childOp); + } else { + builder.addChild(childOp.normalize(childLegacy)); + } + } + return (NormalizedNodeContainer) builder.build(); + } + + @SuppressWarnings("rawtypes") + protected abstract NormalizedNodeContainerBuilder createBuilder(final CompositeNode compositeNode); + + } + + private static abstract class DataContainerNormalizationOperation extends + CompositeNodeNormalizationOpertation { + + private final DataNodeContainer schema; + private final Map> byQName; + private final Map> byArg; + + protected DataContainerNormalizationOperation(final T identifier, final DataNodeContainer schema) { + super(identifier); + this.schema = schema; + this.byArg = new ConcurrentHashMap<>(); + this.byQName = new ConcurrentHashMap<>(); + } + + @Override + public DataNormalizationOperation getChild(final PathArgument child) { + DataNormalizationOperation potential = byArg.get(child); + if (potential != null) { + return potential; + } + potential = fromSchema(schema, child); + return register(potential); + } + + @Override + public DataNormalizationOperation getChild(final QName child) { + DataNormalizationOperation potential = byQName.get(child); + if (potential != null) { + return potential; + } + potential = fromSchemaAndPathArgument(schema, child); + return register(potential); + } + + private DataNormalizationOperation register(final DataNormalizationOperation potential) { + if (potential != null) { + byArg.put(potential.getIdentifier(), potential); + for (QName qName : potential.getQNameIdentifiers()) { + byQName.put(qName, potential); + } + } + return potential; + } + + } + + private static final class ListItemNormalization extends + DataContainerNormalizationOperation { + + private final List keyDefinition; + + protected ListItemNormalization(final NodeIdentifierWithPredicates identifier, final ListSchemaNode schema) { + super(identifier, schema); + keyDefinition = schema.getKeyDefinition(); + } + + @Override + protected NormalizedNodeContainerBuilder createBuilder(final CompositeNode compositeNode) { + ImmutableMap.Builder keys = ImmutableMap.builder(); + for (QName key : keyDefinition) { + SimpleNode valueNode = checkNotNull(compositeNode.getFirstSimpleByName(key),"List node %s MUST contain leaf %s with value.",getIdentifier().getNodeType(),key); + keys.put(key, valueNode.getValue()); + } + + return Builders.mapEntryBuilder().withNodeIdentifier( + new NodeIdentifierWithPredicates(getIdentifier().getNodeType(), keys.build())); + } + + @Override + public NormalizedNode createDefault(final PathArgument currentArg) { + DataContainerNodeAttrBuilder builder = Builders + .mapEntryBuilder().withNodeIdentifier((NodeIdentifierWithPredicates) currentArg); + for (Entry keyValue : ((NodeIdentifierWithPredicates) currentArg).getKeyValues().entrySet()) { + builder.addChild(Builders.leafBuilder() + // + .withNodeIdentifier(new NodeIdentifier(keyValue.getKey())).withValue(keyValue.getValue()) + .build()); + } + return builder.build(); + } + } + + private static final class ContainerNormalization extends DataContainerNormalizationOperation { + + protected ContainerNormalization(final ContainerSchemaNode schema) { + super(new NodeIdentifier(schema.getQName()), schema); + } + + @Override + protected NormalizedNodeContainerBuilder createBuilder(final CompositeNode compositeNode) { + return Builders.containerBuilder().withNodeIdentifier(getIdentifier()); + } + + @Override + public NormalizedNode createDefault(final PathArgument currentArg) { + return Builders.containerBuilder().withNodeIdentifier((NodeIdentifier) currentArg).build(); + } + + } + + private static abstract class MixinNormalizationOp extends + CompositeNodeNormalizationOpertation { + + protected MixinNormalizationOp(final T identifier) { + super(identifier); + } + + @Override + public final boolean isMixin() { + return true; + } + + } + + private static final class LeafListMixinNormalization extends MixinNormalizationOp { + + private final DataNormalizationOperation innerOp; + + public LeafListMixinNormalization(final LeafListSchemaNode potential) { + super(new NodeIdentifier(potential.getQName())); + innerOp = new LeafListEntryNormalization(potential); + } + + @Override + protected NormalizedNodeContainerBuilder createBuilder(final CompositeNode compositeNode) { + return Builders.leafSetBuilder().withNodeIdentifier(getIdentifier()); + } + + @Override + public NormalizedNode createDefault(final PathArgument currentArg) { + return Builders.leafSetBuilder().withNodeIdentifier(getIdentifier()).build(); + } + + @Override + public DataNormalizationOperation getChild(final PathArgument child) { + if (child instanceof NodeWithValue) { + return innerOp; + } + return null; + } + + @Override + public DataNormalizationOperation getChild(final QName child) { + if (getIdentifier().getNodeType().equals(child)) { + return innerOp; + } + return null; + } + } + + private static final class AugmentationNormalization extends MixinNormalizationOp { + + private final Map> byQName; + private final Map> byArg; + + public AugmentationNormalization(final AugmentationSchema augmentation, final DataNodeContainer schema) { + super(augmentationIdentifierFrom(augmentation)); + + ImmutableMap.Builder> byQNameBuilder = ImmutableMap.builder(); + ImmutableMap.Builder> byArgBuilder = ImmutableMap.builder(); + + for (DataSchemaNode augNode : augmentation.getChildNodes()) { + DataSchemaNode resolvedNode = schema.getDataChildByName(augNode.getQName()); + DataNormalizationOperation resolvedOp = fromDataSchemaNode(resolvedNode); + byArgBuilder.put(resolvedOp.getIdentifier(), resolvedOp); + for (QName resQName : resolvedOp.getQNameIdentifiers()) { + byQNameBuilder.put(resQName, resolvedOp); + } + } + byQName = byQNameBuilder.build(); + byArg = byArgBuilder.build(); + + } + + @Override + public DataNormalizationOperation getChild(final PathArgument child) { + return byArg.get(child); + } + + @Override + public DataNormalizationOperation getChild(final QName child) { + return byQName.get(child); + } + + @Override + protected Set getQNameIdentifiers() { + return getIdentifier().getPossibleChildNames(); + } + + @SuppressWarnings("rawtypes") + @Override + protected NormalizedNodeContainerBuilder createBuilder(final CompositeNode compositeNode) { + return Builders.augmentationBuilder().withNodeIdentifier(getIdentifier()); + } + + @Override + public NormalizedNode createDefault(final PathArgument currentArg) { + return Builders.augmentationBuilder().withNodeIdentifier(getIdentifier()).build(); + } + + } + + private static final class ListMixinNormalization extends MixinNormalizationOp { + + private final ListItemNormalization innerNode; + + public ListMixinNormalization(final ListSchemaNode list) { + super(new NodeIdentifier(list.getQName())); + this.innerNode = new ListItemNormalization(new NodeIdentifierWithPredicates(list.getQName(), + Collections. emptyMap()), list); + } + + @SuppressWarnings("rawtypes") + @Override + protected NormalizedNodeContainerBuilder createBuilder(final CompositeNode compositeNode) { + return Builders.mapBuilder().withNodeIdentifier(getIdentifier()); + } + + @Override + public NormalizedNode createDefault(final PathArgument currentArg) { + return Builders.mapBuilder().withNodeIdentifier(getIdentifier()).build(); + } + + @Override + public DataNormalizationOperation getChild(final PathArgument child) { + if (child.getNodeType().equals(getIdentifier().getNodeType())) { + return innerNode; + } + return null; + } + + @Override + public DataNormalizationOperation getChild(final QName child) { + if (getIdentifier().getNodeType().equals(child)) { + return innerNode; + } + return null; + } + + } + + private static class ChoiceNodeNormalization extends MixinNormalizationOp { + + private final ImmutableMap> byQName; + private final ImmutableMap> byArg; + + protected ChoiceNodeNormalization(final org.opendaylight.yangtools.yang.model.api.ChoiceNode schema) { + super(new NodeIdentifier(schema.getQName())); + ImmutableMap.Builder> byQNameBuilder = ImmutableMap.builder(); + ImmutableMap.Builder> byArgBuilder = ImmutableMap.builder(); + + for (ChoiceCaseNode caze : schema.getCases()) { + for (DataSchemaNode cazeChild : caze.getChildNodes()) { + DataNormalizationOperation childOp = fromDataSchemaNode(cazeChild); + byArgBuilder.put(childOp.getIdentifier(), childOp); + for (QName qname : childOp.getQNameIdentifiers()) { + byQNameBuilder.put(qname, childOp); + } + } + } + byQName = byQNameBuilder.build(); + byArg = byArgBuilder.build(); + } + + @Override + public DataNormalizationOperation getChild(final PathArgument child) { + return byArg.get(child); + } + + @Override + public DataNormalizationOperation getChild(final QName child) { + return byQName.get(child); + } + + @Override + protected NormalizedNodeContainerBuilder createBuilder(final CompositeNode compositeNode) { + return Builders.choiceBuilder().withNodeIdentifier(getIdentifier()); + } + + @Override + public NormalizedNode createDefault(final PathArgument currentArg) { + return Builders.choiceBuilder().withNodeIdentifier(getIdentifier()).build(); + } + } + + public static DataNormalizationOperation fromSchemaAndPathArgument(final DataNodeContainer schema, + final QName child) { + DataSchemaNode potential = schema.getDataChildByName(child); + if (potential == null) { + Iterable choices = FluentIterable.from( + schema.getChildNodes()).filter(org.opendaylight.yangtools.yang.model.api.ChoiceNode.class); + potential = findChoice(choices, child); + } + checkArgument(potential != null, "Supplied QName %s is not valid according to schema %s", child, schema); + if ((schema instanceof DataSchemaNode) && !((DataSchemaNode) schema).isAugmenting() && potential.isAugmenting()) { + return fromAugmentation(schema, (AugmentationTarget) schema, potential); + } + return fromDataSchemaNode(potential); + } + + private static org.opendaylight.yangtools.yang.model.api.ChoiceNode findChoice( + final Iterable choices, final QName child) { + org.opendaylight.yangtools.yang.model.api.ChoiceNode foundChoice = null; + choiceLoop: for (org.opendaylight.yangtools.yang.model.api.ChoiceNode choice : choices) { + for (ChoiceCaseNode caze : choice.getCases()) { + if (caze.getDataChildByName(child) != null) { + foundChoice = choice; + break choiceLoop; + } + } + } + return foundChoice; + } + + public static AugmentationIdentifier augmentationIdentifierFrom(final AugmentationSchema augmentation) { + ImmutableSet.Builder potentialChildren = ImmutableSet.builder(); + for (DataSchemaNode child : augmentation.getChildNodes()) { + potentialChildren.add(child.getQName()); + } + return new AugmentationIdentifier(null, potentialChildren.build()); + } + + private static AugmentationNormalization fromAugmentation(final DataNodeContainer schema, + final AugmentationTarget augments, final DataSchemaNode potential) { + AugmentationSchema augmentation = null; + for (AugmentationSchema aug : augments.getAvailableAugmentations()) { + DataSchemaNode child = aug.getDataChildByName(potential.getQName()); + if (child != null) { + augmentation = aug; + break; + } + + } + if (augmentation != null) { + return new AugmentationNormalization(augmentation, schema); + } else { + return null; + } + } + + private static DataNormalizationOperation fromSchema(final DataNodeContainer schema, final PathArgument child) { + if (child instanceof AugmentationIdentifier) { + return fromSchemaAndPathArgument(schema, ((AugmentationIdentifier) child).getPossibleChildNames() + .iterator().next()); + } + return fromSchemaAndPathArgument(schema, child.getNodeType()); + } + + public static DataNormalizationOperation fromDataSchemaNode(final DataSchemaNode potential) { + if (potential instanceof ContainerSchemaNode) { + return new ContainerNormalization((ContainerSchemaNode) potential); + } else if (potential instanceof ListSchemaNode) { + return new ListMixinNormalization((ListSchemaNode) potential); + } else if (potential instanceof LeafSchemaNode) { + return new LeafNormalization(new NodeIdentifier(potential.getQName())); + } else if (potential instanceof org.opendaylight.yangtools.yang.model.api.ChoiceNode) { + return new ChoiceNodeNormalization((org.opendaylight.yangtools.yang.model.api.ChoiceNode) potential); + } else if (potential instanceof LeafListSchemaNode) { + return new LeafListMixinNormalization((LeafListSchemaNode) potential); + } + return null; + } + + public static DataNormalizationOperation from(final SchemaContext ctx) { + return new ContainerNormalization(ctx); + } + + public abstract NormalizedNode createDefault(PathArgument currentArg); +} diff --git a/opendaylight/md-sal/sal-common-impl/src/main/java/org/opendaylight/controller/md/sal/common/impl/util/compat/DataNormalizer.java b/opendaylight/md-sal/sal-common-impl/src/main/java/org/opendaylight/controller/md/sal/common/impl/util/compat/DataNormalizer.java new file mode 100644 index 0000000000..9487f21590 --- /dev/null +++ b/opendaylight/md-sal/sal-common-impl/src/main/java/org/opendaylight/controller/md/sal/common/impl/util/compat/DataNormalizer.java @@ -0,0 +1,186 @@ +package org.opendaylight.controller.md.sal.common.impl.util.compat; + +import static com.google.common.base.Preconditions.checkArgument; + +import java.util.AbstractMap; +import java.util.ArrayList; +import java.util.Map; + +import org.opendaylight.yangtools.yang.data.api.CompositeNode; +import org.opendaylight.yangtools.yang.data.api.InstanceIdentifier; +import org.opendaylight.yangtools.yang.data.api.InstanceIdentifier.AugmentationIdentifier; +import org.opendaylight.yangtools.yang.data.api.InstanceIdentifier.NodeIdentifier; +import org.opendaylight.yangtools.yang.data.api.InstanceIdentifier.NodeIdentifierWithPredicates; +import org.opendaylight.yangtools.yang.data.api.InstanceIdentifier.PathArgument; +import org.opendaylight.yangtools.yang.data.api.Node; +import org.opendaylight.yangtools.yang.data.api.SimpleNode; +import org.opendaylight.yangtools.yang.data.api.schema.DataContainerNode; +import org.opendaylight.yangtools.yang.data.api.schema.MixinNode; +import org.opendaylight.yangtools.yang.data.api.schema.NormalizedNode; +import org.opendaylight.yangtools.yang.data.api.schema.NormalizedNodeContainer; +import org.opendaylight.yangtools.yang.data.impl.ImmutableCompositeNode; +import org.opendaylight.yangtools.yang.data.impl.SimpleNodeTOImpl; +import org.opendaylight.yangtools.yang.data.impl.util.CompositeNodeBuilder; +import org.opendaylight.yangtools.yang.model.api.SchemaContext; + +import com.google.common.base.Preconditions; +import com.google.common.base.Predicate; +import com.google.common.collect.FluentIterable; +import com.google.common.collect.ImmutableList; +import com.google.common.collect.Iterables; + +public class DataNormalizer { + + private final SchemaContext schemaContext; + + private final DataNormalizationOperation operation; + + public DataNormalizer(final SchemaContext ctx) { + schemaContext = ctx; + operation = DataNormalizationOperation.from(ctx); + } + + public InstanceIdentifier toNormalized(final InstanceIdentifier legacy) { + ImmutableList.Builder normalizedArgs = ImmutableList.builder(); + + DataNormalizationOperation currentOp = operation; + for (PathArgument legacyArg : legacy.getPath()) { + currentOp = currentOp.getChild(legacyArg); + checkArgument(currentOp != null, "Legacy Instance Identifier %s is not correct. Normalized Instance Identifier so far %s",legacy,normalizedArgs.build()); + while (currentOp.isMixin()) { + normalizedArgs.add(currentOp.getIdentifier()); + currentOp = currentOp.getChild(legacyArg.getNodeType()); + } + normalizedArgs.add(legacyArg); + } + return new InstanceIdentifier(normalizedArgs.build()); + } + + public Map.Entry> toNormalized(final Map.Entry legacy) { + return toNormalized(legacy.getKey(), legacy.getValue()); + } + + public Map.Entry> toNormalized(final InstanceIdentifier legacyPath, final CompositeNode legacyData) { + + InstanceIdentifier normalizedPath = toNormalized(legacyPath); + + DataNormalizationOperation currentOp = operation; + for (PathArgument arg : normalizedPath.getPath()) { + currentOp = currentOp.getChild(arg); + } + // Write Augmentaiton data resolution + if (legacyData.getChildren().size() == 1) { + DataNormalizationOperation potentialOp = currentOp.getChild(legacyData.getChildren().get(0) + .getNodeType()); + if(potentialOp.getIdentifier() instanceof AugmentationIdentifier) { + currentOp = potentialOp; + ArrayList reworkedArgs = new ArrayList<>(normalizedPath.getPath()); + reworkedArgs.add(potentialOp.getIdentifier()); + normalizedPath = new InstanceIdentifier(reworkedArgs); + } + } + + Preconditions.checkArgument(currentOp != null, + "Instance Identifier %s does not reference correct schema Node.", normalizedPath); + return new AbstractMap.SimpleEntry>(normalizedPath,currentOp.normalize(legacyData)); + } + + public InstanceIdentifier toLegacy(final InstanceIdentifier normalized) { + ImmutableList.Builder legacyArgs = ImmutableList.builder(); + PathArgument previous = null; + for (PathArgument normalizedArg : normalized.getPath()) { + if (normalizedArg instanceof NodeIdentifier) { + if (previous != null) { + legacyArgs.add(previous); + } + previous = normalizedArg; + } else if (normalizedArg instanceof NodeIdentifierWithPredicates) { + // We skip previous node, which was mixin. + previous = normalizedArg; + } else if (normalizedArg instanceof AugmentationIdentifier) { + // We ignore argument + } + // FIXME : Add option for reading choice + } + if (previous != null) { + legacyArgs.add(previous); + } + return new InstanceIdentifier(legacyArgs.build()); + } + + public CompositeNode toLegacy(final InstanceIdentifier normalizedPath, final NormalizedNode normalizedData) { + // Preconditions.checkArgument(normalizedData instanceof + // DataContainerNode,"Node object %s, %s should be of type DataContainerNode",normalizedPath,normalizedData); + if (normalizedData instanceof DataContainerNode) { + return toLegacyFromDataContainer((DataContainerNode) normalizedData); + } + return null; + } + + public static Node toLegacy(final NormalizedNode node) { + if (node instanceof MixinNode) { + /** + * Direct reading of MixinNodes is not supported, + * since it is not possible in legacy APIs create pointer + * to Mixin Nodes. + * + */ + return null; + } + + if (node instanceof DataContainerNode) { + return toLegacyFromDataContainer((DataContainerNode) node); + } + return toLegacySimple(node); + + } + + private static SimpleNode toLegacySimple(final NormalizedNode node) { + return new SimpleNodeTOImpl(node.getNodeType(), null, node.getValue()); + } + + @SuppressWarnings({ "unchecked", "rawtypes" }) + private static CompositeNode toLegacyFromDataContainer(final DataContainerNode node) { + CompositeNodeBuilder builder = ImmutableCompositeNode.builder(); + builder.setQName(node.getNodeType()); + for (NormalizedNode child : node.getValue()) { + if (child instanceof MixinNode && child instanceof NormalizedNodeContainer) { + builder.addAll(toLegacyNodesFromMixin((NormalizedNodeContainer) child)); + } else { + addToBuilder(builder, toLegacy(child)); + } + } + return builder.toInstance(); + } + + private static void addToBuilder(final CompositeNodeBuilder builder, final Node legacy) { + if (legacy != null) { + builder.add(legacy); + } + } + + @SuppressWarnings({ "rawtypes", "unchecked" }) + private static Iterable> toLegacyNodesFromMixin( + final NormalizedNodeContainer> mixin) { + ArrayList> ret = new ArrayList<>(); + for (NormalizedNode child : mixin.getValue()) { + if(child instanceof MixinNode && child instanceof NormalizedNodeContainer) { + Iterables.addAll(ret,toLegacyNodesFromMixin((NormalizedNodeContainer) child)); + } else { + ret.add(toLegacy(child)); + } + } + return FluentIterable.from(ret).filter(new Predicate>() { + + @Override + public boolean apply(final Node input) { + return input != null; + } + }); + } + + public DataNormalizationOperation getRootOperation() { + return operation; + } + +} diff --git a/opendaylight/md-sal/sal-dom-api/src/main/java/org/opendaylight/controller/md/sal/dom/api/DOMDataBroker.java b/opendaylight/md-sal/sal-dom-api/src/main/java/org/opendaylight/controller/md/sal/dom/api/DOMDataBroker.java index 5328b79b1f..dbaba294aa 100644 --- a/opendaylight/md-sal/sal-dom-api/src/main/java/org/opendaylight/controller/md/sal/dom/api/DOMDataBroker.java +++ b/opendaylight/md-sal/sal-dom-api/src/main/java/org/opendaylight/controller/md/sal/dom/api/DOMDataBroker.java @@ -8,10 +8,11 @@ package org.opendaylight.controller.md.sal.dom.api; import org.opendaylight.controller.md.sal.common.api.data.AsyncDataBroker; +import org.opendaylight.controller.sal.core.api.BrokerService; import org.opendaylight.yangtools.yang.data.api.InstanceIdentifier; import org.opendaylight.yangtools.yang.data.api.schema.NormalizedNode; -public interface DOMDataBroker extends AsyncDataBroker, DOMDataChangeListener>{ +public interface DOMDataBroker extends AsyncDataBroker, DOMDataChangeListener>, BrokerService { @Override DOMDataReadTransaction newReadOnlyTransaction(); diff --git a/opendaylight/md-sal/sal-dom-api/src/main/yang/opendaylight-md-sal-dom.yang b/opendaylight/md-sal/sal-dom-api/src/main/yang/opendaylight-md-sal-dom.yang index b0417eb8a0..8194dee0f3 100644 --- a/opendaylight/md-sal/sal-dom-api/src/main/yang/opendaylight-md-sal-dom.yang +++ b/opendaylight/md-sal/sal-dom-api/src/main/yang/opendaylight-md-sal-dom.yang @@ -22,6 +22,11 @@ module opendaylight-md-sal-dom { base "config:service-type"; config:java-class "org.opendaylight.controller.sal.core.api.data.DataProviderService"; } + + identity dom-async-data-broker { + base "config:service-type"; + config:java-class "org.opendaylight.controller.md.sal.dom.api.DOMDataBroker"; + } identity dom-data-store { base "config:service-type"; diff --git a/opendaylight/md-sal/sal-dom-broker/pom.xml b/opendaylight/md-sal/sal-dom-broker/pom.xml index e3e5043e91..5063e4339b 100644 --- a/opendaylight/md-sal/sal-dom-broker/pom.xml +++ b/opendaylight/md-sal/sal-dom-broker/pom.xml @@ -138,10 +138,15 @@ org.opendaylight.controller.sal.dom.broker, org.opendaylight.controller.sal.dom.broker.impl, + org.opendaylight.controller.sal.dom.broker.impl.*, org.opendaylight.controller.sal.dom.broker.osgi, org.opendaylight.controller.sal.dom.broker.util, org.opendaylight.controller.config.yang.md.sal.dom.impl, org.opendaylight.controller.config.yang.md.sal.dom.statistics, + org.opendaylight.controller.md.sal.dom.broker.impl, + org.opendaylight.controller.md.sal.dom.broker.impl.*, + org.opendaylight.controller.md.sal.dom.store.impl, + org.opendaylight.controller.md.sal.dom.store.impl.*, org.opendaylight.yangtools.yang.util, org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.controller.md.sal.dom.impl.rev131028.* diff --git a/opendaylight/md-sal/sal-dom-broker/src/main/java/org/opendaylight/controller/config/yang/md/sal/dom/impl/DomBrokerImplModule.java b/opendaylight/md-sal/sal-dom-broker/src/main/java/org/opendaylight/controller/config/yang/md/sal/dom/impl/DomBrokerImplModule.java index f4d642f82d..767785dbf1 100644 --- a/opendaylight/md-sal/sal-dom-broker/src/main/java/org/opendaylight/controller/config/yang/md/sal/dom/impl/DomBrokerImplModule.java +++ b/opendaylight/md-sal/sal-dom-broker/src/main/java/org/opendaylight/controller/config/yang/md/sal/dom/impl/DomBrokerImplModule.java @@ -7,14 +7,12 @@ */ package org.opendaylight.controller.config.yang.md.sal.dom.impl; -import org.opendaylight.controller.config.yang.md.sal.dom.statistics.DomBrokerRuntimeMXBeanImpl; +import org.opendaylight.controller.md.sal.dom.api.DOMDataBroker; import org.opendaylight.controller.sal.core.api.data.DataStore; import org.opendaylight.controller.sal.dom.broker.BrokerConfigActivator; import org.opendaylight.controller.sal.dom.broker.BrokerImpl; import org.osgi.framework.BundleContext; -import static com.google.common.base.Preconditions.*; - /** * */ @@ -23,29 +21,30 @@ public final class DomBrokerImplModule extends org.opendaylight.controller.confi private BundleContext bundleContext; - public DomBrokerImplModule(org.opendaylight.controller.config.api.ModuleIdentifier identifier, org.opendaylight.controller.config.api.DependencyResolver dependencyResolver) { + public DomBrokerImplModule(final org.opendaylight.controller.config.api.ModuleIdentifier identifier, final org.opendaylight.controller.config.api.DependencyResolver dependencyResolver) { super(identifier, dependencyResolver); } - public DomBrokerImplModule(org.opendaylight.controller.config.api.ModuleIdentifier identifier, org.opendaylight.controller.config.api.DependencyResolver dependencyResolver, DomBrokerImplModule oldModule, java.lang.AutoCloseable oldInstance) { + public DomBrokerImplModule(final org.opendaylight.controller.config.api.ModuleIdentifier identifier, final org.opendaylight.controller.config.api.DependencyResolver dependencyResolver, final DomBrokerImplModule oldModule, final java.lang.AutoCloseable oldInstance) { super(identifier, dependencyResolver, oldModule, oldInstance); } @Override public void validate(){ super.validate(); - checkArgument(getDataStore() != null, "Data Store needs to be provided for DomBroker"); } - + @Override public java.lang.AutoCloseable createInstance() { final BrokerImpl broker = new BrokerImpl(); final BrokerConfigActivator activator = new BrokerConfigActivator(); final DataStore store = getDataStoreDependency(); - activator.start(broker, store, getBundleContext()); - - final DomBrokerImplRuntimeMXBean domBrokerRuntimeMXBean = new DomBrokerRuntimeMXBeanImpl(activator.getDataService()); - getRootRuntimeBeanRegistratorWrapper().register(domBrokerRuntimeMXBean); + final DOMDataBroker asyncBroker= getAsyncDataBrokerDependency(); + + activator.start(broker, store, asyncBroker,getBundleContext()); + +// final DomBrokerImplRuntimeMXBean domBrokerRuntimeMXBean = new DomBrokerRuntimeMXBeanImpl(activator.getDataService()); +// getRootRuntimeBeanRegistratorWrapper().register(domBrokerRuntimeMXBean); return broker; } @@ -53,7 +52,7 @@ public final class DomBrokerImplModule extends org.opendaylight.controller.confi return this.bundleContext; } - public void setBundleContext(BundleContext bundleContext) { + public void setBundleContext(final BundleContext bundleContext) { this.bundleContext = bundleContext; } } diff --git a/opendaylight/md-sal/sal-dom-broker/src/main/java/org/opendaylight/controller/config/yang/md/sal/dom/impl/DomInmemoryDataBrokerModule.java b/opendaylight/md-sal/sal-dom-broker/src/main/java/org/opendaylight/controller/config/yang/md/sal/dom/impl/DomInmemoryDataBrokerModule.java new file mode 100644 index 0000000000..696c10eb19 --- /dev/null +++ b/opendaylight/md-sal/sal-dom-broker/src/main/java/org/opendaylight/controller/config/yang/md/sal/dom/impl/DomInmemoryDataBrokerModule.java @@ -0,0 +1,77 @@ +/** + * Generated file + + * Generated from: yang module name: opendaylight-sal-dom-broker-impl yang module local name: dom-inmemory-data-broker + * Generated by: org.opendaylight.controller.config.yangjmxgenerator.plugin.JMXGenerator + * Generated at: Fri Mar 28 17:32:48 CET 2014 + * + * Do not modify this file unless it is present under src/main directory + */ +package org.opendaylight.controller.config.yang.md.sal.dom.impl; + +import java.util.Hashtable; +import java.util.concurrent.Executors; + +import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType; +import org.opendaylight.controller.md.sal.dom.api.DOMDataBroker; +import org.opendaylight.controller.md.sal.dom.broker.impl.DOMDataBrokerImpl; +import org.opendaylight.controller.md.sal.dom.store.impl.InMemoryDOMDataStore; +import org.opendaylight.controller.sal.core.spi.data.DOMStore; +import org.osgi.framework.BundleContext; + +import com.google.common.collect.ImmutableMap; +import com.google.common.util.concurrent.ListeningExecutorService; +import com.google.common.util.concurrent.MoreExecutors; + +/** +* +*/ +public final class DomInmemoryDataBrokerModule extends + org.opendaylight.controller.config.yang.md.sal.dom.impl.AbstractDomInmemoryDataBrokerModule { + + private BundleContext bundleContext; + + public DomInmemoryDataBrokerModule(final org.opendaylight.controller.config.api.ModuleIdentifier identifier, + final org.opendaylight.controller.config.api.DependencyResolver dependencyResolver) { + super(identifier, dependencyResolver); + } + + public DomInmemoryDataBrokerModule(final org.opendaylight.controller.config.api.ModuleIdentifier identifier, + final org.opendaylight.controller.config.api.DependencyResolver dependencyResolver, + final DomInmemoryDataBrokerModule oldModule, final java.lang.AutoCloseable oldInstance) { + + super(identifier, dependencyResolver, oldModule, oldInstance); + } + + @Override + protected void customValidation() { + // Add custom validation for module attributes here. + } + + @Override + public java.lang.AutoCloseable createInstance() { + ListeningExecutorService storeExecutor = MoreExecutors.listeningDecorator(Executors.newFixedThreadPool(2)); + InMemoryDOMDataStore operStore = new InMemoryDOMDataStore("DOM-OPER", storeExecutor); + InMemoryDOMDataStore configStore = new InMemoryDOMDataStore("DOM-CFG", storeExecutor); + ImmutableMap datastores = ImmutableMap + . builder().put(LogicalDatastoreType.OPERATIONAL, operStore) + .put(LogicalDatastoreType.CONFIGURATION, configStore).build(); + + DOMDataBrokerImpl newDataBroker = new DOMDataBrokerImpl(datastores, MoreExecutors.sameThreadExecutor()); + + getBundleContext().registerService(DOMDataBroker.class, newDataBroker, new Hashtable()); + + getSchemaServiceDependency().registerSchemaServiceListener(operStore); + getSchemaServiceDependency().registerSchemaServiceListener(configStore); + + return newDataBroker; + } + + private BundleContext getBundleContext() { + return bundleContext; + } + + void setBundleContext(final BundleContext ctx) { + bundleContext = ctx; + } +} diff --git a/opendaylight/md-sal/sal-dom-broker/src/main/java/org/opendaylight/controller/config/yang/md/sal/dom/impl/DomInmemoryDataBrokerModuleFactory.java b/opendaylight/md-sal/sal-dom-broker/src/main/java/org/opendaylight/controller/config/yang/md/sal/dom/impl/DomInmemoryDataBrokerModuleFactory.java new file mode 100644 index 0000000000..92d159cec6 --- /dev/null +++ b/opendaylight/md-sal/sal-dom-broker/src/main/java/org/opendaylight/controller/config/yang/md/sal/dom/impl/DomInmemoryDataBrokerModuleFactory.java @@ -0,0 +1,39 @@ +/** +* Generated file + +* Generated from: yang module name: opendaylight-sal-dom-broker-impl yang module local name: dom-inmemory-data-broker +* Generated by: org.opendaylight.controller.config.yangjmxgenerator.plugin.JMXGenerator +* Generated at: Fri Mar 28 17:32:48 CET 2014 +* +* Do not modify this file unless it is present under src/main directory +*/ +package org.opendaylight.controller.config.yang.md.sal.dom.impl; + +import org.opendaylight.controller.config.api.DependencyResolver; +import org.opendaylight.controller.config.api.DynamicMBeanWithInstance; +import org.opendaylight.controller.config.spi.Module; +import org.osgi.framework.BundleContext; + +/** +* +*/ +public class DomInmemoryDataBrokerModuleFactory extends org.opendaylight.controller.config.yang.md.sal.dom.impl.AbstractDomInmemoryDataBrokerModuleFactory +{ + + + + @Override + public Module createModule(final String instanceName, final DependencyResolver dependencyResolver, final BundleContext bundleContext) { + DomInmemoryDataBrokerModule module = (DomInmemoryDataBrokerModule) super.createModule(instanceName, dependencyResolver, bundleContext); + module.setBundleContext(bundleContext); + return module; + } + + @Override + public Module createModule(final String instanceName, final DependencyResolver dependencyResolver, + final DynamicMBeanWithInstance old, final BundleContext bundleContext) throws Exception { + DomInmemoryDataBrokerModule module = (DomInmemoryDataBrokerModule) super.createModule(instanceName, dependencyResolver, old, bundleContext); + module.setBundleContext(bundleContext); + return module; + } +} diff --git a/opendaylight/md-sal/sal-dom-broker/src/main/java/org/opendaylight/controller/md/sal/dom/broker/impl/DOMDataBrokerImpl.java b/opendaylight/md-sal/sal-dom-broker/src/main/java/org/opendaylight/controller/md/sal/dom/broker/impl/DOMDataBrokerImpl.java index 3fafad7cf9..fcf8b40efe 100644 --- a/opendaylight/md-sal/sal-dom-broker/src/main/java/org/opendaylight/controller/md/sal/dom/broker/impl/DOMDataBrokerImpl.java +++ b/opendaylight/md-sal/sal-dom-broker/src/main/java/org/opendaylight/controller/md/sal/dom/broker/impl/DOMDataBrokerImpl.java @@ -10,10 +10,12 @@ package org.opendaylight.controller.md.sal.dom.broker.impl; import static com.google.common.base.Preconditions.checkNotNull; import static com.google.common.base.Preconditions.checkState; +import java.util.Collections; import java.util.List; import java.util.Map.Entry; import java.util.concurrent.Callable; import java.util.concurrent.ExecutionException; +import java.util.concurrent.atomic.AtomicLong; import org.opendaylight.controller.md.sal.common.api.TransactionStatus; import org.opendaylight.controller.md.sal.common.api.data.AsyncTransaction; @@ -23,6 +25,7 @@ import org.opendaylight.controller.md.sal.dom.api.DOMDataChangeListener; import org.opendaylight.controller.md.sal.dom.api.DOMDataReadTransaction; import org.opendaylight.controller.md.sal.dom.api.DOMDataReadWriteTransaction; import org.opendaylight.controller.md.sal.dom.api.DOMDataWriteTransaction; +import org.opendaylight.controller.sal.common.util.Rpcs; import org.opendaylight.controller.sal.core.spi.data.DOMStore; import org.opendaylight.controller.sal.core.spi.data.DOMStoreReadTransaction; import org.opendaylight.controller.sal.core.spi.data.DOMStoreReadWriteTransaction; @@ -30,6 +33,7 @@ import org.opendaylight.controller.sal.core.spi.data.DOMStoreThreePhaseCommitCoh import org.opendaylight.controller.sal.core.spi.data.DOMStoreTransaction; import org.opendaylight.controller.sal.core.spi.data.DOMStoreWriteTransaction; import org.opendaylight.yangtools.concepts.ListenerRegistration; +import org.opendaylight.yangtools.yang.common.RpcError; import org.opendaylight.yangtools.yang.common.RpcResult; import org.opendaylight.yangtools.yang.data.api.InstanceIdentifier; import org.opendaylight.yangtools.yang.data.api.schema.NormalizedNode; @@ -45,12 +49,13 @@ import com.google.common.util.concurrent.Futures; import com.google.common.util.concurrent.ListenableFuture; import com.google.common.util.concurrent.ListeningExecutorService; -public class DOMDataBrokerImpl implements DOMDataBroker { +public class DOMDataBrokerImpl implements DOMDataBroker, AutoCloseable { private static final Logger LOG = LoggerFactory.getLogger(DOMDataBrokerImpl.class); private static final Logger COORDINATOR_LOG = LoggerFactory.getLogger(CommitCoordination.class); private final ImmutableMap datastores; private final ListeningExecutorService executor; + private final AtomicLong txNum = new AtomicLong(); public DOMDataBrokerImpl(final ImmutableMap datastores, final ListeningExecutorService executor) { @@ -83,7 +88,7 @@ public class DOMDataBrokerImpl implements DOMDataBroker { } private Object newTransactionIdentifier() { - return new Object(); + return "DOM-" + txNum.getAndIncrement(); } @Override @@ -115,6 +120,7 @@ public class DOMDataBrokerImpl implements DOMDataBroker { private ListenableFuture> submit( final WriteTransactionImpl transaction) { + LOG.debug("Tx: {} is submitted for execution.",transaction.getIdentifier()); return executor.submit(new CommitCoordination(transaction)); } @@ -245,6 +251,11 @@ public class DOMDataBrokerImpl implements DOMDataBroker { final InstanceIdentifier path) { return getSubtransaction(store).read(path); } + + @Override + public void merge(final LogicalDatastoreType store, final InstanceIdentifier path, final NormalizedNode data) { + + } } private final class CommitCoordination implements Callable> { @@ -265,7 +276,8 @@ public class DOMDataBrokerImpl implements DOMDataBroker { preCommit().get(); try { commit().get(); - return null; + COORDINATOR_LOG.debug("Tx: {} Is commited.",transaction.getIdentifier()); + return Rpcs.getRpcResult(true, TransactionStatus.COMMITED, Collections.emptySet()); } catch (InterruptedException | ExecutionException e) { COORDINATOR_LOG.error("Tx: {} Error during commit", transaction.getIdentifier(), e); } @@ -275,6 +287,7 @@ public class DOMDataBrokerImpl implements DOMDataBroker { transaction.getIdentifier(), e); } } else { + COORDINATOR_LOG.info("Tx: {} Did not pass canCommit phase."); abort().get(); } } catch (InterruptedException | ExecutionException e) { @@ -286,7 +299,7 @@ public class DOMDataBrokerImpl implements DOMDataBroker { } catch (InterruptedException | ExecutionException e) { COORDINATOR_LOG.error("Tx: {} Error during abort", transaction.getIdentifier(), e); } - return null; + return Rpcs.getRpcResult(false, TransactionStatus.FAILED, Collections.emptySet()); } public ListenableFuture preCommit() { @@ -328,4 +341,9 @@ public class DOMDataBrokerImpl implements DOMDataBroker { } + @Override + public void close() throws Exception { + + } + } 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 new file mode 100644 index 0000000000..b2217a6f0a --- /dev/null +++ b/opendaylight/md-sal/sal-dom-broker/src/main/java/org/opendaylight/controller/md/sal/dom/broker/impl/compat/BackwardsCompatibleDataBroker.java @@ -0,0 +1,148 @@ +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(); + + + public BackwardsCompatibleDataBroker(final DOMDataBroker newBiDataImpl) { + backingBroker = newBiDataImpl; + } + + @Override + public void onGlobalContextUpdated(final SchemaContext ctx) { + normalizer = new DataNormalizer(ctx); + } + + @Override + public CompositeNode readConfigurationData(final InstanceIdentifier legacyPath) { + BackwardsCompatibleTransaction tx = BackwardsCompatibleTransaction.readOnlyTransaction(backingBroker.newReadOnlyTransaction(),normalizer); + try { + return tx.readConfigurationData(legacyPath); + } finally { + tx.commit(); + } + } + + @Override + public CompositeNode readOperationalData(final InstanceIdentifier legacyPath) { + BackwardsCompatibleTransaction tx = BackwardsCompatibleTransaction.readOnlyTransaction(backingBroker.newReadOnlyTransaction(),normalizer); + try { + return tx.readOperationalData(legacyPath); + } finally { + tx.commit(); + } + } + + @Override + public DataModificationTransaction beginTransaction() { + return BackwardsCompatibleTransaction.readWriteTransaction(backingBroker.newReadWriteTransaction(), normalizer); + } + + @Override + public ListenerRegistration registerDataChangeListener(final InstanceIdentifier path, + final DataChangeListener listener) { + return fakeRegistry .register(listener); + } + + @Override + public Registration> registerCommitHandler( + final InstanceIdentifier path, final DataCommitHandler commitHandler) { + // FIXME Do real forwarding + return new AbstractObjectRegistration>(commitHandler) { + @Override + protected void removeRegistration() { + // NOOP + } + }; + } + + @Override + public ListenerRegistration>> registerCommitHandlerListener( + final RegistrationListener> commitHandlerListener) { + return null; + } + + // Obsolote functionality + + @Override + public void addValidator(final DataStoreIdentifier store, final DataValidator validator) { + throw new UnsupportedOperationException(); + } + + @Override + public void removeValidator(final DataStoreIdentifier store, final DataValidator validator) { + throw new UnsupportedOperationException(); + } + + @Override + public void addRefresher(final DataStoreIdentifier store, final DataRefresher refresher) { + throw new UnsupportedOperationException(); + } + + @Override + public void removeRefresher(final DataStoreIdentifier store, final DataRefresher refresher) { + throw new UnsupportedOperationException(); + } + + @Override + public Registration> registerConfigurationReader( + final InstanceIdentifier path, final DataReader reader) { + throw new UnsupportedOperationException("Data Reader contract is not supported."); + } + + @Override + public Registration> registerOperationalReader( + final InstanceIdentifier path, final DataReader reader) { + throw new UnsupportedOperationException("Data Reader contract is not supported."); + } + + private final class TranslatingListenerInvoker implements DOMDataChangeListener, Delegator { + + + private DataChangeListener delegate; + + @Override + public void onDataChanged(final AsyncDataChangeEvent> normalizedChange) { + + DataChangeEvent legacyChange = null; + delegate.onDataChanged(legacyChange); + } + + @Override + public DataChangeListener getDelegate() { + + return delegate; + } + + + } + +} diff --git a/opendaylight/md-sal/sal-dom-broker/src/main/java/org/opendaylight/controller/md/sal/dom/broker/impl/compat/BackwardsCompatibleTransaction.java b/opendaylight/md-sal/sal-dom-broker/src/main/java/org/opendaylight/controller/md/sal/dom/broker/impl/compat/BackwardsCompatibleTransaction.java new file mode 100644 index 0000000000..fce2494554 --- /dev/null +++ b/opendaylight/md-sal/sal-dom-broker/src/main/java/org/opendaylight/controller/md/sal/dom/broker/impl/compat/BackwardsCompatibleTransaction.java @@ -0,0 +1,304 @@ +package org.opendaylight.controller.md.sal.dom.broker.impl.compat; + +import static com.google.common.base.Preconditions.checkNotNull; + +import java.util.ArrayList; +import java.util.Collections; +import java.util.Iterator; +import java.util.List; +import java.util.Map; +import java.util.Map.Entry; +import java.util.Set; +import java.util.concurrent.ExecutionException; +import java.util.concurrent.Future; + +import org.opendaylight.controller.md.sal.common.api.TransactionStatus; +import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType; +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.controller.md.sal.dom.api.DOMDataReadTransaction; +import org.opendaylight.controller.md.sal.dom.api.DOMDataReadWriteTransaction; +import org.opendaylight.controller.sal.core.api.data.DataModificationTransaction; +import org.opendaylight.yangtools.concepts.Delegator; +import org.opendaylight.yangtools.concepts.ListenerRegistration; +import org.opendaylight.yangtools.yang.common.RpcResult; +import org.opendaylight.yangtools.yang.data.api.CompositeNode; +import org.opendaylight.yangtools.yang.data.api.InstanceIdentifier; +import org.opendaylight.yangtools.yang.data.api.InstanceIdentifier.AugmentationIdentifier; +import org.opendaylight.yangtools.yang.data.api.InstanceIdentifier.NodeIdentifier; +import org.opendaylight.yangtools.yang.data.api.InstanceIdentifier.PathArgument; +import org.opendaylight.yangtools.yang.data.api.schema.AugmentationNode; +import org.opendaylight.yangtools.yang.data.api.schema.LeafSetNode; +import org.opendaylight.yangtools.yang.data.api.schema.MapEntryNode; +import org.opendaylight.yangtools.yang.data.api.schema.MapNode; +import org.opendaylight.yangtools.yang.data.api.schema.NormalizedNode; +import org.opendaylight.yangtools.yang.data.impl.schema.Builders; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import com.google.common.base.Optional; +import com.google.common.base.Preconditions; +import com.google.common.collect.Iterables; +import com.google.common.util.concurrent.ListenableFuture; + +public abstract class BackwardsCompatibleTransaction implements + DataModificationTransaction, Delegator { + + private static final Logger LOG = LoggerFactory.getLogger(BackwardsCompatibleTransaction.class); + + private final T asyncTx; + private final DataNormalizer normalizer; + + protected BackwardsCompatibleTransaction(final T asyncTx, final DataNormalizer normalizer) { + super(); + this.asyncTx = asyncTx; + this.normalizer = normalizer; + } + + public static BackwardsCompatibleTransaction readOnlyTransaction(final DOMDataReadTransaction readTx, + final DataNormalizer normalizer) { + + return new BackwardsCompatibleTransaction(readTx, normalizer) { + + @Override + public TransactionStatus getStatus() { + return TransactionStatus.NEW; + } + + @Override + public Future> commit() { + getDelegate().close(); + return null; + } + }; + } + + public static BackwardsCompatibleTransaction readWriteTransaction(final DOMDataReadWriteTransaction rwTx, + final DataNormalizer normalizer) { + return new ReadWriteTransaction(rwTx, normalizer); + } + + protected DataNormalizer getNormalizer() { + return normalizer; + } + + @Override + public T getDelegate() { + return asyncTx; + }; + + @Override + public CompositeNode readConfigurationData(final InstanceIdentifier legacyPath) { + + InstanceIdentifier normalizedPath = normalizer.toNormalized(legacyPath); + + ListenableFuture>> normalizedData = asyncTx.read( + LogicalDatastoreType.CONFIGURATION, normalizedPath); + + try { + return normalizer.toLegacy(normalizedPath, normalizedData.get().orNull()); + } catch (InterruptedException | ExecutionException e) { + return null; + } + } + + @Override + public CompositeNode readOperationalData(final InstanceIdentifier legacyPath) { + InstanceIdentifier normalizedPath = normalizer.toNormalized(legacyPath); + + ListenableFuture>> normalizedData = asyncTx.read( + LogicalDatastoreType.OPERATIONAL, normalizedPath); + + try { + return normalizer.toLegacy(normalizedPath, normalizedData.get().orNull()); + } catch (InterruptedException | ExecutionException e) { + return null; + } + } + + @Override + public ListenerRegistration registerListener(final DataTransactionListener listener) { + throw new UnsupportedOperationException(); + } + + @Override + public Map getCreatedConfigurationData() { + return Collections.emptyMap(); + } + + @Override + public Map getCreatedOperationalData() { + return Collections.emptyMap(); + } + + @Override + public Map getOriginalConfigurationData() { + return Collections.emptyMap(); + } + + @Override + public Map getOriginalOperationalData() { + return Collections.emptyMap(); + } + + @Override + public Set getRemovedConfigurationData() { + return Collections.emptySet(); + } + + @Override + public Set getRemovedOperationalData() { + return Collections.emptySet(); + } + + @Override + public Map getUpdatedConfigurationData() { + return Collections.emptyMap(); + } + + @Override + public Map getUpdatedOperationalData() { + return Collections.emptyMap(); + } + + @Override + public void putConfigurationData(final InstanceIdentifier path, final CompositeNode data) { + throw new UnsupportedOperationException(); + } + + @Override + public void putOperationalData(final InstanceIdentifier path, final CompositeNode data) { + throw new UnsupportedOperationException(); + } + + @Override + public void removeConfigurationData(final InstanceIdentifier path) { + throw new UnsupportedOperationException(); + } + + @Override + public void removeOperationalData(final InstanceIdentifier path) { + throw new UnsupportedOperationException(); + } + + @Override + public Object getIdentifier() { + return asyncTx.getIdentifier(); + } + + private static final class ReadWriteTransaction extends BackwardsCompatibleTransaction { + + private TransactionStatus status = TransactionStatus.NEW; + + protected ReadWriteTransaction(final DOMDataReadWriteTransaction asyncTx, final DataNormalizer normalizer) { + super(asyncTx, normalizer); + } + + @Override + public TransactionStatus getStatus() { + return status; + } + + @Override + public Future> commit() { + Preconditions.checkState(status == TransactionStatus.NEW); + status = TransactionStatus.SUBMITED; + return getDelegate().commit(); + } + + @Override + public void putConfigurationData(final InstanceIdentifier legacyPath, final CompositeNode legacyData) { + checkNotNull(legacyPath, "Path MUST NOT be null."); + checkNotNull(legacyData, "Data for path %s MUST NOT be null",legacyData); + Entry> normalizedData = getNormalizer().toNormalized(legacyPath, legacyData); + putWithEnsuredParents(LogicalDatastoreType.CONFIGURATION, normalizedData.getKey(), normalizedData.getValue()); + } + + @Override + public void putOperationalData(final InstanceIdentifier legacyPath, final CompositeNode legacyData) { + checkNotNull(legacyPath, "Path MUST NOT be null."); + checkNotNull(legacyData, "Data for path %s MUST NOT be null",legacyData); + Entry> normalizedData = getNormalizer().toNormalized(legacyPath, legacyData); + putWithEnsuredParents(LogicalDatastoreType.OPERATIONAL, normalizedData.getKey(), normalizedData.getValue()); + } + + private void putWithEnsuredParents(final LogicalDatastoreType store, final InstanceIdentifier normalizedPath, + final NormalizedNode normalizedData) { + + LOG.trace("write {}:{} ",store,normalizedPath); + try { + List currentArguments = new ArrayList<>(); + DataNormalizationOperation currentOp = getNormalizer().getRootOperation(); + Iterator iterator = normalizedPath.getPath().iterator(); + while(iterator.hasNext()) { + PathArgument currentArg = iterator.next(); + currentOp = currentOp.getChild(currentArg); + currentArguments.add(currentArg); + InstanceIdentifier currentPath = new InstanceIdentifier(currentArguments); + boolean isPresent = getDelegate().read(store, currentPath).get().isPresent(); + if(isPresent == false && iterator.hasNext()) { + getDelegate().put(store, currentPath, currentOp.createDefault(currentArg)); + } + } + } catch (InterruptedException | ExecutionException e) { + LOG.error("Exception durring read.",e); + } + + getDelegate().put(store, normalizedPath, normalizedData); + } + + private boolean isAugmentationChild(final InstanceIdentifier normalizedPath) { + List parentArgs = parentPath(normalizedPath).getPath(); + if(parentArgs.isEmpty()) { + return false; + } + return Iterables.getLast(parentArgs) instanceof AugmentationIdentifier; + } + + private void ensureParentNode(final LogicalDatastoreType store, final InstanceIdentifier normalizedPath, + final NormalizedNode normalizedData) { + InstanceIdentifier parentPath = parentPath(normalizedPath); + PathArgument parentType = Iterables.getLast(parentPath.getPath()); + if(parentType instanceof AugmentationIdentifier) { + AugmentationNode node = Builders.augmentationBuilder() + .withNodeIdentifier((AugmentationIdentifier) parentType) + .build(); + getDelegate().put(store, parentPath, node); + } + if(normalizedData instanceof MapEntryNode) { + MapNode mapNode = Builders.mapBuilder().withNodeIdentifier(new NodeIdentifier(normalizedData.getNodeType())).build(); + getDelegate().put(store, parentPath, mapNode); + } else if (normalizedData instanceof LeafSetNode){ + LeafSetNode leafNode = Builders.leafSetBuilder().withNodeIdentifier(new NodeIdentifier(normalizedData.getNodeType())).build(); + getDelegate().put(store, parentPath, leafNode); + } + + + } + + private InstanceIdentifier parentPath(final InstanceIdentifier normalizedPath) { + List childArgs = normalizedPath.getPath(); + return new InstanceIdentifier(childArgs.subList(0, childArgs.size() -1)); + } + + private boolean parentNodeDoesNotExists(final LogicalDatastoreType store, final InstanceIdentifier normalizedPath) { + try { + return !getDelegate().read(store, parentPath(normalizedPath)).get().isPresent(); + } catch (InterruptedException | ExecutionException e) { + throw new IllegalStateException(e); + } + } + + @Override + public void removeConfigurationData(final InstanceIdentifier legacyPath) { + checkNotNull(legacyPath, "Path MUST NOT be null."); + getDelegate().delete(LogicalDatastoreType.CONFIGURATION, getNormalizer().toNormalized(legacyPath)); + } + + @Override + public void removeOperationalData(final InstanceIdentifier legacyPath) { + checkNotNull(legacyPath, "Path MUST NOT be null."); + getDelegate().delete(LogicalDatastoreType.OPERATIONAL, getNormalizer().toNormalized(legacyPath)); + } + } +} diff --git a/opendaylight/md-sal/sal-dom-broker/src/main/java/org/opendaylight/controller/md/sal/dom/store/impl/InMemoryDOMDataStore.java b/opendaylight/md-sal/sal-dom-broker/src/main/java/org/opendaylight/controller/md/sal/dom/store/impl/InMemoryDOMDataStore.java index 39299ab1bd..0944c2efae 100644 --- a/opendaylight/md-sal/sal-dom-broker/src/main/java/org/opendaylight/controller/md/sal/dom/store/impl/InMemoryDOMDataStore.java +++ b/opendaylight/md-sal/sal-dom-broker/src/main/java/org/opendaylight/controller/md/sal/dom/store/impl/InMemoryDOMDataStore.java @@ -17,6 +17,7 @@ import java.util.concurrent.atomic.AtomicLong; import org.opendaylight.controller.md.sal.common.api.data.AsyncDataBroker.DataChangeScope; import org.opendaylight.controller.md.sal.common.api.data.AsyncDataChangeListener; import org.opendaylight.controller.md.sal.dom.store.impl.tree.ListenerRegistrationNode; +import org.opendaylight.controller.md.sal.dom.store.impl.tree.ModificationType; import org.opendaylight.controller.md.sal.dom.store.impl.tree.NodeModification; import org.opendaylight.controller.md.sal.dom.store.impl.tree.StoreMetadataNode; import org.opendaylight.controller.md.sal.dom.store.impl.tree.TreeNodeUtils; @@ -125,8 +126,9 @@ public class InMemoryDOMDataStore implements DOMStore, Identifiable, Sch } private synchronized DOMStoreThreePhaseCommitCohort submit( - final SnaphostBackedWriteTransaction snaphostBackedWriteTransaction) { - return new ThreePhaseCommitImpl(snaphostBackedWriteTransaction); + final SnaphostBackedWriteTransaction writeTx) { + LOG.debug("Tx: {} is submitted. Modifications: {}",writeTx.getIdentifier(),writeTx.getMutatedView()); + return new ThreePhaseCommitImpl(writeTx); } private Object nextIdentifier() { @@ -136,6 +138,9 @@ public class InMemoryDOMDataStore implements DOMStore, Identifiable, Sch private synchronized void commit(final DataAndMetadataSnapshot currentSnapshot, final StoreMetadataNode newDataTree, final Iterable listenerTasks) { LOG.debug("Updating Store snaphot version: {} with version:{}",currentSnapshot.getMetadataTree().getSubtreeVersion(),newDataTree.getSubtreeVersion()); + if(LOG.isTraceEnabled()) { + LOG.trace("Data Tree is {}",StoreUtils.toStringTree(newDataTree)); + } checkState(snapshot == currentSnapshot, "Store snapshot and transaction snapshot differs"); snapshot = DataAndMetadataSnapshot.builder() // .setMetadataTree(newDataTree) // @@ -156,6 +161,8 @@ public class InMemoryDOMDataStore implements DOMStore, Identifiable, Sch public SnapshotBackedReadTransaction(final Object identifier, final DataAndMetadataSnapshot snapshot) { this.identifier = identifier; this.stableSnapshot = snapshot; + LOG.debug("ReadOnly Tx: {} allocated with snapshot {}",identifier,snapshot.getMetadataTree().getSubtreeVersion()); + } @Override @@ -195,6 +202,7 @@ public class InMemoryDOMDataStore implements DOMStore, Identifiable, Sch this.identifier = identifier; mutableTree = MutableDataTree.from(snapshot, applyOper); this.store = store; + LOG.debug("Write Tx: {} allocated with snapshot {}",identifier,snapshot.getMetadataTree().getSubtreeVersion()); } @Override @@ -301,6 +309,9 @@ public class InMemoryDOMDataStore implements DOMStore, Identifiable, Sch @Override public ListenableFuture preCommit() { storeSnapshot = snapshot; + if(modification.getModificationType() == ModificationType.UNMODIFIED) { + return Futures.immediateFuture(null); + } return executor.submit(new Callable() { @@ -335,8 +346,12 @@ public class InMemoryDOMDataStore implements DOMStore, Identifiable, Sch @Override public ListenableFuture commit() { - checkState(proposedSubtree != null); - checkState(storeSnapshot != null); + if(modification.getModificationType() == ModificationType.UNMODIFIED) { + return Futures.immediateFuture(null); + } + + checkState(proposedSubtree != null,"Proposed subtree must be computed"); + checkState(storeSnapshot != null,"Proposed subtree must be computed"); // return ImmediateFuture<>; InMemoryDOMDataStore.this.commit(storeSnapshot, proposedSubtree.get(),listenerTasks); return Futures. immediateFuture(null); diff --git a/opendaylight/md-sal/sal-dom-broker/src/main/java/org/opendaylight/controller/md/sal/dom/store/impl/MutableDataTree.java b/opendaylight/md-sal/sal-dom-broker/src/main/java/org/opendaylight/controller/md/sal/dom/store/impl/MutableDataTree.java index 9fa32a68e5..f252744876 100644 --- a/opendaylight/md-sal/sal-dom-broker/src/main/java/org/opendaylight/controller/md/sal/dom/store/impl/MutableDataTree.java +++ b/opendaylight/md-sal/sal-dom-broker/src/main/java/org/opendaylight/controller/md/sal/dom/store/impl/MutableDataTree.java @@ -7,7 +7,6 @@ */ package org.opendaylight.controller.md.sal.dom.store.impl; -import static com.google.common.base.Preconditions.checkArgument; import static com.google.common.base.Preconditions.checkState; import java.util.Map.Entry; @@ -51,12 +50,8 @@ class MutableDataTree { } public Optional> read(final InstanceIdentifier path) { - Entry modification = TreeNodeUtils.findClosest(rootModification, path); - return getModifiedVersion(path, modification); - } + Entry modification = TreeNodeUtils.findClosestsOrFirstMatch(rootModification, path, NodeModification.IS_TERMINAL_PREDICATE); - private Optional> getModifiedVersion(final InstanceIdentifier path, - final Entry modification) { Optional result = resolveSnapshot(modification); if (result.isPresent()) { NormalizedNode data = result.get().getData(); @@ -76,20 +71,21 @@ class MutableDataTree { private Optional resolveSnapshot(final InstanceIdentifier path, final NodeModification modification) { try { + Optional> potentialSnapshot = modification.getSnapshotCache(); + if(potentialSnapshot.isPresent()) { + return potentialSnapshot.get(); + } return resolveModificationStrategy(path).apply(modification, modification.getOriginal(), StoreUtils.increase(snapshot.getMetadataTree().getSubtreeVersion())); } catch (Exception e) { - log.error("Could not create snapshot for {},", e); + log.error("Could not create snapshot for {}", path,e); throw e; } } private ModificationApplyOperation resolveModificationStrategy(final InstanceIdentifier path) { log.trace("Resolving modification apply strategy for {}", path); - Optional strategy = TreeNodeUtils.findNode(strategyTree, path); - checkArgument(strategy.isPresent(), - "Provided path %s is not supported by data store. No schema available for it.", path); - return strategy.get(); + return TreeNodeUtils.findNodeChecked(strategyTree, path); } private OperationWithModification resolveModificationFor(final InstanceIdentifier path) { @@ -118,4 +114,11 @@ class MutableDataTree { protected NodeModification getRootModification() { return rootModification; } + + @Override + public String toString() { + return "MutableDataTree [modification=" + rootModification + "]"; + } + + } diff --git a/opendaylight/md-sal/sal-dom-broker/src/main/java/org/opendaylight/controller/md/sal/dom/store/impl/SchemaAwareApplyOperation.java b/opendaylight/md-sal/sal-dom-broker/src/main/java/org/opendaylight/controller/md/sal/dom/store/impl/SchemaAwareApplyOperation.java index 6308b6f63e..fd8560773b 100644 --- a/opendaylight/md-sal/sal-dom-broker/src/main/java/org/opendaylight/controller/md/sal/dom/store/impl/SchemaAwareApplyOperation.java +++ b/opendaylight/md-sal/sal-dom-broker/src/main/java/org/opendaylight/controller/md/sal/dom/store/impl/SchemaAwareApplyOperation.java @@ -2,16 +2,20 @@ package org.opendaylight.controller.md.sal.dom.store.impl; import static com.google.common.base.Preconditions.checkArgument; +import java.util.Map; import java.util.Set; +import java.util.concurrent.ExecutionException; import org.opendaylight.controller.md.sal.dom.store.impl.tree.ModificationType; import org.opendaylight.controller.md.sal.dom.store.impl.tree.NodeModification; import org.opendaylight.controller.md.sal.dom.store.impl.tree.StoreMetadataNode; import org.opendaylight.controller.md.sal.dom.store.impl.tree.StoreNodeCompositeBuilder; +import org.opendaylight.yangtools.yang.data.api.InstanceIdentifier.AugmentationIdentifier; import org.opendaylight.yangtools.yang.data.api.InstanceIdentifier.NodeIdentifier; import org.opendaylight.yangtools.yang.data.api.InstanceIdentifier.NodeIdentifierWithPredicates; import org.opendaylight.yangtools.yang.data.api.InstanceIdentifier.NodeWithValue; import org.opendaylight.yangtools.yang.data.api.InstanceIdentifier.PathArgument; +import org.opendaylight.yangtools.yang.data.api.schema.AugmentationNode; import org.opendaylight.yangtools.yang.data.api.schema.ContainerNode; import org.opendaylight.yangtools.yang.data.api.schema.LeafNode; import org.opendaylight.yangtools.yang.data.api.schema.LeafSetEntryNode; @@ -20,12 +24,17 @@ import org.opendaylight.yangtools.yang.data.api.schema.MapEntryNode; import org.opendaylight.yangtools.yang.data.api.schema.MapNode; import org.opendaylight.yangtools.yang.data.api.schema.NormalizedNode; import org.opendaylight.yangtools.yang.data.api.schema.NormalizedNodeContainer; +import org.opendaylight.yangtools.yang.data.impl.schema.Builders; import org.opendaylight.yangtools.yang.data.impl.schema.builder.api.DataContainerNodeBuilder; import org.opendaylight.yangtools.yang.data.impl.schema.builder.api.NormalizedNodeContainerBuilder; +import org.opendaylight.yangtools.yang.data.impl.schema.builder.impl.ImmutableChoiceNodeBuilder; import org.opendaylight.yangtools.yang.data.impl.schema.builder.impl.ImmutableContainerNodeBuilder; import org.opendaylight.yangtools.yang.data.impl.schema.builder.impl.ImmutableLeafSetNodeBuilder; import org.opendaylight.yangtools.yang.data.impl.schema.builder.impl.ImmutableMapEntryNodeBuilder; import org.opendaylight.yangtools.yang.data.impl.schema.builder.impl.ImmutableMapNodeBuilder; +import org.opendaylight.yangtools.yang.model.api.AugmentationSchema; +import org.opendaylight.yangtools.yang.model.api.AugmentationTarget; +import org.opendaylight.yangtools.yang.model.api.ChoiceCaseNode; import org.opendaylight.yangtools.yang.model.api.ChoiceNode; import org.opendaylight.yangtools.yang.model.api.ContainerSchemaNode; import org.opendaylight.yangtools.yang.model.api.DataNodeContainer; @@ -36,9 +45,10 @@ import org.opendaylight.yangtools.yang.model.api.ListSchemaNode; import com.google.common.base.Function; import com.google.common.base.Optional; -import com.google.common.cache.Cache; import com.google.common.cache.CacheBuilder; import com.google.common.cache.CacheLoader; +import com.google.common.cache.LoadingCache; +import com.google.common.collect.ImmutableMap; import com.google.common.collect.ImmutableSet; import com.google.common.collect.ImmutableSet.Builder; import com.google.common.primitives.UnsignedLong; @@ -60,11 +70,26 @@ public abstract class SchemaAwareApplyOperation implements ModificationApplyOper throw new IllegalArgumentException("Not supported schema node type for " + schemaNode.getClass()); } - @Override - public Optional getChild(final PathArgument child) { - throw new IllegalArgumentException(); + public static SchemaAwareApplyOperation from(final DataNodeContainer resolvedTree, + final AugmentationTarget augSchemas, final AugmentationIdentifier identifier) { + AugmentationSchema augSchema = null; + allAugments : for (AugmentationSchema potential : augSchemas.getAvailableAugmentations()) { + boolean containsAll = true; + for(DataSchemaNode child : potential.getChildNodes()) { + if(identifier.getPossibleChildNames().contains(child.getQName())) { + augSchema = potential; + break allAugments; + } + } + } + if(augSchema != null) { + return new AugmentationModificationStrategy(augSchema,resolvedTree); + } + return null; } + + protected final ModificationApplyOperation resolveChildOperation(final PathArgument child) { Optional potential = getChild(child); checkArgument(potential.isPresent(), "Operation for child %s is not defined.", child); @@ -123,13 +148,14 @@ public abstract class SchemaAwareApplyOperation implements ModificationApplyOper @Override public final Optional apply(final NodeModification modification, final Optional currentMeta, final UnsignedLong subtreeVersion) { + switch (modification.getModificationType()) { case DELETE: - return Optional.absent(); + return modification.storeSnapshot(Optional.absent()); case SUBTREE_MODIFIED: - return Optional.of(applySubtreeChange(modification, currentMeta.get(), subtreeVersion)); + return modification.storeSnapshot(Optional.of(applySubtreeChange(modification, currentMeta.get(), subtreeVersion))); case WRITE: - return Optional.of(applyWrite(modification, currentMeta, subtreeVersion)); + return modification.storeSnapshot(Optional.of(applyWrite(modification, currentMeta, subtreeVersion))); case UNMODIFIED: return currentMeta; default: @@ -217,13 +243,12 @@ public abstract class SchemaAwareApplyOperation implements ModificationApplyOper this.nodeClass = nodeClass; } - @Override public void verifyStructure(final NodeModification modification) throws IllegalArgumentException { - if(modification.getModificationType() == ModificationType.WRITE) { + if (modification.getModificationType() == ModificationType.WRITE) { } - for(NodeModification childModification : modification.getModifications()) { + for (NodeModification childModification : modification.getModifications()) { resolveChildOperation(childModification.getIdentifier()).verifyStructure(childModification); } } @@ -234,7 +259,7 @@ public abstract class SchemaAwareApplyOperation implements ModificationApplyOper checkArgument(nodeClass.isInstance(writenValue), "Node should must be of type %s", nodeClass); checkArgument(writenValue instanceof NormalizedNodeContainer); NormalizedNodeContainer writenCont = (NormalizedNodeContainer) writenValue; - for(Object child : writenCont.getValue()) { + for (Object child : writenCont.getValue()) { checkArgument(child instanceof NormalizedNode); NormalizedNode childNode = (NormalizedNode) child; } @@ -277,7 +302,6 @@ public abstract class SchemaAwareApplyOperation implements ModificationApplyOper @SuppressWarnings("rawtypes") NormalizedNodeContainerBuilder dataBuilder = createBuilder(modification.getIdentifier()); StoreNodeCompositeBuilder builder = StoreNodeCompositeBuilder.from(dataBuilder) - // .setIdentifier(modification.getIdentifier()).setNodeVersion(currentMeta.getNodeVersion()) .setSubtreeVersion(updatedSubtreeVersion); // We process preexisting nodes @@ -348,17 +372,21 @@ public abstract class SchemaAwareApplyOperation implements ModificationApplyOper NormalizedNodeContainerModificationStrategy { private final T schema; - private final Cache childCache = CacheBuilder.newBuilder() - .build(CacheLoader.from(new Function() { - - @Override - public ModificationApplyOperation apply(final PathArgument identifier) { - DataSchemaNode child = schema.getDataChildByName(identifier.getNodeType()); - if (child == null || child.isAugmenting()) { - return null; + private final LoadingCache childCache = CacheBuilder.newBuilder().build( + CacheLoader.from(new Function() { + + @Override + public ModificationApplyOperation apply(final PathArgument identifier) { + if (identifier instanceof AugmentationIdentifier && schema instanceof AugmentationTarget) { + return from(schema, (AugmentationTarget) schema, (AugmentationIdentifier) identifier); + } + + DataSchemaNode child = schema.getDataChildByName(identifier.getNodeType()); + if (child == null) { + return null; + } + return from(child); } - return from(child); - } })); protected DataNodeContainerModificationStrategy(final T schema, @@ -373,11 +401,11 @@ public abstract class SchemaAwareApplyOperation implements ModificationApplyOper @Override public Optional getChild(final PathArgument identifier) { - DataSchemaNode child = schema.getDataChildByName(identifier.getNodeType()); - if (child == null || child.isAugmenting()) { + try { + return Optional. fromNullable(childCache.get(identifier)); + } catch (ExecutionException e) { return Optional.absent(); } - return Optional. of(from(child)); } @Override @@ -408,20 +436,52 @@ public abstract class SchemaAwareApplyOperation implements ModificationApplyOper } + public static class AugmentationModificationStrategy extends + DataNodeContainerModificationStrategy { + + protected AugmentationModificationStrategy(final AugmentationSchema schema, final DataNodeContainer resolved) { + super(schema, AugmentationNode.class); + // FIXME: Use resolved children instead of unresolved. + + } + + + @Override + protected DataContainerNodeBuilder createBuilder(final PathArgument identifier) { + return Builders.augmentationBuilder().withNodeIdentifier((AugmentationIdentifier) identifier); + } + + } + public static class ChoiceModificationStrategy extends NormalizedNodeContainerModificationStrategy { private final ChoiceNode schema; + private final Map childNodes; public ChoiceModificationStrategy(final ChoiceNode schemaNode) { super(org.opendaylight.yangtools.yang.data.api.schema.ChoiceNode.class); this.schema = schemaNode; + ImmutableMap.Builder child = ImmutableMap.builder(); + + for(ChoiceCaseNode caze : schemaNode.getCases()) { + for(DataSchemaNode cazeChild : caze.getChildNodes()) { + SchemaAwareApplyOperation childNode = from(cazeChild); + child.put(new NodeIdentifier(cazeChild.getQName()),childNode); + } + } + childNodes = child.build(); + } + + @Override + public Optional getChild(final PathArgument child) { + return Optional.fromNullable(childNodes.get(child)); } @Override @SuppressWarnings("rawtypes") protected DataContainerNodeBuilder createBuilder(final PathArgument identifier) { checkArgument(identifier instanceof NodeIdentifier); - return ImmutableContainerNodeBuilder.create().withNodeIdentifier((NodeIdentifier) identifier); + return ImmutableChoiceNodeBuilder.create().withNodeIdentifier((NodeIdentifier) identifier); } } diff --git a/opendaylight/md-sal/sal-dom-broker/src/main/java/org/opendaylight/controller/md/sal/dom/store/impl/StoreUtils.java b/opendaylight/md-sal/sal-dom-broker/src/main/java/org/opendaylight/controller/md/sal/dom/store/impl/StoreUtils.java index 4ad941ae95..df58d62dd4 100644 --- a/opendaylight/md-sal/sal-dom-broker/src/main/java/org/opendaylight/controller/md/sal/dom/store/impl/StoreUtils.java +++ b/opendaylight/md-sal/sal-dom-broker/src/main/java/org/opendaylight/controller/md/sal/dom/store/impl/StoreUtils.java @@ -8,10 +8,14 @@ import org.opendaylight.controller.md.sal.common.api.data.AsyncDataChangeEvent; import org.opendaylight.controller.md.sal.dom.store.impl.tree.StoreMetadataNode; import org.opendaylight.yangtools.concepts.Identifiable; import org.opendaylight.yangtools.yang.data.api.InstanceIdentifier; +import org.opendaylight.yangtools.yang.data.api.InstanceIdentifier.AugmentationIdentifier; +import org.opendaylight.yangtools.yang.data.api.InstanceIdentifier.NodeIdentifierWithPredicates; import org.opendaylight.yangtools.yang.data.api.InstanceIdentifier.PathArgument; import org.opendaylight.yangtools.yang.data.api.schema.NormalizedNode; +import org.opendaylight.yangtools.yang.data.api.schema.NormalizedNodeContainer; import com.google.common.base.Function; +import com.google.common.base.Strings; import com.google.common.collect.FluentIterable; import com.google.common.collect.ImmutableList; import com.google.common.collect.ImmutableMap; @@ -93,4 +97,38 @@ public final class StoreUtils { return FluentIterable.from(children).transform(StoreUtils.identifierExtractor()).toSet(); } + public static String toStringTree(final StoreMetadataNode metaNode) { + StringBuilder builder = new StringBuilder(); + toStringTree(builder, metaNode,0); + return builder.toString(); + + } + + private static void toStringTree(final StringBuilder builder, final StoreMetadataNode metaNode,final int offset) { + String prefix = Strings.repeat(" ", offset); + builder.append(prefix).append(toStringTree(metaNode.getIdentifier())); + NormalizedNode dataNode = metaNode.getData(); + if(dataNode instanceof NormalizedNodeContainer) { + builder.append(" {").append("\n"); + for(StoreMetadataNode child : metaNode.getChildren()) { + toStringTree(builder, child, offset+4); + } + builder.append(prefix).append("}"); + } else { + builder.append(" ").append(dataNode.getValue()); + } + builder.append("\n"); + } + + private static String toStringTree(final PathArgument identifier) { + if( identifier instanceof NodeIdentifierWithPredicates) { + StringBuilder builder = new StringBuilder(); + builder.append(identifier.getNodeType().getLocalName()); + builder.append(((NodeIdentifierWithPredicates) identifier).getKeyValues().values()); + return builder.toString(); + } else if (identifier instanceof AugmentationIdentifier) { + return "augmentation"; + } + return identifier.getNodeType().getLocalName(); + } } diff --git a/opendaylight/md-sal/sal-dom-broker/src/main/java/org/opendaylight/controller/md/sal/dom/store/impl/tree/ListenerRegistrationNode.java b/opendaylight/md-sal/sal-dom-broker/src/main/java/org/opendaylight/controller/md/sal/dom/store/impl/tree/ListenerRegistrationNode.java index d6d1ca309f..ee49effd31 100644 --- a/opendaylight/md-sal/sal-dom-broker/src/main/java/org/opendaylight/controller/md/sal/dom/store/impl/tree/ListenerRegistrationNode.java +++ b/opendaylight/md-sal/sal-dom-broker/src/main/java/org/opendaylight/controller/md/sal/dom/store/impl/tree/ListenerRegistrationNode.java @@ -1,8 +1,8 @@ package org.opendaylight.controller.md.sal.dom.store.impl.tree; import java.util.HashMap; +import java.util.HashSet; import java.util.Map; -import java.util.concurrent.ConcurrentSkipListSet; import org.opendaylight.controller.md.sal.common.api.data.AsyncDataBroker.DataChangeScope; import org.opendaylight.controller.md.sal.common.api.data.AsyncDataChangeListener; @@ -20,7 +20,7 @@ public class ListenerRegistrationNode implements StoreTreeNode children; private final PathArgument identifier; - private final ConcurrentSkipListSet> listeners; + private final HashSet> listeners; private ListenerRegistrationNode(final PathArgument identifier) { this(null,identifier); @@ -30,7 +30,7 @@ public class ListenerRegistrationNode implements StoreTreeNode(); - listeners = new ConcurrentSkipListSet<>(); + listeners = new HashSet<>(); } public final static ListenerRegistrationNode createRoot() { diff --git a/opendaylight/md-sal/sal-dom-broker/src/main/java/org/opendaylight/controller/md/sal/dom/store/impl/tree/NodeModification.java b/opendaylight/md-sal/sal-dom-broker/src/main/java/org/opendaylight/controller/md/sal/dom/store/impl/tree/NodeModification.java index 764afcb3e1..a0c15eb4a0 100644 --- a/opendaylight/md-sal/sal-dom-broker/src/main/java/org/opendaylight/controller/md/sal/dom/store/impl/tree/NodeModification.java +++ b/opendaylight/md-sal/sal-dom-broker/src/main/java/org/opendaylight/controller/md/sal/dom/store/impl/tree/NodeModification.java @@ -17,6 +17,8 @@ import org.opendaylight.yangtools.yang.data.api.InstanceIdentifier.PathArgument; import org.opendaylight.yangtools.yang.data.api.schema.NormalizedNode; import com.google.common.base.Optional; +import com.google.common.base.Predicate; +import com.google.common.primitives.UnsignedLong; /** * Node Modification Node and Tree @@ -30,6 +32,12 @@ import com.google.common.base.Optional; */ public class NodeModification implements StoreTreeNode, Identifiable { + public static final Predicate IS_TERMINAL_PREDICATE = new Predicate() { + @Override + public boolean apply(final NodeModification input) { + return input.getModificationType() == ModificationType.WRITE || input.getModificationType() == ModificationType.DELETE; + } + }; private final PathArgument identifier; private ModificationType modificationType = ModificationType.UNMODIFIED; @@ -38,7 +46,8 @@ public class NodeModification implements StoreTreeNode, Identi private NormalizedNode value; - private StoreMetadataNode snapshotCache; + private UnsignedLong subtreeVersion; + private Optional snapshotCache; private final Map childModification; @@ -109,6 +118,7 @@ public class NodeModification implements StoreTreeNode, Identi */ public synchronized NodeModification modifyChild(final PathArgument child) { checkSealed(); + clearSnapshot(); if(modificationType == ModificationType.UNMODIFIED) { updateModificationType(ModificationType.SUBTREE_MODIFIED); } @@ -143,6 +153,7 @@ public class NodeModification implements StoreTreeNode, Identi */ public synchronized void delete() { checkSealed(); + clearSnapshot(); updateModificationType(ModificationType.DELETE); childModification.clear(); this.value = null; @@ -156,6 +167,7 @@ public class NodeModification implements StoreTreeNode, Identi */ public synchronized void write(final NormalizedNode value) { checkSealed(); + clearSnapshot(); updateModificationType(ModificationType.WRITE); childModification.clear(); this.value = value; @@ -167,6 +179,7 @@ public class NodeModification implements StoreTreeNode, Identi public synchronized void seal() { sealed = true; + clearSnapshot(); for(NodeModification child : childModification.values()) { child.seal(); } @@ -176,6 +189,15 @@ public class NodeModification implements StoreTreeNode, Identi snapshotCache = null; } + public Optional storeSnapshot(final Optional snapshot) { + snapshotCache = snapshot; + return snapshot; + } + + public Optional> getSnapshotCache() { + return Optional.fromNullable(snapshotCache); + } + public boolean hasAdditionalModifications() { return !childModification.isEmpty(); } @@ -188,7 +210,7 @@ public class NodeModification implements StoreTreeNode, Identi @Override public String toString() { return "NodeModification [identifier=" + identifier + ", modificationType=" - + modificationType + ", value=" + value + ", childModification=" + childModification + "]"; + + modificationType + ", childModification=" + childModification + "]"; } public static NodeModification createUnmodified(final StoreMetadataNode metadataTree) { diff --git a/opendaylight/md-sal/sal-dom-broker/src/main/java/org/opendaylight/controller/md/sal/dom/store/impl/tree/TreeNodeUtils.java b/opendaylight/md-sal/sal-dom-broker/src/main/java/org/opendaylight/controller/md/sal/dom/store/impl/tree/TreeNodeUtils.java index dc89309877..a2a706a9da 100644 --- a/opendaylight/md-sal/sal-dom-broker/src/main/java/org/opendaylight/controller/md/sal/dom/store/impl/tree/TreeNodeUtils.java +++ b/opendaylight/md-sal/sal-dom-broker/src/main/java/org/opendaylight/controller/md/sal/dom/store/impl/tree/TreeNodeUtils.java @@ -8,13 +8,18 @@ package org.opendaylight.controller.md.sal.dom.store.impl.tree; import java.util.AbstractMap.SimpleEntry; +import java.util.ArrayList; import java.util.Iterator; +import java.util.List; import java.util.Map; import org.opendaylight.yangtools.yang.data.api.InstanceIdentifier; import org.opendaylight.yangtools.yang.data.api.InstanceIdentifier.PathArgument; import com.google.common.base.Optional; +import com.google.common.base.Preconditions; +import com.google.common.base.Predicate; +import com.google.common.base.Predicates; public class TreeNodeUtils { @@ -35,6 +40,19 @@ public class TreeNodeUtils { return current; } + + public static > T findNodeChecked(final T tree, final InstanceIdentifier path) { + T current = tree; + List nested = new ArrayList<>(path.getPath()); + for(PathArgument pathArg : path.getPath()) { + Optional potential = current.getChild(pathArg); + nested.add(pathArg); + Preconditions.checkArgument(potential.isPresent(),"Child %s is not present in tree.",nested); + current = potential.get(); + } + return current; + } + /** * Finds a node or closest parent in the tree * @@ -44,12 +62,16 @@ public class TreeNodeUtils { * */ public static > Map.Entry findClosest(final T tree, final InstanceIdentifier path) { + return findClosestsOrFirstMatch(tree, path, Predicates.alwaysFalse()); + } + + public static > Map.Entry findClosestsOrFirstMatch(final T tree, final InstanceIdentifier path, final Predicate predicate) { Optional parent = Optional.of(tree); Optional current = Optional. of(tree); int nesting = 0; Iterator pathIter = path.getPath().iterator(); - while (current.isPresent() && pathIter.hasNext()) { + while (current.isPresent() && pathIter.hasNext() && !predicate.apply(current.get())) { parent = current; current = current.get().getChild(pathIter.next()); nesting++; @@ -62,6 +84,7 @@ public class TreeNodeUtils { // so this prat of code is never triggered, in cases nesting == 0; final InstanceIdentifier parentPath = new InstanceIdentifier(path.getPath().subList(0, nesting - 1)); return new SimpleEntry(parentPath,parent.get()); + } public static > Optional getChild(final Optional parent,final PathArgument child) { diff --git a/opendaylight/md-sal/sal-dom-broker/src/main/java/org/opendaylight/controller/sal/dom/broker/BrokerConfigActivator.xtend b/opendaylight/md-sal/sal-dom-broker/src/main/java/org/opendaylight/controller/sal/dom/broker/BrokerConfigActivator.xtend index 6b5f5acb19..9cbf4282e4 100644 --- a/opendaylight/md-sal/sal-dom-broker/src/main/java/org/opendaylight/controller/sal/dom/broker/BrokerConfigActivator.xtend +++ b/opendaylight/md-sal/sal-dom-broker/src/main/java/org/opendaylight/controller/sal/dom/broker/BrokerConfigActivator.xtend @@ -22,13 +22,22 @@ import org.osgi.framework.BundleContext import org.osgi.framework.ServiceRegistration import org.opendaylight.controller.sal.dom.broker.impl.SchemaContextProviders import org.opendaylight.controller.sal.core.api.RpcProvisionRegistry +import org.opendaylight.controller.md.sal.dom.broker.impl.compat.BackwardsCompatibleDataBroker +import org.opendaylight.controller.md.sal.dom.broker.impl.DOMDataBrokerImpl +import com.google.common.util.concurrent.MoreExecutors +import com.google.common.collect.ImmutableMap +import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType +import org.opendaylight.controller.sal.core.spi.data.DOMStore +import org.opendaylight.controller.md.sal.dom.store.impl.InMemoryDOMDataStore +import java.util.concurrent.Executors +import org.opendaylight.controller.md.sal.dom.api.DOMDataBroker class BrokerConfigActivator implements AutoCloseable { private static val ROOT = InstanceIdentifier.builder().toInstance(); @Property - private var DataBrokerImpl dataService; + private var DataProviderService dataService; private var ServiceRegistration dataReg; private var ServiceRegistration dataProviderReg; @@ -40,7 +49,7 @@ class BrokerConfigActivator implements AutoCloseable { SchemaAwareDataStoreAdapter wrappedStore - public def void start(BrokerImpl broker, DataStore store, BundleContext context) { + public def void start(BrokerImpl broker, DataStore store, DOMDataBroker asyncBroker,BundleContext context) { val emptyProperties = new Hashtable(); broker.setBundleContext(context); @@ -48,27 +57,32 @@ class BrokerConfigActivator implements AutoCloseable { schemaService = context.getService(serviceRef); broker.setRouter(new SchemaAwareRpcBroker("/", SchemaContextProviders.fromSchemaService(schemaService))); - - dataService = new DataBrokerImpl(); - //dataService.setExecutor(broker.getExecutor()); - - dataReg = context.registerService(DataBrokerService, dataService, emptyProperties); - dataProviderReg = context.registerService(DataProviderService, dataService, emptyProperties); - - wrappedStore = new SchemaAwareDataStoreAdapter(); - wrappedStore.changeDelegate(store); - wrappedStore.setValidationEnabled(false); - - context.registerService(SchemaServiceListener, wrappedStore, emptyProperties) - - dataService.registerConfigurationReader(ROOT, wrappedStore); - dataService.registerCommitHandler(ROOT, wrappedStore); - dataService.registerOperationalReader(ROOT, wrappedStore); + + + if(asyncBroker == null) { + dataService = new DataBrokerImpl(); + dataProviderReg = context.registerService(DataProviderService, dataService, emptyProperties); + + wrappedStore = new SchemaAwareDataStoreAdapter(); + wrappedStore.changeDelegate(store); + wrappedStore.setValidationEnabled(false); + context.registerService(SchemaServiceListener, wrappedStore, emptyProperties) + + dataService.registerConfigurationReader(ROOT, wrappedStore); + dataService.registerCommitHandler(ROOT, wrappedStore); + dataService.registerOperationalReader(ROOT, wrappedStore); + } else { + val compatibleDataBroker = new BackwardsCompatibleDataBroker(asyncBroker); + context.registerService(SchemaServiceListener,compatibleDataBroker,emptyProperties); + dataService = compatibleDataBroker; + } + + +// mountService = new MountPointManagerImpl(); - mountService.setDataBroker(dataService); - - mountReg = context.registerService(MountService, mountService, emptyProperties); + dataReg = context.registerService(DataBrokerService, dataService, emptyProperties); + mountReg = context.registerService(MountService, mountService, emptyProperties); mountProviderReg = context.registerService(MountProvisionService, mountService, emptyProperties); rpcProvisionRegistryReg = context.registerService(RpcProvisionRegistry, broker.getRouter(), emptyProperties); diff --git a/opendaylight/md-sal/sal-dom-broker/src/main/java/org/opendaylight/controller/sal/dom/broker/GlobalBundleScanningSchemaServiceImpl.java b/opendaylight/md-sal/sal-dom-broker/src/main/java/org/opendaylight/controller/sal/dom/broker/GlobalBundleScanningSchemaServiceImpl.java index bf35037b22..a60a30d256 100644 --- a/opendaylight/md-sal/sal-dom-broker/src/main/java/org/opendaylight/controller/sal/dom/broker/GlobalBundleScanningSchemaServiceImpl.java +++ b/opendaylight/md-sal/sal-dom-broker/src/main/java/org/opendaylight/controller/sal/dom/broker/GlobalBundleScanningSchemaServiceImpl.java @@ -46,7 +46,7 @@ public class GlobalBundleScanningSchemaServiceImpl implements // private ListenerRegistry listeners; private BundleContext context; - private BundleScanner scanner = new BundleScanner(); + private final BundleScanner scanner = new BundleScanner(); private BundleTracker>> bundleTracker; @@ -60,7 +60,7 @@ public class GlobalBundleScanningSchemaServiceImpl implements // return listeners; } - public void setListeners(ListenerRegistry listeners) { + public void setListeners(final ListenerRegistry listeners) { this.listeners = listeners; } @@ -68,7 +68,7 @@ public class GlobalBundleScanningSchemaServiceImpl implements // return context; } - public void setContext(BundleContext context) { + public void setContext(final BundleContext context) { this.context = context; } @@ -92,12 +92,13 @@ public class GlobalBundleScanningSchemaServiceImpl implements // return getGlobalContext(); } + @Override public SchemaContext getGlobalContext() { return contextResolver.getSchemaContext().orNull(); } @Override - public void addModule(Module module) { + public void addModule(final Module module) { throw new UnsupportedOperationException(); } @@ -107,12 +108,16 @@ public class GlobalBundleScanningSchemaServiceImpl implements // } @Override - public void removeModule(Module module) { + public void removeModule(final Module module) { throw new UnsupportedOperationException(); } @Override - public ListenerRegistration registerSchemaServiceListener(SchemaServiceListener listener) { + public ListenerRegistration registerSchemaServiceListener(final SchemaServiceListener listener) { + Optional potentialCtx = contextResolver.getSchemaContext(); + if(potentialCtx.isPresent()) { + listener.onGlobalContextUpdated(potentialCtx.get()); + } return listeners.register(listener); } @@ -128,7 +133,7 @@ public class GlobalBundleScanningSchemaServiceImpl implements // } - private void updateContext(SchemaContext snapshot) { + private void updateContext(final SchemaContext snapshot) { Object[] services = listenerTracker.getServices(); if (services != null) { for (Object rawListener : services) { @@ -151,7 +156,7 @@ public class GlobalBundleScanningSchemaServiceImpl implements // private class BundleScanner implements BundleTrackerCustomizer>> { @Override - public ImmutableSet> addingBundle(Bundle bundle, BundleEvent event) { + public ImmutableSet> addingBundle(final Bundle bundle, final BundleEvent event) { if (bundle.getBundleId() == 0) { return ImmutableSet.of(); @@ -172,7 +177,7 @@ public class GlobalBundleScanningSchemaServiceImpl implements // } @Override - public void modifiedBundle(Bundle bundle, BundleEvent event, ImmutableSet> object) { + public void modifiedBundle(final Bundle bundle, final BundleEvent event, final ImmutableSet> object) { logger.debug("Modified bundle {} {} {}", bundle, event, object); } @@ -183,7 +188,7 @@ public class GlobalBundleScanningSchemaServiceImpl implements // */ @Override - public synchronized void removedBundle(Bundle bundle, BundleEvent event, ImmutableSet> urls) { + public synchronized void removedBundle(final Bundle bundle, final BundleEvent event, final ImmutableSet> urls) { for (Registration url : urls) { try { url.close(); @@ -196,7 +201,7 @@ public class GlobalBundleScanningSchemaServiceImpl implements // } @Override - public SchemaServiceListener addingService(ServiceReference reference) { + public SchemaServiceListener addingService(final ServiceReference reference) { SchemaServiceListener listener = context.getService(reference); SchemaContext _ctxContext = getGlobalContext(); @@ -217,12 +222,12 @@ public class GlobalBundleScanningSchemaServiceImpl implements // } @Override - public void modifiedService(ServiceReference reference, SchemaServiceListener service) { + public void modifiedService(final ServiceReference reference, final SchemaServiceListener service) { // NOOP } @Override - public void removedService(ServiceReference reference, SchemaServiceListener service) { + public void removedService(final ServiceReference reference, final SchemaServiceListener service) { context.ungetService(reference); } } diff --git a/opendaylight/md-sal/sal-dom-broker/src/main/java/org/opendaylight/controller/sal/dom/broker/osgi/DOMDataBrokerProxy.java b/opendaylight/md-sal/sal-dom-broker/src/main/java/org/opendaylight/controller/sal/dom/broker/osgi/DOMDataBrokerProxy.java new file mode 100644 index 0000000000..70db71f3ac --- /dev/null +++ b/opendaylight/md-sal/sal-dom-broker/src/main/java/org/opendaylight/controller/sal/dom/broker/osgi/DOMDataBrokerProxy.java @@ -0,0 +1,41 @@ +package org.opendaylight.controller.sal.dom.broker.osgi; + +import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType; +import org.opendaylight.controller.md.sal.dom.api.DOMDataBroker; +import org.opendaylight.controller.md.sal.dom.api.DOMDataChangeListener; +import org.opendaylight.controller.md.sal.dom.api.DOMDataReadTransaction; +import org.opendaylight.controller.md.sal.dom.api.DOMDataReadWriteTransaction; +import org.opendaylight.controller.md.sal.dom.api.DOMDataWriteTransaction; +import org.opendaylight.yangtools.concepts.ListenerRegistration; +import org.opendaylight.yangtools.yang.data.api.InstanceIdentifier; +import org.osgi.framework.ServiceReference; + +public class DOMDataBrokerProxy extends AbstractBrokerServiceProxy implements DOMDataBroker { + + public DOMDataBrokerProxy(final ServiceReference ref, final DOMDataBroker delegate) { + super(ref, delegate); + } + + @Override + public DOMDataReadTransaction newReadOnlyTransaction() { + return getDelegate().newReadOnlyTransaction(); + } + + @Override + public DOMDataReadWriteTransaction newReadWriteTransaction() { + return getDelegate().newReadWriteTransaction(); + } + + @Override + public DOMDataWriteTransaction newWriteOnlyTransaction() { + return getDelegate().newWriteOnlyTransaction(); + } + + @Override + public ListenerRegistration registerDataChangeListener(final LogicalDatastoreType store, + final InstanceIdentifier path, final DOMDataChangeListener listener, + final org.opendaylight.controller.md.sal.common.api.data.AsyncDataBroker.DataChangeScope triggeringScope) { + return getDelegate().registerDataChangeListener(store, path, listener, triggeringScope); + } + +} diff --git a/opendaylight/md-sal/sal-dom-broker/src/main/java/org/opendaylight/controller/sal/dom/broker/osgi/ProxyFactory.xtend b/opendaylight/md-sal/sal-dom-broker/src/main/java/org/opendaylight/controller/sal/dom/broker/osgi/ProxyFactory.xtend index 5b97443b92..d0afc3f47d 100644 --- a/opendaylight/md-sal/sal-dom-broker/src/main/java/org/opendaylight/controller/sal/dom/broker/osgi/ProxyFactory.xtend +++ b/opendaylight/md-sal/sal-dom-broker/src/main/java/org/opendaylight/controller/sal/dom/broker/osgi/ProxyFactory.xtend @@ -16,6 +16,7 @@ import org.opendaylight.controller.sal.core.api.notify.NotificationService import org.opendaylight.controller.sal.core.api.model.SchemaService import org.opendaylight.controller.sal.core.api.mount.MountProvisionService import org.opendaylight.controller.sal.core.api.RpcProvisionRegistry +import org.opendaylight.controller.md.sal.dom.api.DOMDataBroker class ProxyFactory { @@ -23,6 +24,7 @@ class ProxyFactory { return createProxyImpl(serviceRef, service) as T; } + private static def dispatch createProxyImpl(ServiceReference ref, DataBrokerService service) { new DataBrokerServiceProxy(ref as ServiceReference, service); } @@ -51,6 +53,11 @@ class ProxyFactory { private static def dispatch createProxyImpl(ServiceReference ref, RpcProvisionRegistry service) { new RpcProvisionRegistryProxy(ref as ServiceReference, service); } + + private static def dispatch createProxyImpl(ServiceReference ref, DOMDataBroker service) { + new DOMDataBrokerProxy(ref as ServiceReference, service) + } + private static def dispatch createProxyImpl(ServiceReference reference, BrokerService service) { throw new IllegalArgumentException("Not supported class"); diff --git a/opendaylight/md-sal/sal-dom-broker/src/main/yang/opendaylight-dom-broker-impl.yang b/opendaylight/md-sal/sal-dom-broker/src/main/yang/opendaylight-dom-broker-impl.yang index 9ae9c9ce6d..3c29fe5885 100644 --- a/opendaylight/md-sal/sal-dom-broker/src/main/yang/opendaylight-dom-broker-impl.yang +++ b/opendaylight/md-sal/sal-dom-broker/src/main/yang/opendaylight-dom-broker-impl.yang @@ -21,6 +21,12 @@ module opendaylight-sal-dom-broker-impl { config:java-name-prefix DomBrokerImpl; } + + identity dom-inmemory-data-broker { + base config:module-type; + config:provided-service sal:dom-async-data-broker; + } + identity hash-map-data-store { base config:module-type; config:provided-service sal:dom-data-store; @@ -39,11 +45,37 @@ module opendaylight-sal-dom-broker-impl { container data-store { uses config:service-ref { refine type { - mandatory true; + mandatory false; config:required-identity sal:dom-data-store; } } } + + container async-data-broker { + uses config:service-ref { + refine type { + mandatory false; + config:required-identity sal:dom-async-data-broker; + } + } + + } + } + } + + augment "/config:modules/config:module/config:configuration" { + case dom-inmemory-data-broker { + when "/config:modules/config:module/config:type = 'dom-inmemory-data-broker'"; + + container schema-service { + uses config:service-ref { + refine type { + mandatory false; + config:required-identity sal:schema-service; + } + } + + } } } diff --git a/opendaylight/md-sal/sal-dom-broker/src/test/java/org/opendaylight/controller/md/sal/dom/broker/impl/DataNormalizerTest.java b/opendaylight/md-sal/sal-dom-broker/src/test/java/org/opendaylight/controller/md/sal/dom/broker/impl/DataNormalizerTest.java new file mode 100644 index 0000000000..9aa558b5ac --- /dev/null +++ b/opendaylight/md-sal/sal-dom-broker/src/test/java/org/opendaylight/controller/md/sal/dom/broker/impl/DataNormalizerTest.java @@ -0,0 +1,60 @@ +package org.opendaylight.controller.md.sal.dom.broker.impl; + +import static org.junit.Assert.assertNotNull; + +import org.junit.Test; +import org.opendaylight.controller.md.sal.common.impl.util.compat.DataNormalizer; +import org.opendaylight.controller.md.sal.dom.store.impl.TestModel; +import org.opendaylight.yangtools.yang.data.api.InstanceIdentifier; +import org.opendaylight.yangtools.yang.data.api.InstanceIdentifier.NodeIdentifier; +import org.opendaylight.yangtools.yang.data.api.InstanceIdentifier.NodeIdentifierWithPredicates; +import org.opendaylight.yangtools.yang.data.api.Node; +import org.opendaylight.yangtools.yang.data.api.schema.ChoiceNode; +import org.opendaylight.yangtools.yang.data.api.schema.MapEntryNode; +import org.opendaylight.yangtools.yang.data.impl.schema.Builders; +import org.opendaylight.yangtools.yang.data.impl.schema.ImmutableNodes; +import org.opendaylight.yangtools.yang.model.api.SchemaContext; + +public class DataNormalizerTest { + + private static final Short OUTER_LIST_ID = (short)10; + + private static final InstanceIdentifier OUTER_LIST_PATH_LEGACY = InstanceIdentifier.builder(TestModel.TEST_QNAME) + .nodeWithKey(TestModel.OUTER_LIST_QNAME, TestModel.ID_QNAME,OUTER_LIST_ID).build(); + + private static final InstanceIdentifier LEAF_TWO_PATH_LEGACY = InstanceIdentifier.builder(OUTER_LIST_PATH_LEGACY) + .node(TestModel.TWO_QNAME).build(); + + private static final ChoiceNode OUTER_CHOICE_ITEM = Builders.choiceBuilder() + .withNodeIdentifier(new NodeIdentifier(TestModel.OUTER_CHOICE_QNAME)) + .withChild(ImmutableNodes.leafNode(TestModel.TWO_QNAME, "two")) + .withChild(ImmutableNodes.leafNode(TestModel.THREE_QNAME, "three")) + .build(); + + private static final MapEntryNode OUTER_LIST_WITHOUT_CHOICE = Builders.mapEntryBuilder() + .withNodeIdentifier(new NodeIdentifierWithPredicates(TestModel.OUTER_LIST_QNAME, TestModel.ID_QNAME,OUTER_LIST_ID)) + .withChild(ImmutableNodes.leafNode(TestModel.ID_QNAME, OUTER_LIST_ID)) + .build(); + + private static final MapEntryNode OUTER_LIST_WITH_CHOICE = Builders.mapEntryBuilder() + .withNodeIdentifier(new NodeIdentifierWithPredicates(TestModel.OUTER_LIST_QNAME, TestModel.ID_QNAME,OUTER_LIST_ID)) + .withChild(ImmutableNodes.leafNode(TestModel.ID_QNAME, OUTER_LIST_ID)) + .withChild(OUTER_CHOICE_ITEM) + .build(); + + @Test + public void test() { + SchemaContext testCtx = TestModel.createTestContext(); + DataNormalizer normalizer = new DataNormalizer(testCtx); + + InstanceIdentifier normalizedPath = normalizer.toNormalized(LEAF_TWO_PATH_LEGACY); + + Node outerListLegacy = normalizer.toLegacy(OUTER_LIST_WITH_CHOICE); + assertNotNull(outerListLegacy); + + + + + } + +} diff --git a/opendaylight/md-sal/sal-dom-broker/src/test/java/org/opendaylight/controller/md/sal/dom/store/impl/TestModel.java b/opendaylight/md-sal/sal-dom-broker/src/test/java/org/opendaylight/controller/md/sal/dom/store/impl/TestModel.java index cab7e57500..2c965047db 100644 --- a/opendaylight/md-sal/sal-dom-broker/src/test/java/org/opendaylight/controller/md/sal/dom/store/impl/TestModel.java +++ b/opendaylight/md-sal/sal-dom-broker/src/test/java/org/opendaylight/controller/md/sal/dom/store/impl/TestModel.java @@ -31,6 +31,8 @@ public class TestModel { public static final InstanceIdentifier TEST_PATH = InstanceIdentifier.of(TEST_QNAME); public static final InstanceIdentifier OUTER_LIST_PATH = InstanceIdentifier.builder(TEST_PATH).node(OUTER_LIST_QNAME).build(); + public static final QName TWO_QNAME = QName.create(TEST_QNAME,"two"); + public static final QName THREE_QNAME = QName.create(TEST_QNAME,"three"); public static final InputStream getDatastoreTestInputStream() {