*/
package org.opendaylight.controller.cluster.datastore;
-import com.google.common.annotations.VisibleForTesting;
import com.google.common.base.Optional;
+import com.google.common.base.Preconditions;
import com.google.common.base.Strings;
import java.util.AbstractMap.SimpleEntry;
import java.util.HashMap;
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.api.DOMDataTreeChangeListener;
-import org.opendaylight.controller.md.sal.dom.store.impl.DOMImmutableDataChangeEvent;
-import org.opendaylight.controller.md.sal.dom.store.impl.ResolveDataChangeEventsTask;
-import org.opendaylight.controller.md.sal.dom.store.impl.tree.ListenerTree;
+import org.opendaylight.controller.md.sal.dom.store.impl.DataChangeListenerRegistration;
import org.opendaylight.yangtools.concepts.ListenerRegistration;
import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier;
import org.opendaylight.yangtools.yang.data.api.schema.NormalizedNode;
import org.opendaylight.yangtools.yang.data.api.schema.tree.DataTreeCandidate;
+import org.opendaylight.yangtools.yang.data.api.schema.tree.DataTreeCandidateTip;
import org.opendaylight.yangtools.yang.data.api.schema.tree.DataTreeCandidates;
import org.opendaylight.yangtools.yang.data.api.schema.tree.DataTreeModification;
+import org.opendaylight.yangtools.yang.data.api.schema.tree.DataTreeSnapshot;
import org.opendaylight.yangtools.yang.data.api.schema.tree.DataValidationFailedException;
import org.opendaylight.yangtools.yang.data.api.schema.tree.TipProducingDataTree;
+import org.opendaylight.yangtools.yang.data.api.schema.tree.TreeType;
import org.opendaylight.yangtools.yang.data.impl.schema.tree.InMemoryDataTreeFactory;
import org.opendaylight.yangtools.yang.model.api.SchemaContext;
import org.slf4j.Logger;
* This class is not part of the API contract and is subject to change at any time.
*/
@NotThreadSafe
-@VisibleForTesting
-public final class ShardDataTree extends ShardDataTreeTransactionParent {
+public class ShardDataTree extends ShardDataTreeTransactionParent {
private static final Logger LOG = LoggerFactory.getLogger(ShardDataTree.class);
- private static final ShardDataTreeNotificationManager MANAGER = new ShardDataTreeNotificationManager();
+ private static final YangInstanceIdentifier ROOT_PATH = YangInstanceIdentifier.builder().build();
+
private final Map<String, ShardDataTreeTransactionChain> transactionChains = new HashMap<>();
- private final ShardDataTreeChangePublisher treeChangePublisher = new ShardDataTreeChangePublisher();
- private final ListenerTree listenerTree = ListenerTree.create();
+ private final ShardDataTreeChangeListenerPublisher treeChangeListenerPublisher;
+ private final ShardDataChangeListenerPublisher dataChangeListenerPublisher;
private final TipProducingDataTree dataTree;
+ private final String logContext;
+ private SchemaContext schemaContext;
+
+ public ShardDataTree(final SchemaContext schemaContext, final TreeType treeType,
+ final ShardDataTreeChangeListenerPublisher treeChangeListenerPublisher,
+ final ShardDataChangeListenerPublisher dataChangeListenerPublisher, final String logContext) {
+ dataTree = InMemoryDataTreeFactory.getInstance().create(treeType);
+ updateSchemaContext(schemaContext);
+ this.treeChangeListenerPublisher = treeChangeListenerPublisher;
+ this.dataChangeListenerPublisher = dataChangeListenerPublisher;
+ this.logContext = logContext;
+ }
- ShardDataTree(final SchemaContext schemaContext) {
- dataTree = InMemoryDataTreeFactory.getInstance().create();
- if (schemaContext != null) {
- dataTree.setSchemaContext(schemaContext);
- }
+ public ShardDataTree(final SchemaContext schemaContext, final TreeType treeType) {
+ this(schemaContext, treeType, new DefaultShardDataTreeChangeListenerPublisher(),
+ new DefaultShardDataChangeListenerPublisher(), "");
}
- TipProducingDataTree getDataTree() {
+ public TipProducingDataTree getDataTree() {
return dataTree;
}
+ SchemaContext getSchemaContext() {
+ return schemaContext;
+ }
+
void updateSchemaContext(final SchemaContext schemaContext) {
+ Preconditions.checkNotNull(schemaContext);
+ this.schemaContext = schemaContext;
dataTree.setSchemaContext(schemaContext);
}
ReadWriteShardDataTreeTransaction newReadWriteTransaction(final String txId, final String chainId) {
if (Strings.isNullOrEmpty(chainId)) {
- return new ReadWriteShardDataTreeTransaction(this, txId, dataTree.takeSnapshot().newModification());
+ return new ReadWriteShardDataTreeTransaction(ShardDataTree.this, txId, dataTree.takeSnapshot()
+ .newModification());
}
return ensureTransactionChain(chainId).newReadWriteTransaction(txId);
}
- void notifyListeners(final DataTreeCandidate candidate) {
- LOG.debug("Notifying listeners on candidate {}", candidate);
+ public void notifyListeners(final DataTreeCandidate candidate) {
+ treeChangeListenerPublisher.publishChanges(candidate, logContext);
+ dataChangeListenerPublisher.publishChanges(candidate, logContext);
+ }
+
+ void notifyOfInitialData(DataChangeListenerRegistration<AsyncDataChangeListener<YangInstanceIdentifier,
+ NormalizedNode<?, ?>>> listenerReg, Optional<DataTreeCandidate> currentState) {
- // DataTreeChanges first, as they are more light-weight
- treeChangePublisher.publishChanges(candidate);
+ if(currentState.isPresent()) {
+ ShardDataChangeListenerPublisher localPublisher = dataChangeListenerPublisher.newInstance();
+ localPublisher.registerDataChangeListener(listenerReg.getPath(), listenerReg.getInstance(),
+ listenerReg.getScope());
+ localPublisher.publishChanges(currentState.get(), logContext);
+ }
+ }
- // DataChanges second, as they are heavier
- ResolveDataChangeEventsTask.create(candidate, listenerTree).resolve(MANAGER);
+ void notifyOfInitialData(final YangInstanceIdentifier path, final DOMDataTreeChangeListener listener,
+ final Optional<DataTreeCandidate> currentState) {
+ if(currentState.isPresent()) {
+ ShardDataTreeChangeListenerPublisher localPublisher = treeChangeListenerPublisher.newInstance();
+ localPublisher.registerTreeChangeListener(path, listener);
+ localPublisher.publishChanges(currentState.get(), logContext);
+ }
}
void closeAllTransactionChains() {
if (chain != null) {
chain.close();
} else {
- LOG.warn("Closing non-existent transaction chain {}", transactionChainId);
+ LOG.debug("{}: Closing non-existent transaction chain {}", logContext, transactionChainId);
}
}
- Entry<ListenerRegistration<AsyncDataChangeListener<YangInstanceIdentifier, NormalizedNode<?, ?>>>, DOMImmutableDataChangeEvent> registerChangeListener(
- final YangInstanceIdentifier path,
- final AsyncDataChangeListener<YangInstanceIdentifier, NormalizedNode<?, ?>> listener, final DataChangeScope scope) {
- final ListenerRegistration<AsyncDataChangeListener<YangInstanceIdentifier, NormalizedNode<?, ?>>> reg =
- listenerTree.registerDataChangeListener(path, listener, scope);
+ Entry<DataChangeListenerRegistration<AsyncDataChangeListener<YangInstanceIdentifier, NormalizedNode<?, ?>>>,
+ Optional<DataTreeCandidate>> registerChangeListener(final YangInstanceIdentifier path,
+ final AsyncDataChangeListener<YangInstanceIdentifier, NormalizedNode<?, ?>> listener,
+ final DataChangeScope scope) {
+ final DataChangeListenerRegistration<AsyncDataChangeListener<YangInstanceIdentifier, NormalizedNode<?, ?>>> reg =
+ dataChangeListenerPublisher.registerDataChangeListener(path, listener, scope);
- final Optional<NormalizedNode<?, ?>> currentState = dataTree.takeSnapshot().readNode(path);
- final DOMImmutableDataChangeEvent event;
- if (currentState.isPresent()) {
- final NormalizedNode<?, ?> data = currentState.get();
- event = DOMImmutableDataChangeEvent.builder(DataChangeScope.BASE).setAfter(data).addCreated(path, data).build();
- } else {
- event = null;
- }
+ return new SimpleEntry<>(reg, readCurrentData());
+ }
- return new SimpleEntry<>(reg, event);
+ private Optional<DataTreeCandidate> readCurrentData() {
+ final Optional<NormalizedNode<?, ?>> currentState = dataTree.takeSnapshot().readNode(ROOT_PATH);
+ return currentState.isPresent() ? Optional.of(DataTreeCandidates.fromNormalizedNode(
+ ROOT_PATH, currentState.get())) : Optional.<DataTreeCandidate>absent();
}
- Entry<ListenerRegistration<DOMDataTreeChangeListener>, DataTreeCandidate> registerTreeChangeListener(final YangInstanceIdentifier path,
- final DOMDataTreeChangeListener listener) {
- final ListenerRegistration<DOMDataTreeChangeListener> reg = treeChangePublisher.registerTreeChangeListener(path, listener);
+ public Entry<ListenerRegistration<DOMDataTreeChangeListener>, Optional<DataTreeCandidate>> registerTreeChangeListener(
+ final YangInstanceIdentifier path, final DOMDataTreeChangeListener listener) {
+ final ListenerRegistration<DOMDataTreeChangeListener> reg = treeChangeListenerPublisher.registerTreeChangeListener(
+ path, listener);
- final Optional<NormalizedNode<?, ?>> currentState = dataTree.takeSnapshot().readNode(path);
- final DataTreeCandidate event;
- if (currentState.isPresent()) {
- event = DataTreeCandidates.fromNormalizedNode(path, currentState.get());
- } else {
- event = null;
- }
- return new SimpleEntry<>(reg, event);
+ return new SimpleEntry<>(reg, readCurrentData());
}
void applyForeignCandidate(final String identifier, final DataTreeCandidate foreign) throws DataValidationFailedException {
- LOG.debug("Applying foreign transaction {}", identifier);
+ LOG.debug("{}: Applying foreign transaction {}", logContext, identifier);
final DataTreeModification mod = dataTree.takeSnapshot().newModification();
DataTreeCandidates.applyToModification(mod, foreign);
mod.ready();
- LOG.trace("Applying foreign modification {}", mod);
+ LOG.trace("{}: Applying foreign modification {}", logContext, mod);
dataTree.validate(mod);
final DataTreeCandidate candidate = dataTree.prepare(mod);
dataTree.commit(candidate);
ShardDataTreeCohort finishTransaction(final ReadWriteShardDataTreeTransaction transaction) {
final DataTreeModification snapshot = transaction.getSnapshot();
snapshot.ready();
- return new SimpleShardDataTreeCohort(this, snapshot);
+ return new SimpleShardDataTreeCohort(this, snapshot, transaction.getId());
}
+ public Optional<NormalizedNode<?, ?>> readNode(YangInstanceIdentifier path) {
+ return dataTree.takeSnapshot().readNode(path);
+ }
+
+ public DataTreeSnapshot takeSnapshot() {
+ return dataTree.takeSnapshot();
+ }
+
+ public DataTreeModification newModification() {
+ return dataTree.takeSnapshot().newModification();
+ }
+
+ public DataTreeCandidate commit(DataTreeModification modification) throws DataValidationFailedException {
+ modification.ready();
+ dataTree.validate(modification);
+ DataTreeCandidateTip candidate = dataTree.prepare(modification);
+ dataTree.commit(candidate);
+ return candidate;
+ }
}