<groupId>org.slf4j</groupId>
<artifactId>slf4j-api</artifactId>
</dependency>
+
+ <dependency>
+ <groupId>org.opendaylight.yangtools</groupId>
+ <artifactId>mockito-configuration</artifactId>
+ <scope>test</scope>
+ </dependency>
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-simple</artifactId>
<instructions>
<Bundle-Name>${project.groupId}.${project.artifactId}</Bundle-Name>
<Bundle-Activator>org.opendaylight.controller.sal.dom.broker.osgi.SchemaServiceActivator</Bundle-Activator>
- <Export-Package>org.opendaylight.controller.sal.dom.broker.spi</Export-Package>
- <Private-Package>org.opendaylight.controller.sal.dom.broker,
+ <Export-Package>org.opendaylight.controller.sal.dom.broker.spi,
+ <!--sal.broker.impl is exported for sal-netconf-connector to use SchemaAwareRpcRegistry.-->
+ <!-- TODO Remove sal.broker.impl from export when SchemaAwareRpcRegistry is not used in connector anymore -->
org.opendaylight.controller.sal.dom.broker.impl,
org.opendaylight.controller.sal.dom.broker.impl.*,
+ </Export-Package>
+ <Private-Package>org.opendaylight.controller.sal.dom.broker,
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.config.yang.md.sal.dom.statistics,\
org.opendaylight.controller.md.sal.dom.broker.impl,
org.opendaylight.controller.md.sal.dom.broker.impl.*,
org.opendaylight.yangtools.yang.util,
*/
package org.opendaylight.controller.config.yang.md.sal.dom.impl;
+import com.google.common.collect.ClassToInstanceMap;
+import com.google.common.collect.MutableClassToInstanceMap;
import org.opendaylight.controller.md.sal.dom.api.DOMDataBroker;
+import org.opendaylight.controller.md.sal.dom.api.DOMMountPointService;
import org.opendaylight.controller.md.sal.dom.broker.impl.compat.BackwardsCompatibleDataBroker;
+import org.opendaylight.controller.md.sal.dom.broker.impl.mount.DOMMountPointServiceImpl;
import org.opendaylight.controller.sal.core.api.BrokerService;
import org.opendaylight.controller.sal.core.api.RpcProvisionRegistry;
import org.opendaylight.controller.sal.core.api.data.DataBrokerService;
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.mount.MountService;
+import org.opendaylight.controller.sal.dom.broker.BackwardsCompatibleMountPointManager;
import org.opendaylight.controller.sal.dom.broker.BrokerImpl;
import org.opendaylight.controller.sal.dom.broker.DataBrokerImpl;
import org.opendaylight.controller.sal.dom.broker.GlobalBundleScanningSchemaServiceImpl;
-import org.opendaylight.controller.sal.dom.broker.MountPointManagerImpl;
import org.opendaylight.controller.sal.dom.broker.impl.SchemaAwareDataStoreAdapter;
import org.opendaylight.controller.sal.dom.broker.impl.SchemaAwareRpcBroker;
import org.opendaylight.controller.sal.dom.broker.impl.SchemaContextProviders;
import org.opendaylight.yangtools.yang.data.api.InstanceIdentifier;
-import com.google.common.collect.ClassToInstanceMap;
-import com.google.common.collect.MutableClassToInstanceMap;
-
/**
*
*/
services.putInstance(DataProviderService.class,legacyData);
services.putInstance(DataBrokerService.class, legacyData);
+ final DOMMountPointService mountService = new DOMMountPointServiceImpl();
+ services.putInstance(DOMMountPointService.class, mountService);
- MountPointManagerImpl mountService = new MountPointManagerImpl();
- services.putInstance(MountService.class, mountService);
- services.putInstance(MountProvisionService.class, mountService);
+ // TODO remove backwards service, use only new DOMMountPointService
+ final MountProvisionService backwardsMountService = new BackwardsCompatibleMountPointManager(mountService);
+ services.putInstance(MountService.class, backwardsMountService);
+ services.putInstance(MountProvisionService.class, backwardsMountService);
return new BrokerImpl(router, services);
}
package org.opendaylight.controller.md.sal.dom.broker.impl.mount;
+import com.google.common.base.Optional;
+import com.google.common.base.Preconditions;
+import com.google.common.collect.ClassToInstanceMap;
+import com.google.common.collect.MutableClassToInstanceMap;
import java.util.HashMap;
import java.util.Map;
-
import org.opendaylight.controller.md.sal.dom.api.DOMMountPoint;
import org.opendaylight.controller.md.sal.dom.api.DOMMountPointService;
import org.opendaylight.controller.md.sal.dom.api.DOMService;
import org.opendaylight.yangtools.yang.data.api.InstanceIdentifier;
import org.opendaylight.yangtools.yang.model.api.SchemaContext;
-import com.google.common.base.Optional;
-import com.google.common.base.Preconditions;
-import com.google.common.collect.ClassToInstanceMap;
-import com.google.common.collect.MutableClassToInstanceMap;
-
public class DOMMountPointServiceImpl implements DOMMountPointService {
- private final Map<InstanceIdentifier, SimpleDOMMountPoint> mountPoints = new HashMap<>();
+ private final Map<InstanceIdentifier, DOMMountPoint> mountPoints = new HashMap<>();
private final ListenerRegistry<MountProvisionListener> listeners = ListenerRegistry.create();
@Override
public Optional<DOMMountPoint> getMountPoint(final InstanceIdentifier path) {
- return Optional.<DOMMountPoint>fromNullable(mountPoints.get(path));
+ return Optional.fromNullable(mountPoints.get(path));
}
@Override
}
}
+ public void notifyMountRemoved(final InstanceIdentifier identifier) {
+ for (final ListenerRegistration<MountProvisionListener> listener : listeners
+ .getListeners()) {
+ listener.getInstance().onMountPointRemoved(identifier);
+ }
+ }
+
@Override
public ListenerRegistration<MountProvisionListener> registerProvisionListener(
final MountProvisionListener listener) {
return listeners.register(listener);
}
- public ObjectRegistration<DOMMountPoint> registerMountPoint(final SimpleDOMMountPoint mountPoint) {
+ public ObjectRegistration<DOMMountPoint> registerMountPoint(final DOMMountPoint mountPoint) {
synchronized (mountPoints) {
Preconditions.checkState(!mountPoints.containsKey(mountPoint.getIdentifier()), "Mount point already exists");
mountPoints.put(mountPoint.getIdentifier(), mountPoint);
}
notifyMountCreated(mountPoint.getIdentifier());
- // FIXME this shouldnt be null
- return null;
+ return new MountRegistration(mountPoint);
+ }
+
+ public void unregisterMountPoint(final InstanceIdentifier mountPointId) {
+ synchronized (mountPoints) {
+ Preconditions.checkState(mountPoints.containsKey(mountPointId), "Mount point does not exist");
+ mountPoints.remove(mountPointId);
+ }
+ notifyMountRemoved(mountPointId);
}
public class DOMMountPointBuilderImpl implements DOMMountPointBuilder {
return registerMountPoint(mountPoint);
}
}
+
+ private final class MountRegistration implements ObjectRegistration<DOMMountPoint> {
+ private final DOMMountPoint mountPoint;
+
+ public MountRegistration(final DOMMountPoint mountPoint) {
+ this.mountPoint = mountPoint;
+ }
+
+ @Override
+ public DOMMountPoint getInstance() {
+ return mountPoint;
+ }
+
+ @Override
+ public void close() throws Exception {
+ unregisterMountPoint(mountPoint.getIdentifier());
+ }
+ }
}
--- /dev/null
+/*
+ * Copyright (c) 2014 Cisco Systems, Inc. and others. All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html.
+ */
+package org.opendaylight.controller.sal.dom.broker;
+
+import com.google.common.annotations.VisibleForTesting;
+import com.google.common.base.Function;
+import com.google.common.base.Optional;
+import com.google.common.base.Preconditions;
+import com.google.common.util.concurrent.CheckedFuture;
+import com.google.common.util.concurrent.Futures;
+import com.google.common.util.concurrent.JdkFutureAdapters;
+import com.google.common.util.concurrent.ListenableFuture;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+import javax.annotation.Nullable;
+import org.opendaylight.controller.md.sal.common.api.RegistrationListener;
+import org.opendaylight.controller.md.sal.common.api.TransactionStatus;
+import org.opendaylight.controller.md.sal.common.api.data.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.api.data.LogicalDatastoreType;
+import org.opendaylight.controller.md.sal.common.api.data.TransactionChainListener;
+import org.opendaylight.controller.md.sal.common.api.data.TransactionCommitFailedException;
+import org.opendaylight.controller.md.sal.common.api.routing.RouteChangeListener;
+import org.opendaylight.controller.md.sal.common.impl.ListenerRegistry;
+import org.opendaylight.controller.md.sal.common.impl.util.compat.DataNormalizationException;
+import org.opendaylight.controller.md.sal.common.impl.util.compat.DataNormalizer;
+import org.opendaylight.controller.md.sal.dom.api.DOMDataBroker;
+import org.opendaylight.controller.md.sal.dom.api.DOMDataChangeListener;
+import org.opendaylight.controller.md.sal.dom.api.DOMDataReadOnlyTransaction;
+import org.opendaylight.controller.md.sal.dom.api.DOMDataReadWriteTransaction;
+import org.opendaylight.controller.md.sal.dom.api.DOMDataWriteTransaction;
+import org.opendaylight.controller.md.sal.dom.api.DOMMountPoint;
+import org.opendaylight.controller.md.sal.dom.api.DOMMountPointService;
+import org.opendaylight.controller.md.sal.dom.api.DOMService;
+import org.opendaylight.controller.md.sal.dom.api.DOMTransactionChain;
+import org.opendaylight.controller.md.sal.dom.broker.impl.compat.BackwardsCompatibleDataBroker;
+import org.opendaylight.controller.sal.common.DataStoreIdentifier;
+import org.opendaylight.controller.sal.core.api.Broker.RoutedRpcRegistration;
+import org.opendaylight.controller.sal.core.api.Broker.RpcRegistration;
+import org.opendaylight.controller.sal.core.api.RoutedRpcDefaultImplementation;
+import org.opendaylight.controller.sal.core.api.RpcImplementation;
+import org.opendaylight.controller.sal.core.api.RpcProvisionRegistry;
+import org.opendaylight.controller.sal.core.api.RpcRegistrationListener;
+import org.opendaylight.controller.sal.core.api.RpcRoutingContext;
+import org.opendaylight.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.controller.sal.core.api.model.SchemaService;
+import org.opendaylight.controller.sal.core.api.mount.MountProvisionInstance;
+import org.opendaylight.controller.sal.core.api.notify.NotificationListener;
+import org.opendaylight.controller.sal.core.api.notify.NotificationPublishService;
+import org.opendaylight.controller.sal.dom.broker.impl.NotificationRouterImpl;
+import org.opendaylight.controller.sal.dom.broker.impl.SchemaAwareRpcBroker;
+import org.opendaylight.controller.sal.dom.broker.impl.SchemaContextProvider;
+import org.opendaylight.controller.sal.dom.broker.spi.NotificationRouter;
+import org.opendaylight.controller.sal.dom.broker.util.ProxySchemaContext;
+import org.opendaylight.yangtools.concepts.ListenerRegistration;
+import org.opendaylight.yangtools.concepts.Registration;
+import org.opendaylight.yangtools.yang.common.QName;
+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.PathArgument;
+import org.opendaylight.yangtools.yang.data.api.schema.NormalizedNode;
+import org.opendaylight.yangtools.yang.model.api.Module;
+import org.opendaylight.yangtools.yang.model.api.SchemaContext;
+import org.opendaylight.yangtools.yang.model.api.SchemaServiceListener;
+
+public class BackwardsCompatibleMountPoint implements MountProvisionInstance, SchemaContextProvider, SchemaService {
+
+ private final DataProviderService dataReader;
+ private final DataReader<InstanceIdentifier,CompositeNode> readWrapper;
+
+ private final InstanceIdentifier mountPath;
+ private final NotificationPublishService notificationPublishService;
+ private final RpcProvisionRegistry rpcs;
+
+ private final ListenerRegistry<SchemaServiceListener> schemaListenerRegistry = new ListenerRegistry<>();
+
+ private SchemaContext schemaContext;
+
+ public BackwardsCompatibleMountPoint(final InstanceIdentifier path, final DOMMountPointService.DOMMountPointBuilder mountPointBuilder) {
+ this.mountPath = Preconditions.checkNotNull(path);
+ Preconditions.checkNotNull(mountPointBuilder);
+
+ dataReader = new DataBrokerImpl();
+ readWrapper = new ReadWrapper();
+ notificationPublishService = new DelgatingNotificationPublishService();
+ rpcs = new SchemaAwareRpcBroker(path.toString(), this);
+
+ mountPointBuilder.addService(DOMDataBroker.class, new BackwardsCompatibleDomStore(dataReader, this));
+ mountPointBuilder.addService(NotificationPublishService.class, notificationPublishService);
+ mountPointBuilder.addService(RpcProvisionRegistry.class, rpcs);
+
+ mountPointBuilder.addInitialSchemaContext(new ProxySchemaContext(this));
+
+ mountPointBuilder.register();
+ }
+
+ public BackwardsCompatibleMountPoint(final InstanceIdentifier path, final DOMMountPoint mount) {
+ this.mountPath = Preconditions.checkNotNull(path);
+ Preconditions.checkNotNull(mount);
+
+ final DOMDataBroker domBroker = getServiceWithCheck(mount, DOMDataBroker.class);
+
+ this.schemaContext = mount.getSchemaContext();
+ dataReader = new BackwardsCompatibleDataBroker(domBroker, this);
+ readWrapper = new ReadWrapper();
+
+ notificationPublishService = getServiceWithCheck(mount, NotificationPublishService.class);
+ rpcs = getServiceWithCheck(mount, RpcProvisionRegistry.class);
+ }
+
+ private <T extends DOMService> T getServiceWithCheck(final DOMMountPoint mount, final Class<T> type) {
+ final Optional<T> serviceOptional = mount.getService(type);
+ Preconditions.checkArgument(serviceOptional.isPresent(), "Service {} has to be set in {}. " +
+ "Cannot construct backwards compatible mount wrapper without it", type, mount);
+ return serviceOptional.get();
+ }
+
+ @Override
+ public void addModule(final Module module) {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public void removeModule(final Module module) {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public SchemaContext getSessionContext() {
+ return getSchemaContext();
+ }
+
+ @Override
+ public SchemaContext getGlobalContext() {
+ return getSchemaContext();
+ }
+
+ @Override
+ public ListenerRegistration<SchemaServiceListener> registerSchemaServiceListener(final SchemaServiceListener listener) {
+ return schemaListenerRegistry.register(listener);
+ }
+
+ @Override
+ public void publish(final CompositeNode notification) {
+ notificationPublishService.publish(notification);
+ }
+
+ @Override
+ public ListenerRegistration<NotificationListener> addNotificationListener(final QName notification, final NotificationListener listener) {
+ return notificationPublishService.addNotificationListener(notification, listener);
+ }
+
+ // TODO Read wrapper is never used ... same in org.opendaylight.controller.sal.dom.broker.MountPointImpl
+ public DataReader<InstanceIdentifier, CompositeNode> getReadWrapper() {
+ return readWrapper;
+ }
+
+ @Override
+ public CompositeNode readConfigurationData(final InstanceIdentifier path) {
+ return dataReader.readConfigurationData(path);
+ }
+
+ @Override
+ public CompositeNode readOperationalData(final InstanceIdentifier path) {
+ return dataReader.readOperationalData(path);
+ }
+
+ @Override
+ public Registration registerOperationalReader(
+ final InstanceIdentifier path, final DataReader<InstanceIdentifier, CompositeNode> reader) {
+ return dataReader.registerOperationalReader(path, reader);
+ }
+
+ @Override
+ public Registration registerConfigurationReader(
+ final InstanceIdentifier path, final DataReader<InstanceIdentifier, CompositeNode> reader) {
+ return dataReader.registerConfigurationReader(path, reader);
+ }
+
+ @Override
+ public RoutedRpcRegistration addRoutedRpcImplementation(final QName rpcType, final RpcImplementation implementation) {
+ return rpcs.addRoutedRpcImplementation(rpcType, implementation);
+ }
+
+ @Override
+ public void setRoutedRpcDefaultDelegate(final RoutedRpcDefaultImplementation defaultImplementation) {
+ rpcs.setRoutedRpcDefaultDelegate(defaultImplementation);
+ }
+
+ @Override
+ public RpcRegistration addRpcImplementation(final QName rpcType, final RpcImplementation implementation)
+ throws IllegalArgumentException {
+ return rpcs.addRpcImplementation(rpcType, implementation);
+ }
+
+ @Override
+ public Set<QName> getSupportedRpcs() {
+ return rpcs.getSupportedRpcs();
+ }
+
+ @Override
+ public ListenableFuture<RpcResult<CompositeNode>> invokeRpc(final QName rpc, final CompositeNode input) {
+ return rpcs.invokeRpc(rpc, input);
+ }
+
+ @Override
+ public ListenerRegistration<RpcRegistrationListener> addRpcRegistrationListener(final RpcRegistrationListener listener) {
+ return rpcs.addRpcRegistrationListener(listener);
+ }
+
+ @Override
+ public ListenableFuture<RpcResult<CompositeNode>> rpc(final QName type, final CompositeNode input) {
+ return rpcs.invokeRpc(type, input);
+ }
+
+ @Override
+ public DataModificationTransaction beginTransaction() {
+ return dataReader.beginTransaction();
+ }
+
+ @Override
+ public ListenerRegistration<DataChangeListener> registerDataChangeListener(final InstanceIdentifier path,
+ final DataChangeListener listener) {
+ return dataReader.registerDataChangeListener(path, listener);
+ }
+
+ @Override
+ public Registration registerCommitHandler(
+ final InstanceIdentifier path, final DataCommitHandler<InstanceIdentifier, CompositeNode> commitHandler) {
+ return dataReader.registerCommitHandler(path, commitHandler);
+ }
+
+ @Override
+ public void removeRefresher(final DataStoreIdentifier store, final DataRefresher refresher) {
+ // NOOP
+ }
+
+ @Override
+ public void addRefresher(final DataStoreIdentifier store, final DataRefresher refresher) {
+ // NOOP
+ }
+
+ @Override
+ public void addValidator(final DataStoreIdentifier store, final DataValidator validator) {
+ // NOOP
+ }
+ @Override
+ public void removeValidator(final DataStoreIdentifier store, final DataValidator validator) {
+ // NOOP
+ }
+
+ @Override
+ public SchemaContext getSchemaContext() {
+ return schemaContext;
+ }
+
+ @Override
+ public void setSchemaContext(final SchemaContext schemaContext) {
+ this.schemaContext = schemaContext;
+ for (ListenerRegistration<SchemaServiceListener> schemaServiceListenerListenerRegistration : schemaListenerRegistry.getListeners()) {
+ schemaServiceListenerListenerRegistration.getInstance().onGlobalContextUpdated(schemaContext);
+ }
+ }
+
+ class ReadWrapper implements DataReader<InstanceIdentifier, CompositeNode> {
+ private InstanceIdentifier shortenPath(final InstanceIdentifier path) {
+ InstanceIdentifier ret = null;
+ if(mountPath.contains(path)) {
+ final List<PathArgument> newArgs = path.getPath().subList(mountPath.getPath().size(), path.getPath().size());
+ ret = InstanceIdentifier.create(newArgs);
+ }
+ return ret;
+ }
+
+ @Override
+ public CompositeNode readConfigurationData(final InstanceIdentifier path) {
+ final InstanceIdentifier newPath = shortenPath(path);
+ if(newPath == null) {
+ return null;
+ }
+ return BackwardsCompatibleMountPoint.this.readConfigurationData(newPath);
+ }
+
+ @Override
+ public CompositeNode readOperationalData(final InstanceIdentifier path) {
+ final InstanceIdentifier newPath = shortenPath(path);
+ if(newPath == null) {
+ return null;
+ }
+ return BackwardsCompatibleMountPoint.this.readOperationalData(newPath);
+ }
+ }
+
+ @Override
+ public ListenerRegistration<RegistrationListener<DataCommitHandlerRegistration<InstanceIdentifier, CompositeNode>>> registerCommitHandlerListener(
+ final RegistrationListener<DataCommitHandlerRegistration<InstanceIdentifier, CompositeNode>> commitHandlerListener) {
+ return dataReader.registerCommitHandlerListener(commitHandlerListener);
+ }
+
+ @Override
+ public <L extends RouteChangeListener<RpcRoutingContext, InstanceIdentifier>> ListenerRegistration<L> registerRouteChangeListener(
+ final L listener) {
+ return rpcs.registerRouteChangeListener(listener);
+ }
+
+ @VisibleForTesting
+ static final class BackwardsCompatibleDomStore implements DOMDataBroker {
+ private final DataProviderService dataReader;
+ private final SchemaContextProvider schemaContextProvider;
+
+ public BackwardsCompatibleDomStore(final DataProviderService dataReader, final SchemaContextProvider schemaContextProvider) {
+ this.dataReader = dataReader;
+ this.schemaContextProvider = schemaContextProvider;
+ }
+
+ @Override
+ public DOMDataReadOnlyTransaction newReadOnlyTransaction() {
+ final DataNormalizer dataNormalizer = new DataNormalizer(schemaContextProvider.getSchemaContext());
+ return new BackwardsCompatibleReadTransaction(dataReader, dataNormalizer);
+ }
+
+ @Override
+ public DOMDataWriteTransaction newWriteOnlyTransaction() {
+ final DataNormalizer dataNormalizer = new DataNormalizer(schemaContextProvider.getSchemaContext());
+ return new BackwardsCompatibleWriteTransaction(dataReader, dataNormalizer);
+ }
+
+ @Override
+ public ListenerRegistration<DOMDataChangeListener> registerDataChangeListener(final LogicalDatastoreType store, final InstanceIdentifier path, final DOMDataChangeListener listener, final DataChangeScope triggeringScope) {
+ throw new UnsupportedOperationException("Register data listener not supported for mount point");
+ }
+
+ @Override
+ public DOMTransactionChain createTransactionChain(final TransactionChainListener listener) {
+ throw new UnsupportedOperationException("Transaction chain not supported for mount point");
+ }
+
+ @Override
+ public DOMDataReadWriteTransaction newReadWriteTransaction() {
+ final DataNormalizer dataNormalizer = new DataNormalizer(schemaContextProvider.getSchemaContext());
+ return new BackwardsCompatibleReadWriteTransaction(dataReader, dataNormalizer);
+ }
+
+ @VisibleForTesting
+ static final class BackwardsCompatibleReadTransaction implements DOMDataReadOnlyTransaction {
+ private final DataProviderService dataReader;
+ private final DataNormalizer normalizer;
+
+ public BackwardsCompatibleReadTransaction(final DataProviderService dataReader, final DataNormalizer normalizer) {
+ this.dataReader = dataReader;
+ this.normalizer = normalizer;
+ }
+
+ @Override
+ public Object getIdentifier() {
+ return this;
+ }
+
+ @Override
+ public void close() {
+ // NOOP
+ }
+
+ @Override
+ public ListenableFuture<Optional<NormalizedNode<?, ?>>> read(final LogicalDatastoreType store, final InstanceIdentifier path) {
+
+ CompositeNode rawData = null;
+
+ switch (store) {
+ case CONFIGURATION: {
+ rawData = dataReader.readConfigurationData(path);
+ break;
+ }
+ case OPERATIONAL: {
+ rawData = dataReader.readOperationalData(path);
+ break;
+ }
+ }
+ Preconditions.checkNotNull(rawData, "Unable to read %s data on path %s", store, path);
+
+ final Map.Entry<InstanceIdentifier, NormalizedNode<?, ?>> normalized = normalizer.toNormalized(path, rawData);
+ final Optional<NormalizedNode<?, ?>> normalizedNodeOptional = Optional.<NormalizedNode<?, ?>>fromNullable(normalized.getValue());
+ return com.google.common.util.concurrent.Futures.immediateFuture(normalizedNodeOptional);
+ }
+ }
+
+ @VisibleForTesting
+ static final class BackwardsCompatibleWriteTransaction implements DOMDataWriteTransaction {
+ private DataModificationTransaction oldTx;
+ private final DataNormalizer dataNormalizer;
+
+ public BackwardsCompatibleWriteTransaction(final DataProviderService dataReader, final DataNormalizer dataNormalizer) {
+ this.oldTx = dataReader.beginTransaction();
+ this.dataNormalizer = dataNormalizer;
+ }
+
+ @Override
+ public Object getIdentifier() {
+ return this;
+ }
+
+ @Override
+ public boolean cancel() {
+ oldTx = null;
+ return true;
+ }
+
+ @Override
+ public void put(final LogicalDatastoreType store, final InstanceIdentifier path, final NormalizedNode<?, ?> data) {
+ final CompositeNode legacyData = dataNormalizer.toLegacy(path, data);
+ try {
+ final InstanceIdentifier legacyPath = dataNormalizer.toLegacy(path);
+
+ switch (store) {
+ case CONFIGURATION: {
+ oldTx.putConfigurationData(legacyPath, legacyData);
+ return;
+ }
+ }
+
+ throw new IllegalArgumentException("Cannot put data " + path + " to datastore " + store);
+ } catch (final DataNormalizationException e) {
+ throw new IllegalArgumentException(String.format("Cannot transform path %s to legacy format", path), e);
+ }
+ }
+
+ @Override
+ public void merge(final LogicalDatastoreType store, final InstanceIdentifier path, final NormalizedNode<?, ?> data) {
+ // TODO not supported
+ throw new UnsupportedOperationException("Merge not supported for mount point");
+ }
+
+ @Override
+ public void delete(final LogicalDatastoreType store, final InstanceIdentifier path) {
+ try {
+ final InstanceIdentifier legacyPath = dataNormalizer.toLegacy(path);
+
+ switch (store) {
+ case CONFIGURATION: {
+ oldTx.removeConfigurationData(legacyPath);
+ return;
+ }
+ }
+ throw new IllegalArgumentException("Cannot delete data " + path + " from datastore " + store);
+ } catch (final DataNormalizationException e) {
+ throw new IllegalArgumentException(String.format("Cannot transform path %s to legacy format", path), e);
+ }
+ }
+
+ @Override
+ public CheckedFuture<Void, TransactionCommitFailedException> submit() {
+ final ListenableFuture<Void> commitAsVoid = Futures.transform(commit(), new Function<RpcResult<TransactionStatus>, Void>() {
+ @Override
+ public Void apply(@Nullable final RpcResult<TransactionStatus> input) {
+ return null;
+ }
+ });
+
+ return Futures.makeChecked(commitAsVoid, new Function<Exception, TransactionCommitFailedException>() {
+ @Override
+ public TransactionCommitFailedException apply(@Nullable final Exception input) {
+ return new TransactionCommitFailedException("Commit failed", input);
+ }
+ });
+ }
+
+ @Override
+ public ListenableFuture<RpcResult<TransactionStatus>> commit() {
+ return JdkFutureAdapters.listenInPoolThread(oldTx.commit());
+ }
+ }
+
+
+ @VisibleForTesting
+ static class BackwardsCompatibleReadWriteTransaction implements DOMDataReadWriteTransaction {
+
+ private final DataProviderService dataReader;
+ private final DataNormalizer dataNormalizer;
+ private final BackwardsCompatibleWriteTransaction delegateWriteTx;
+
+ public BackwardsCompatibleReadWriteTransaction(final DataProviderService dataReader, final DataNormalizer dataNormalizer) {
+ this.dataReader = dataReader;
+ this.dataNormalizer = dataNormalizer;
+ this.delegateWriteTx = new BackwardsCompatibleWriteTransaction(dataReader, dataNormalizer);
+ }
+
+ @Override
+ public Object getIdentifier() {
+ return this;
+ }
+
+ @Override
+ public ListenableFuture<Optional<NormalizedNode<?, ?>>> read(final LogicalDatastoreType store, final InstanceIdentifier path) {
+ return new BackwardsCompatibleReadTransaction(dataReader, dataNormalizer).read(store, path);
+ }
+
+ @Override
+ public boolean cancel() {
+ return delegateWriteTx.cancel();
+ }
+
+ @Override
+ public void put(final LogicalDatastoreType store, final InstanceIdentifier path, final NormalizedNode<?, ?> data) {
+ delegateWriteTx.put(store, path, data);
+ }
+
+ @Override
+ public void merge(final LogicalDatastoreType store, final InstanceIdentifier path, final NormalizedNode<?, ?> data) {
+ delegateWriteTx.merge(store, path, data);
+ }
+
+ @Override
+ public void delete(final LogicalDatastoreType store, final InstanceIdentifier path) {
+ delegateWriteTx.delete(store, path);
+ }
+
+ @Override
+ public CheckedFuture<Void, TransactionCommitFailedException> submit() {
+ return delegateWriteTx.submit();
+ }
+
+ @Override
+ public ListenableFuture<RpcResult<TransactionStatus>> commit() {
+ return delegateWriteTx.commit();
+ }
+ }
+ }
+
+ private class DelgatingNotificationPublishService implements NotificationPublishService {
+ private final NotificationRouter notificationRouter;
+
+ public DelgatingNotificationPublishService(final NotificationRouter notificationRouter) {
+ this.notificationRouter = notificationRouter;
+ }
+
+ private DelgatingNotificationPublishService() {
+ this(new NotificationRouterImpl());
+ }
+
+ @Override
+ public void publish(final CompositeNode notification) {
+ notificationRouter.publish(notification);
+ }
+
+ @Override
+ public ListenerRegistration<NotificationListener> addNotificationListener(final QName notification, final NotificationListener listener) {
+ return notificationRouter.addNotificationListener(notification, listener);
+ }
+ }
+}
--- /dev/null
+/*
+ * Copyright (c) 2014 Cisco Systems, Inc. and others. All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html.
+ */
+package org.opendaylight.controller.sal.dom.broker;
+
+import static com.google.common.base.Preconditions.checkState;
+
+import com.google.common.base.Optional;
+import java.util.concurrent.ConcurrentHashMap;
+import java.util.concurrent.ConcurrentMap;
+import org.opendaylight.controller.md.sal.dom.api.DOMMountPoint;
+import org.opendaylight.controller.md.sal.dom.api.DOMMountPointService;
+import org.opendaylight.controller.sal.core.api.mount.MountProvisionInstance;
+import org.opendaylight.controller.sal.core.api.mount.MountProvisionListener;
+import org.opendaylight.controller.sal.core.api.mount.MountProvisionService;
+import org.opendaylight.yangtools.concepts.ListenerRegistration;
+import org.opendaylight.yangtools.concepts.util.ListenerRegistry;
+import org.opendaylight.yangtools.yang.data.api.InstanceIdentifier;
+
+public class BackwardsCompatibleMountPointManager implements MountProvisionService, MountProvisionListener {
+
+ private final ListenerRegistry<MountProvisionListener> listeners = ListenerRegistry.create();
+ private final ConcurrentMap<InstanceIdentifier, MountProvisionInstance> mounts = new ConcurrentHashMap<>();
+
+ private final DOMMountPointService domMountPointService;
+
+ public BackwardsCompatibleMountPointManager(final DOMMountPointService domMountPointService) {
+ this.domMountPointService = domMountPointService;
+ }
+
+ @Override
+ public MountProvisionInstance createMountPoint(final InstanceIdentifier path) {
+ checkState(!mounts.containsKey(path), "Mount already created");
+ // Create mount point instance, wrap instance of new API with BackwardsCompatibleMountPoint to preserve backwards comatibility
+ final BackwardsCompatibleMountPoint mount = new BackwardsCompatibleMountPoint(path, domMountPointService.createMountPoint(path));
+ mounts.put(path, mount);
+ return mount;
+ }
+
+ public void notifyMountCreated(final InstanceIdentifier identifier) {
+ for (final ListenerRegistration<MountProvisionListener> listener : listeners.getListeners()) {
+ listener.getInstance().onMountPointCreated(identifier);
+ }
+ }
+
+ public void notifyMountRemoved(final InstanceIdentifier identifier) {
+ for (final ListenerRegistration<MountProvisionListener> listener : listeners.getListeners()) {
+ listener.getInstance().onMountPointRemoved(identifier);
+ }
+ }
+
+ @Override
+ public MountProvisionInstance createOrGetMountPoint(
+ final InstanceIdentifier path) {
+ final MountProvisionInstance mount = getMountPoint(path);
+ if (mount == null) {
+ return createMountPoint(path);
+ }
+ return mount;
+ }
+
+ @Override
+ public MountProvisionInstance getMountPoint(final InstanceIdentifier path) {
+ // If the mount point was created here, return directly
+ if(mounts.containsKey(path)) {
+ return mounts.get(path);
+ }
+
+ // If mount was created in underlying DOMMountService, wrap as MountProvisionInstance
+ final Optional<DOMMountPoint> mount = domMountPointService.getMountPoint(path);
+ if(mount.isPresent()) {
+ return new BackwardsCompatibleMountPoint(path, mount.get());
+ } else {
+ return null;
+ }
+ }
+
+ @Override
+ public ListenerRegistration<MountProvisionListener> registerProvisionListener(
+ final MountProvisionListener listener) {
+ return domMountPointService.registerProvisionListener(listener);
+ }
+
+ @Override
+ public void onMountPointCreated(final InstanceIdentifier path) {
+ notifyMountCreated(path);
+ }
+
+ @Override
+ public void onMountPointRemoved(final InstanceIdentifier path) {
+ notifyMountRemoved(path);
+ }
+}
--- /dev/null
+/*
+ * Copyright (c) 2014 Cisco Systems, Inc. and others. All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html.
+ */
+package org.opendaylight.controller.sal.dom.broker.osgi;
+
+import com.google.common.base.Optional;
+import org.opendaylight.controller.md.sal.dom.api.DOMMountPoint;
+import org.opendaylight.controller.md.sal.dom.api.DOMMountPointService;
+import org.opendaylight.controller.sal.core.api.mount.MountProvisionListener;
+import org.opendaylight.yangtools.concepts.ListenerRegistration;
+import org.opendaylight.yangtools.yang.data.api.InstanceIdentifier;
+import org.osgi.framework.ServiceReference;
+
+public class DOMMountPointServiceProxy extends AbstractBrokerServiceProxy<DOMMountPointService> implements DOMMountPointService{
+
+
+ public DOMMountPointServiceProxy(final ServiceReference<DOMMountPointService> ref, final DOMMountPointService delegate) {
+ super(ref, delegate);
+ }
+
+ @Override
+ public Optional<DOMMountPoint> getMountPoint(final InstanceIdentifier path) {
+ return getDelegate().getMountPoint(path);
+ }
+
+ @Override
+ public DOMMountPointBuilder createMountPoint(final InstanceIdentifier path) {
+ return getDelegate().createMountPoint(path);
+ }
+
+ public ListenerRegistration<MountProvisionListener> registerProvisionListener(final MountProvisionListener listener) {
+ return getDelegate().registerProvisionListener(listener);
+ }
+}
import java.util.Arrays;
+import org.opendaylight.controller.md.sal.dom.api.DOMMountPointService;
import org.opendaylight.controller.sal.core.api.BrokerService;
import org.osgi.framework.ServiceReference;
import org.opendaylight.controller.sal.core.api.data.DataBrokerService;
((ServiceReference<MountProvisionService>) ref), service);
}
+ private static Object _createProxyImpl(final ServiceReference<?> ref,
+ final DOMMountPointService service) {
+
+ return new DOMMountPointServiceProxy(
+ ((ServiceReference<DOMMountPointService>) ref), service);
+ }
+
private static Object _createProxyImpl(final ServiceReference<?> ref,
final SchemaService service) {
return _createProxyImpl(ref, (SchemaService) service);
} else if (service instanceof NotificationService) {
return _createProxyImpl(ref, (NotificationService) service);
+ } else if (service instanceof DOMMountPointService) {
+ return _createProxyImpl(ref, (DOMMountPointService) service);
} else if (service != null) {
return _createProxyImpl(ref, service);
} else {
--- /dev/null
+/*
+ * Copyright (c) 2014 Cisco Systems, Inc. and others. All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html.
+ */
+
+package org.opendaylight.controller.sal.dom.broker.util;
+
+import java.net.URI;
+import java.util.Collection;
+import java.util.Date;
+import java.util.List;
+import java.util.Set;
+
+import org.opendaylight.yangtools.yang.common.QName;
+import org.opendaylight.yangtools.yang.model.api.AugmentationSchema;
+import org.opendaylight.yangtools.yang.model.api.ConstraintDefinition;
+import org.opendaylight.yangtools.yang.model.api.DataSchemaNode;
+import org.opendaylight.yangtools.yang.model.api.ExtensionDefinition;
+import org.opendaylight.yangtools.yang.model.api.GroupingDefinition;
+import org.opendaylight.yangtools.yang.model.api.Module;
+import org.opendaylight.yangtools.yang.model.api.ModuleIdentifier;
+import org.opendaylight.yangtools.yang.model.api.NotificationDefinition;
+import org.opendaylight.yangtools.yang.model.api.RpcDefinition;
+import org.opendaylight.yangtools.yang.model.api.SchemaContext;
+import org.opendaylight.yangtools.yang.model.api.SchemaContextProvider;
+import org.opendaylight.yangtools.yang.model.api.SchemaPath;
+import org.opendaylight.yangtools.yang.model.api.Status;
+import org.opendaylight.yangtools.yang.model.api.TypeDefinition;
+import org.opendaylight.yangtools.yang.model.api.UnknownSchemaNode;
+import org.opendaylight.yangtools.yang.model.api.UsesNode;
+
+import com.google.common.base.Optional;
+import com.google.common.base.Preconditions;
+
+/**
+ * ProxySchema Context for SchemaContextProviders
+ */
+public class ProxySchemaContext implements SchemaContext {
+
+ private final SchemaContextProvider schemaProvider;
+
+ public ProxySchemaContext(final SchemaContextProvider schemaProvider) {
+ this.schemaProvider = schemaProvider;
+ }
+
+ private SchemaContext getCurrentSchema() {
+ Preconditions.checkState(schemaProvider.getSchemaContext() != null, "Schema context unavailable from %s", schemaProvider);
+ return schemaProvider.getSchemaContext();
+ }
+
+ @Override
+ public Set<DataSchemaNode> getDataDefinitions() {
+ return getCurrentSchema().getDataDefinitions();
+ }
+
+ @Override
+ public Set<Module> getModules() {
+ return getCurrentSchema().getModules();
+ }
+
+ @Override
+ public Set<NotificationDefinition> getNotifications() {
+ return getCurrentSchema().getNotifications();
+ }
+
+ @Override
+ public Set<RpcDefinition> getOperations() {
+ return getCurrentSchema().getOperations();
+ }
+
+ @Override
+ public Set<ExtensionDefinition> getExtensions() {
+ return getCurrentSchema().getExtensions();
+ }
+
+ @Override
+ public Module findModuleByName(final String s, final Date date) {
+ return getCurrentSchema().findModuleByName(s, date);
+ }
+
+ @Override
+ public Set<Module> findModuleByNamespace(final URI uri) {
+ return getCurrentSchema().findModuleByNamespace(uri);
+ }
+
+ @Override
+ public Module findModuleByNamespaceAndRevision(final URI uri, final Date date) {
+ return getCurrentSchema().findModuleByNamespaceAndRevision(uri, date);
+ }
+
+ @Override
+ public Optional<String> getModuleSource(final ModuleIdentifier moduleIdentifier) {
+ return getCurrentSchema().getModuleSource(moduleIdentifier);
+ }
+
+ @Override
+ public Set<ModuleIdentifier> getAllModuleIdentifiers() {
+ return getCurrentSchema().getAllModuleIdentifiers();
+ }
+
+ @Override
+ public boolean isPresenceContainer() {
+ return getCurrentSchema().isPresenceContainer();
+ }
+
+ @Override
+ public Set<TypeDefinition<?>> getTypeDefinitions() {
+ return getCurrentSchema().getTypeDefinitions();
+ }
+
+ @Override
+ public Collection<DataSchemaNode> getChildNodes() {
+ return getCurrentSchema().getChildNodes();
+ }
+
+ @Override
+ public Set<GroupingDefinition> getGroupings() {
+ return getCurrentSchema().getGroupings();
+ }
+
+ @Override
+ public DataSchemaNode getDataChildByName(final QName qName) {
+ return getCurrentSchema().getDataChildByName(qName);
+ }
+
+ @Override
+ public DataSchemaNode getDataChildByName(final String s) {
+ return getCurrentSchema().getDataChildByName(s);
+ }
+
+ @Override
+ public Set<UsesNode> getUses() {
+ return getCurrentSchema().getUses();
+ }
+
+ @Override
+ public Set<AugmentationSchema> getAvailableAugmentations() {
+ return getCurrentSchema().getAvailableAugmentations();
+ }
+
+ @Override
+ public boolean isAugmenting() {
+ return getCurrentSchema().isAugmenting();
+ }
+
+ @Override
+ public boolean isAddedByUses() {
+ return getCurrentSchema().isAddedByUses();
+ }
+
+ @Override
+ public boolean isConfiguration() {
+ return getCurrentSchema().isConfiguration();
+ }
+
+ @Override
+ public ConstraintDefinition getConstraints() {
+ return getCurrentSchema().getConstraints();
+ }
+
+ @Override
+ public QName getQName() {
+ return getCurrentSchema().getQName();
+ }
+
+ @Override
+ public SchemaPath getPath() {
+ return getCurrentSchema().getPath();
+ }
+
+ @Override
+ public List<UnknownSchemaNode> getUnknownSchemaNodes() {
+ return getCurrentSchema().getUnknownSchemaNodes();
+ }
+
+ @Override
+ public String getDescription() {
+ return getCurrentSchema().getDescription();
+ }
+
+ @Override
+ public String getReference() {
+ return getCurrentSchema().getReference();
+ }
+
+ @Override
+ public Status getStatus() {
+ return getCurrentSchema().getStatus();
+ }
+}
--- /dev/null
+/*
+ * Copyright (c) 2014 Cisco Systems, Inc. and others. All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html.
+ */
+
+package org.opendaylight.controller.sal.dom.broker;
+
+import static junit.framework.Assert.fail;
+import static org.mockito.Matchers.any;
+import static org.mockito.Mockito.doAnswer;
+import static org.mockito.Mockito.doReturn;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.times;
+import static org.mockito.Mockito.verify;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.mockito.Mock;
+import org.mockito.MockitoAnnotations;
+import org.mockito.invocation.InvocationOnMock;
+import org.mockito.stubbing.Answer;
+import org.opendaylight.controller.md.sal.dom.api.DOMMountPoint;
+import org.opendaylight.controller.md.sal.dom.api.DOMMountPointService;
+import org.opendaylight.controller.md.sal.dom.api.DOMService;
+import org.opendaylight.controller.md.sal.dom.broker.impl.mount.DOMMountPointServiceImpl;
+import org.opendaylight.controller.sal.core.api.mount.MountProvisionInstance;
+import org.opendaylight.controller.sal.core.api.mount.MountProvisionListener;
+import org.opendaylight.yangtools.concepts.ObjectRegistration;
+import org.opendaylight.yangtools.yang.common.QName;
+import org.opendaylight.yangtools.yang.data.api.InstanceIdentifier;
+import org.opendaylight.yangtools.yang.model.api.DataSchemaNode;
+import org.opendaylight.yangtools.yang.model.api.SchemaContext;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import com.google.common.base.Optional;
+
+public class BackwardsCompatibleMountPointManagerTest {
+ private static final Logger log = LoggerFactory.getLogger(BackwardsCompatibleMountPointManagerTest.class);
+
+ @Mock
+ private DOMMountPointServiceImpl domMountPointService;
+ @Mock
+ private DOMMountPointService.DOMMountPointBuilder mountBuilder;
+
+ private BackwardsCompatibleMountPointManager compatibleMountPointManager;
+ static final QName qName = QName.create("namespace", "12-12-1212", "mount");
+ static final InstanceIdentifier id = InstanceIdentifier.builder(qName).build();
+
+ @Before
+ public void setUp() throws Exception {
+ MockitoAnnotations.initMocks(this);
+ stubMountService();
+ compatibleMountPointManager = new BackwardsCompatibleMountPointManager(domMountPointService);
+ }
+
+ @Test
+ public void testCreateMountpointAlreadyCreated() throws Exception {
+ compatibleMountPointManager.createMountPoint(id);
+ verify(domMountPointService).createMountPoint(id);
+ verify(mountBuilder, times(3)).addService(any(Class.class), any(DOMService.class));
+ verify(mountBuilder).addInitialSchemaContext(any(SchemaContext.class));
+
+ try {
+ compatibleMountPointManager.createMountPoint(id);
+ } catch (final IllegalStateException e) {
+ log.debug("", e);
+ return;
+ }
+ fail("Should fail to create duplicate mount");
+ }
+
+ @Test
+ public void testCreateMountpointGetOrCreate() throws Exception {
+ compatibleMountPointManager = new BackwardsCompatibleMountPointManager(new DOMMountPointServiceImpl());
+
+ final MountProvisionListener listener = new MountProvisionListener() {
+ public int createdMounts = 0;
+
+ @Override
+ public void onMountPointCreated(final InstanceIdentifier path) {
+ if(createdMounts++ > 1 ) {
+ fail("Only one mount point should have been created");
+ }
+ }
+
+ @Override
+ public void onMountPointRemoved(final InstanceIdentifier path) {}
+ };
+
+ compatibleMountPointManager.registerProvisionListener(listener);
+
+ final MountProvisionInstance m1 = compatibleMountPointManager.createOrGetMountPoint(id);
+ m1.setSchemaContext(mockSchemaContext());
+ compatibleMountPointManager.createOrGetMountPoint(id);
+ compatibleMountPointManager.createOrGetMountPoint(id);
+ }
+
+ private void stubMountService() {
+ doReturn(mockMountPointBuilder()).when(domMountPointService).createMountPoint(any(InstanceIdentifier.class));
+ doReturn(Optional.of(mockMountPoint())).when(domMountPointService).getMountPoint(any(InstanceIdentifier.class));
+ }
+
+ private DOMMountPoint mockMountPoint() {
+ final DOMMountPoint mock = mock(DOMMountPoint.class);
+ doAnswer(new Answer() {
+ @Override
+ public Object answer(final InvocationOnMock invocation) throws Throwable {
+ return Optional.of(mock(((Class<?>) invocation.getArguments()[0])));
+ }
+ }).when(mock).getService(any(Class.class));
+ doReturn(mockSchemaContext()).when(mock).getSchemaContext();
+ return mock;
+ }
+
+ static SchemaContext mockSchemaContext() {
+ final SchemaContext mock = mock(SchemaContext.class);
+ doReturn(qName).when(mock).getQName();
+ doReturn("schema").when(mock).toString();
+ doReturn(mock(DataSchemaNode.class)).when(mock).getDataChildByName(any(QName.class));
+ return mock;
+ }
+
+ private DOMMountPointService.DOMMountPointBuilder mockMountPointBuilder() {
+ doReturn(mountBuilder).when(mountBuilder).addService(any(Class.class), any(DOMService.class));
+ doReturn(mockObjectRegistration()).when(mountBuilder).register();
+ doReturn(mountBuilder).when(mountBuilder).addInitialSchemaContext(any(SchemaContext.class));
+ return mountBuilder;
+ }
+
+ private ObjectRegistration<?> mockObjectRegistration() {
+ return mock(ObjectRegistration.class);
+ }
+
+}
--- /dev/null
+/*
+ * Copyright (c) 2014 Cisco Systems, Inc. and others. All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html.
+ */
+
+package org.opendaylight.controller.sal.dom.broker;
+
+import static junit.framework.Assert.fail;
+import static org.junit.Assert.assertEquals;
+import static org.mockito.Matchers.any;
+import static org.mockito.Mockito.doNothing;
+import static org.mockito.Mockito.doReturn;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.times;
+import static org.mockito.Mockito.verify;
+
+import com.google.common.base.Optional;
+import com.google.common.util.concurrent.ListenableFuture;
+import java.util.AbstractMap;
+import org.junit.Before;
+import org.junit.Test;
+import org.mockito.Mock;
+import org.mockito.MockitoAnnotations;
+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.DataNormalizationException;
+import org.opendaylight.controller.md.sal.common.impl.util.compat.DataNormalizer;
+import org.opendaylight.controller.sal.core.api.data.DataModificationTransaction;
+import org.opendaylight.controller.sal.core.api.data.DataProviderService;
+import org.opendaylight.controller.sal.dom.broker.impl.SchemaContextProvider;
+import org.opendaylight.yangtools.yang.common.RpcResultBuilder;
+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.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+public class BackwardsCompatibleMountPointTest {
+ private static final Logger log = LoggerFactory.getLogger(BackwardsCompatibleMountPointManagerTest.class);
+
+ private static final InstanceIdentifier id = BackwardsCompatibleMountPointManagerTest.id;
+ private final NormalizedNode<?, ?> normalizedNode = mockNormalizedNode();
+ private final CompositeNode compositeNode = mockCompositeNode();
+
+ @Mock
+ private DataProviderService oldBroker;
+ @Mock
+ private SchemaContextProvider schemaContextProvider;
+ @Mock
+ private DataModificationTransaction mockTx;
+
+ private BackwardsCompatibleMountPoint.BackwardsCompatibleDomStore backwardsCompatibleDomStore;
+
+ @Before
+ public void setUp() throws Exception {
+ MockitoAnnotations.initMocks(this);
+ stubSchemaProvider();
+ stubOldBroker();
+ backwardsCompatibleDomStore = new BackwardsCompatibleMountPoint.BackwardsCompatibleDomStore(oldBroker, schemaContextProvider);
+ }
+
+ private void stubOldBroker() {
+ doReturn(compositeNode).when(oldBroker).readConfigurationData(id);
+ doReturn(compositeNode).when(oldBroker).readOperationalData(id);
+ doReturn(mockTx).when(oldBroker).beginTransaction();
+ doNothing().when(mockTx).putConfigurationData(id, compositeNode);
+ doNothing().when(mockTx).putOperationalData(id, compositeNode);
+ doReturn(com.google.common.util.concurrent.Futures.immediateFuture(RpcResultBuilder.success(TransactionStatus.COMMITED))).when(mockTx).commit();
+ }
+
+ private CompositeNode mockCompositeNode() {
+ final CompositeNode mock = mock(CompositeNode.class);
+ doReturn("node").when(mock).toString();
+ return mock;
+ }
+
+ private void stubSchemaProvider() {
+ doReturn(BackwardsCompatibleMountPointManagerTest.mockSchemaContext()).when(schemaContextProvider).getSchemaContext();
+ }
+
+ @Test
+ public void testBackwardsCompatibleBroker() throws Exception {
+ backwardsCompatibleDomStore.newReadOnlyTransaction();
+ backwardsCompatibleDomStore.newWriteOnlyTransaction();
+ backwardsCompatibleDomStore.newReadWriteTransaction();
+ }
+
+ @Test
+ public void testReadTransaction() throws Exception {
+ final BackwardsCompatibleMountPoint.BackwardsCompatibleDomStore.BackwardsCompatibleReadTransaction tx =
+ new BackwardsCompatibleMountPoint.BackwardsCompatibleDomStore.BackwardsCompatibleReadTransaction(oldBroker, mockNormalizer());
+
+ ListenableFuture<Optional<NormalizedNode<?, ?>>> read = tx.read(LogicalDatastoreType.CONFIGURATION, id);
+ assertEquals(normalizedNode, read.get().get());
+ verify(oldBroker).readConfigurationData(id);
+
+ read = tx.read(LogicalDatastoreType.OPERATIONAL, id);
+ assertEquals(normalizedNode, read.get().get());
+
+ verify(oldBroker).readOperationalData(id);
+ }
+
+ @Test
+ public void testReadWriteTransactionOperational() throws Exception {
+ final BackwardsCompatibleMountPoint.BackwardsCompatibleDomStore.BackwardsCompatibleWriteTransaction tx =
+ new BackwardsCompatibleMountPoint.BackwardsCompatibleDomStore.BackwardsCompatibleWriteTransaction(oldBroker, mockNormalizer());
+
+ verify(oldBroker).beginTransaction();
+
+ tx.put(LogicalDatastoreType.CONFIGURATION, id, normalizedNode);
+ verify(mockTx).putConfigurationData(id, compositeNode);
+
+ tx.put(LogicalDatastoreType.CONFIGURATION, id, normalizedNode);
+ verify(mockTx, times(2)).putConfigurationData(id, compositeNode);
+
+ tx.commit();
+ verify(mockTx).commit();
+ }
+
+
+ @Test
+ public void testCannotPutOperational() throws Exception {
+ final BackwardsCompatibleMountPoint.BackwardsCompatibleDomStore.BackwardsCompatibleWriteTransaction tx =
+ new BackwardsCompatibleMountPoint.BackwardsCompatibleDomStore.BackwardsCompatibleWriteTransaction(oldBroker, mockNormalizer());
+
+ try {
+ tx.put(LogicalDatastoreType.OPERATIONAL, id, normalizedNode);
+ } catch (IllegalArgumentException e) {
+ // Cannot put operational data
+ log.debug("", e);
+ return;
+ }
+
+ fail("Should fail when putting operational data");
+ }
+
+ private DataNormalizer mockNormalizer() throws DataNormalizationException {
+ final DataNormalizer mock = mock(DataNormalizer.class);
+ doReturn(new AbstractMap.SimpleEntry<InstanceIdentifier, NormalizedNode<?, ?>>(id, normalizedNode) {})
+ .when(mock).toNormalized(any(InstanceIdentifier.class), any(CompositeNode.class));
+ doReturn(compositeNode).when(mock).toLegacy(any(InstanceIdentifier.class), any(NormalizedNode.class));
+ doReturn(id).when(mock).toLegacy(any(InstanceIdentifier.class));
+ return mock;
+ }
+
+ private NormalizedNode<?, ?> mockNormalizedNode() {
+ final NormalizedNode mock = mock(NormalizedNode.class);
+ doReturn("mockNormalizedNode").when(mock).toString();
+ return mock;
+ }
+}
\ No newline at end of file