From: Tony Tkacik Date: Thu, 7 Aug 2014 20:05:07 +0000 (+0000) Subject: Merge "Bug 1308 - Unable to publish NodeUpdated message via NotificationService" X-Git-Tag: release/helium~327 X-Git-Url: https://git.opendaylight.org/gerrit/gitweb?a=commitdiff_plain;h=8e42b08cb626a60919c145b2a46d94114c3905d6;hp=471c6c3e7c6bf110a4b8cbfcc6b582f9a8439d0d;p=controller.git Merge "Bug 1308 - Unable to publish NodeUpdated message via NotificationService" --- diff --git a/.gitignore b/.gitignore index f8cf74f826..9144cda4cc 100644 --- a/.gitignore +++ b/.gitignore @@ -27,3 +27,5 @@ out/ maven-eclipse.xml .DS_STORE .metadata +opendaylight/md-sal/sal-distributed-datastore/journal + diff --git a/features/config-netty/pom.xml b/features/config-netty/pom.xml index 98b97d1d95..16fd975130 100644 --- a/features/config-netty/pom.xml +++ b/features/config-netty/pom.xml @@ -19,7 +19,6 @@ org.opendaylight.controller config-persister-features - ${config.version} features xml runtime diff --git a/features/config-netty/src/main/resources/features.xml b/features/config-netty/src/main/resources/features.xml index 3121ca01a2..f1b2d1f753 100644 --- a/features/config-netty/src/main/resources/features.xml +++ b/features/config-netty/src/main/resources/features.xml @@ -12,5 +12,6 @@ mvn:org.opendaylight.controller/threadpool-config-api/${project.version} mvn:org.opendaylight.controller/threadpool-config-impl/${project.version} odl-config-startup + mvn:org.opendaylight.controller/config-netty-config/${config.version}/xml/config \ No newline at end of file diff --git a/features/config-persister/pom.xml b/features/config-persister/pom.xml index 969d0c8841..ec1520ed98 100644 --- a/features/config-persister/pom.xml +++ b/features/config-persister/pom.xml @@ -27,7 +27,6 @@ org.opendaylight.controller netconf-features - ${netconf.version} features xml runtime @@ -35,7 +34,6 @@ org.opendaylight.controller config-features - ${config.version} features xml runtime diff --git a/features/netconf/pom.xml b/features/netconf/pom.xml index 90c088eaba..856557c1e8 100644 --- a/features/netconf/pom.xml +++ b/features/netconf/pom.xml @@ -19,7 +19,6 @@ org.opendaylight.controller config-features - ${config.version} features xml runtime @@ -27,7 +26,6 @@ org.opendaylight.controller features-odl-protocol-framework - ${protocol-framework.version} features xml runtime diff --git a/features/nsf/src/main/resources/features.xml b/features/nsf/src/main/resources/features.xml index fb61f33fb3..130d72e01a 100644 --- a/features/nsf/src/main/resources/features.xml +++ b/features/nsf/src/main/resources/features.xml @@ -34,12 +34,14 @@ mvn:org.opendaylight.controller/forwardingrulesmanager.implementation/${forwardingrulesmanager.implementation.version} mvn:org.opendaylight.controller/topologymanager/${topologymanager.version} + mvn:org.opendaylight.controller/topologymanager.shell/${topologymanager.shell.version} mvn:org.opendaylight.controller/networkconfig.neutron/${networkconfig.neutron.version} mvn:org.opendaylight.controller/networkconfig.neutron.implementation/${networkconfig.neutron.implementation.version} mvn:org.opendaylight.controller/hosttracker/${hosttracker.api.version} mvn:org.opendaylight.controller/hosttracker.implementation/${hosttracker.implementation.version} + mvn:org.opendaylight.controller/hosttracker.shell/${hosttracker.shell.version} mvn:org.opendaylight.controller/forwarding.staticrouting @@ -70,4 +72,4 @@ mvn:org.opendaylight.controller/topology.northbound/${topology.northbound.version} mvn:org.opendaylight.controller/usermanager.northbound/${usermanager.northbound.version} - \ No newline at end of file + diff --git a/features/protocol-framework/pom.xml b/features/protocol-framework/pom.xml index 045ac2dffe..ba5dd18fc2 100644 --- a/features/protocol-framework/pom.xml +++ b/features/protocol-framework/pom.xml @@ -19,7 +19,6 @@ org.opendaylight.controller config-features - ${config.version} features xml runtime diff --git a/itests/base-features-it/pom.xml b/itests/base-features-it/pom.xml new file mode 100644 index 0000000000..8f73779009 --- /dev/null +++ b/itests/base-features-it/pom.xml @@ -0,0 +1,90 @@ + + 4.0.0 + + org.opendaylight.controller + itests-controller + 1.4.2-SNAPSHOT + ../pom.xml + + base-features-it + base-features-it + jar + + + org.opendaylight.controller + base-features + ${project.version} + features + xml + + + org.slf4j + slf4j-api + + + + org.ops4j.pax.exam + pax-exam-container-karaf + ${pax.exam.version} + test + + + org.ops4j.pax.exam + pax-exam-junit4 + test + + + org.ops4j.pax.exam + pax-exam + ${pax.exam.version} + test + + + org.ops4j.pax.url + pax-url-aether + test + + + javax.inject + javax.inject + 1 + test + + + org.apache.karaf.features + org.apache.karaf.features.core + ${karaf.version} + test + + + org.osgi + org.osgi.core + test + + + junit + junit + test + + + + + + + + + + + diff --git a/itests/base-features-it/src/test/java/org/opendaylight/controller/base/BaseFeatureTest.java b/itests/base-features-it/src/test/java/org/opendaylight/controller/base/BaseFeatureTest.java new file mode 100644 index 0000000000..0d38940346 --- /dev/null +++ b/itests/base-features-it/src/test/java/org/opendaylight/controller/base/BaseFeatureTest.java @@ -0,0 +1,74 @@ +package org.opendaylight.controller.base; + +import static org.ops4j.pax.exam.CoreOptions.maven; +import static org.ops4j.pax.exam.karaf.options.KarafDistributionOption.configureConsole; +import static org.ops4j.pax.exam.karaf.options.KarafDistributionOption.karafDistributionConfiguration; +import static org.ops4j.pax.exam.karaf.options.KarafDistributionOption.keepRuntimeFolder; +import static org.ops4j.pax.exam.karaf.options.KarafDistributionOption.logLevel; + +import java.io.File; +import java.net.URI; +import java.util.EnumSet; + +import javax.inject.Inject; + +import junit.framework.Assert; + +import org.apache.karaf.features.Feature; +import org.apache.karaf.features.FeaturesService; +import org.apache.karaf.features.Repository; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.ops4j.pax.exam.Configuration; +import org.ops4j.pax.exam.Option; +import org.ops4j.pax.exam.junit.PaxExam; +import org.ops4j.pax.exam.karaf.options.LogLevelOption.LogLevel; + + +@RunWith(PaxExam.class) +public class BaseFeatureTest { + @Inject + private FeaturesService featuresService; + @Configuration + public Option[] config() { + return new Option[] { + // Provision and launch a container based on a distribution of Karaf (Apache ServiceMix). + karafDistributionConfiguration() + .frameworkUrl( + maven() + .groupId("org.opendaylight.controller") + .artifactId("distribution.opendaylight-karaf") + .type("tar.gz") + .version("1.4.2-SNAPSHOT")) + .name("OpenDaylight") + .unpackDirectory(new File("target/pax")) + .useDeployFolder(false), + // It is really nice if the container sticks around after the test so you can check the contents + // of the data directory when things go wrong. + keepRuntimeFolder(), + // Don't bother with local console output as it just ends up cluttering the logs + configureConsole().ignoreLocalConsole(), + // Force the log level to INFO so we have more details during the test. It defaults to WARN. + logLevel(LogLevel.WARN), + // Remember that the test executes in another process. If you want to debug it, you need + // to tell Pax Exam to launch that process with debugging enabled. Launching the test class itself with + // debugging enabled (for example in Eclipse) will not get you the desired results. + //debugConfiguration("5000", true), + }; + } + + @Test + public void testAllFeatures() throws Exception { + featuresService.addRepository(new URI("mvn:org.opendaylight.controller/base-features/1.4.2-SNAPSHOT/xml/features")); + Repository repoUnderTest = featuresService.getRepository("base-1.4.2-SNAPSHOT"); + Assert.assertNotNull(repoUnderTest); + Feature[] featuresUnderTest = repoUnderTest.getFeatures(); + for(int i=0; i< featuresUnderTest.length; i++) + { + Feature feature = featuresUnderTest[i]; + featuresService.installFeature(feature,EnumSet.of(FeaturesService.Option.Verbose)); + System.out.println("Testing Feature:"+feature.getName()); + Assert.assertTrue(featuresService.isInstalled(feature)); + } + } +} \ No newline at end of file diff --git a/itests/pom.xml b/itests/pom.xml new file mode 100644 index 0000000000..19836a2ad6 --- /dev/null +++ b/itests/pom.xml @@ -0,0 +1,18 @@ + + + 4.0.0 + + org.opendaylight.controller + commons.opendaylight + 1.4.2-SNAPSHOT + ../opendaylight/commons/opendaylight + + itests-controller + pom + + 3.0 + + + base-features-it + + diff --git a/opendaylight/commons/opendaylight/pom.xml b/opendaylight/commons/opendaylight/pom.xml index be88e4a505..4f678f6854 100644 --- a/opendaylight/commons/opendaylight/pom.xml +++ b/opendaylight/commons/opendaylight/pom.xml @@ -95,6 +95,7 @@ 0.5.2-SNAPSHOT 0.5.2-SNAPSHOT 0.4.2-SNAPSHOT + 1.0.0-SNAPSHOT 0.4.2-SNAPSHOT 0.4.2-SNAPSHOT 0.0.2-SNAPSHOT @@ -109,7 +110,6 @@ 2.0.1 1.1.1 2.0 - 4.8.1 1.0.0-SNAPSHOT 3.0.0 3.0.1 @@ -133,6 +133,7 @@ 1.4.2-SNAPSHOT 2013.08.27.4-SNAPSHOT 0.0.2-SNAPSHOT + 4.0.0 1.1.6 1.1.6 1.0-alpha-2 @@ -158,15 +159,17 @@ ${user.name}-private-view https://sonar.opendaylight.org/ + 2.4 jacoco java + target/code-coverage/jacoco.exec + target/code-coverage/jacoco-it.exec org.openflow.openflowj,net.sf.jung2,org.opendaylight.controller.protobuff.messages 1.0.0 1.2.1 3.1.4.RELEASE 3.1.3.RELEASE 3.1.3.RELEASE - org.openflow.openflowj,net.sf.jung2 0.4.2-SNAPSHOT 0.4.2-SNAPSHOT 0.5.1-SNAPSHOT @@ -179,6 +182,7 @@ 0.4.2-SNAPSHOT 0.4.2-SNAPSHOT 0.4.2-SNAPSHOT + 1.0.0-SNAPSHOT 0.4.2-SNAPSHOT 1.2.0 1.2.2 @@ -329,6 +333,11 @@ akka-testkit_${scala.version} ${akka.version} + + com.typesafe.akka + akka-osgi_${scala.version} + ${akka.version} + commons-codec commons-codec @@ -918,11 +927,6 @@ filter-valve ${filtervalve.version} - - org.opendaylight.controller - flow-management-compatibility - ${mdsal.version} - org.opendaylight.controller flowprogrammer.northbound @@ -1240,6 +1244,26 @@ sal-rest-connector-config ${mdsal.version} + + org.opendaylight.controller + config-netty-config + ${config.version} + + + org.opendaylight.controller + md-sal-config + ${mdsal.version} + + + org.opendaylight.controller + netconf-config + ${netconf.version} + + + org.opendaylight.controller + netconf-connector-config + ${netconf.version} + org.opendaylight.controller sal-rest-docgen @@ -1255,6 +1279,28 @@ sal-test-model ${mdsal.version} + + org.opendaylight.controller + sal-distributed-datastore + ${mdsal.version} + + + org.opendaylight.controller + sal-clustering-commons + ${mdsal.version} + + + org.opendaylight.controller + sal-clustering-config + ${mdsal.version} + + + + org.opendaylight.controller + sal-remoterpc-connector + ${mdsal.version} + + @@ -1455,11 +1501,6 @@ model-flow-base ${mdsal.version} - - org.opendaylight.controller.model - model-flow-management - ${mdsal.version} - org.opendaylight.controller.model model-flow-service @@ -1496,6 +1537,11 @@ sample-toaster-provider ${mdsal.version} + + org.opendaylight.controller.samples + toaster-config + ${mdsal.version} + org.opendaylight.controller.thirdparty com.sun.jersey.jersey-servlet @@ -1572,6 +1618,11 @@ util ${yangtools.version} + + org.opendaylight.yangtools + yang-data-composite-node + ${yangtools.version} + @@ -1726,12 +1777,6 @@ slf4j-simple ${slf4j.version} - - junit - junit - ${junit.version} - test - org.opendaylight.controller commons.logback_settings @@ -1757,9 +1802,75 @@ ${yangtools.version} test + + org.opendaylight.controller + config-features + ${config.version} + features + xml + runtime + + + org.opendaylight.controller + features-odl-protocol-framework + ${protocol-framework.version} + features + xml + runtime + + + org.opendaylight.controller + netconf-features + ${netconf.version} + features + xml + runtime + + + org.opendaylight.controller + config-persister-features + ${config.version} + features + xml + runtime + + + org.opendaylight.controller + config-netty-features + ${config.version} + features + xml + runtime + + + org.opendaylight.controller + features-adsal + ${sal.version} + features + xml + runtime + + + org.opendaylight.controller + mdsal-features + ${mdsal.version} + features + xml + runtime + + + + + org.codehaus.sonar-plugins.java + sonar-jacoco-listeners + ${sonar-jacoco-listeners.version} + test + + + @@ -2053,6 +2164,30 @@ org.jacoco jacoco-maven-plugin ${jacoco.version} + + + prepare-ut-agent + process-test-classes + + prepare-agent + + + ${sonar.jacoco.reportPath} + jacoco.agent.ut.arg + + + + prepare-it-agent + pre-integration-test + + prepare-agent + + + ${sonar.jacoco.itReportPath} + jacoco.agent.it.arg + + + org.opendaylight.yangtools @@ -2129,13 +2264,20 @@ maven-failsafe-plugin ${failsafe.version} - ${testvm.argLine} + ${testvm.argLine} ${jacoco.agent.it.arg} logback.configurationFile logback.xml + + + + listener + org.sonar.java.jacoco.JUnitListener + + @@ -2159,19 +2301,30 @@ maven-surefire-plugin ${surefire.version} - ${testvm.argLine} + ${testvm.argLine} ${jacoco.agent.ut.arg} logback.configurationFile logback.xml + + + + listener + org.sonar.java.jacoco.JUnitListener + + org.codehaus.mojo build-helper-maven-plugin + + org.jacoco + jacoco-maven-plugin + diff --git a/opendaylight/commons/protocol-framework/pom.xml b/opendaylight/commons/protocol-framework/pom.xml index f70698731a..774bc7c23f 100644 --- a/opendaylight/commons/protocol-framework/pom.xml +++ b/opendaylight/commons/protocol-framework/pom.xml @@ -91,6 +91,11 @@ netty-event-executor-config test + + ch.qos.logback + logback-classic + test + diff --git a/opendaylight/commons/protocol-framework/src/main/java/org/opendaylight/protocol/framework/AbstractDispatcher.java b/opendaylight/commons/protocol-framework/src/main/java/org/opendaylight/protocol/framework/AbstractDispatcher.java index a62bd7da06..a05d02cd09 100644 --- a/opendaylight/commons/protocol-framework/src/main/java/org/opendaylight/protocol/framework/AbstractDispatcher.java +++ b/opendaylight/commons/protocol-framework/src/main/java/org/opendaylight/protocol/framework/AbstractDispatcher.java @@ -7,12 +7,19 @@ */ package org.opendaylight.protocol.framework; +import java.io.Closeable; +import java.net.InetSocketAddress; +import java.net.SocketAddress; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + import com.google.common.base.Preconditions; import io.netty.bootstrap.Bootstrap; import io.netty.bootstrap.ServerBootstrap; -import io.netty.channel.Channel; import io.netty.buffer.PooledByteBufAllocator; +import io.netty.channel.Channel; import io.netty.channel.ChannelFuture; import io.netty.channel.ChannelInitializer; import io.netty.channel.ChannelOption; @@ -28,13 +35,6 @@ import io.netty.util.concurrent.Future; import io.netty.util.concurrent.GlobalEventExecutor; import io.netty.util.concurrent.Promise; -import java.io.Closeable; -import java.net.InetSocketAddress; -import java.net.SocketAddress; - -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - /** * Dispatcher class for creating servers and clients. The idea is to first create servers and clients and the run the * start method that will handle sockets in different thread. @@ -155,7 +155,7 @@ public abstract class AbstractDispatcher, L extends */ protected Future createClient(final InetSocketAddress address, final ReconnectStrategy strategy, final PipelineInitializer initializer) { final Bootstrap b = new Bootstrap(); - final ProtocolSessionPromise p = new ProtocolSessionPromise(executor, address, strategy, b); + final ProtocolSessionPromise p = new ProtocolSessionPromise<>(executor, address, strategy, b); b.option(ChannelOption.SO_KEEPALIVE, true).handler( new ChannelInitializer() { @Override @@ -165,18 +165,36 @@ public abstract class AbstractDispatcher, L extends }); customizeBootstrap(b); + setWorkerGroup(b); + setChannelFactory(b); + + p.connect(); + LOG.debug("Client created."); + return p; + } + private void setWorkerGroup(final Bootstrap b) { if (b.group() == null) { b.group(workerGroup); } + } - // There is no way to detect if this was already set by - // customizeBootstrap() - try { - b.channel(NioSocketChannel.class); - } catch (IllegalStateException e) { - LOG.trace("Not overriding channelFactory on bootstrap {}", b, e); - } + /** + * Create a client but use a pre-configured bootstrap. + * This method however replaces the ChannelInitializer in the bootstrap. All other configuration is preserved. + * + * @param address remote address + */ + protected Future createClient(final InetSocketAddress address, final ReconnectStrategy strategy, final Bootstrap bootstrap, final PipelineInitializer initializer) { + final ProtocolSessionPromise p = new ProtocolSessionPromise<>(executor, address, strategy, bootstrap); + + bootstrap.handler( + new ChannelInitializer() { + @Override + protected void initChannel(final SocketChannel ch) { + initializer.initializeChannel(ch, p); + } + }); p.connect(); LOG.debug("Client created."); @@ -195,6 +213,9 @@ public abstract class AbstractDispatcher, L extends } /** + * + * @deprecated use {@link org.opendaylight.protocol.framework.AbstractDispatcher#createReconnectingClient(java.net.InetSocketAddress, ReconnectStrategyFactory, org.opendaylight.protocol.framework.AbstractDispatcher.PipelineInitializer)} with only one reconnectStrategyFactory instead. + * * Creates a client. * * @param address remote address @@ -204,15 +225,47 @@ public abstract class AbstractDispatcher, L extends * @return Future representing the reconnection task. It will report completion based on reestablishStrategy, e.g. * success if it indicates no further attempts should be made and failure if it reports an error */ + @Deprecated protected Future createReconnectingClient(final InetSocketAddress address, final ReconnectStrategyFactory connectStrategyFactory, final ReconnectStrategy reestablishStrategy, final PipelineInitializer initializer) { + return createReconnectingClient(address, connectStrategyFactory, initializer); + } - final ReconnectPromise p = new ReconnectPromise(GlobalEventExecutor.INSTANCE, this, address, connectStrategyFactory, reestablishStrategy, initializer); - p.connect(); + /** + * Creates a reconnecting client. + * + * @param address remote address + * @param connectStrategyFactory Factory for creating reconnection strategy for every reconnect attempt + * + * @return Future representing the reconnection task. It will report completion based on reestablishStrategy, e.g. + * success if it indicates no further attempts should be made and failure if it reports an error + */ + protected Future createReconnectingClient(final InetSocketAddress address, final ReconnectStrategyFactory connectStrategyFactory, + final PipelineInitializer initializer) { + final Bootstrap b = new Bootstrap(); + + final ReconnectPromise p = new ReconnectPromise<>(GlobalEventExecutor.INSTANCE, this, address, connectStrategyFactory, b, initializer); + + b.option(ChannelOption.SO_KEEPALIVE, true); + customizeBootstrap(b); + setWorkerGroup(b); + setChannelFactory(b); + + p.connect(); return p; } + private void setChannelFactory(final Bootstrap b) { + // There is no way to detect if this was already set by + // customizeBootstrap() + try { + b.channel(NioSocketChannel.class); + } catch (final IllegalStateException e) { + LOG.trace("Not overriding channelFactory on bootstrap {}", b, e); + } + } + /** * @deprecated Should only be used with {@link AbstractDispatcher#AbstractDispatcher()} */ @@ -225,5 +278,4 @@ public abstract class AbstractDispatcher, L extends this.bossGroup.shutdownGracefully(); } } - } diff --git a/opendaylight/commons/protocol-framework/src/main/java/org/opendaylight/protocol/framework/ProtocolSessionPromise.java b/opendaylight/commons/protocol-framework/src/main/java/org/opendaylight/protocol/framework/ProtocolSessionPromise.java index a78274cca0..a38db61ead 100644 --- a/opendaylight/commons/protocol-framework/src/main/java/org/opendaylight/protocol/framework/ProtocolSessionPromise.java +++ b/opendaylight/commons/protocol-framework/src/main/java/org/opendaylight/protocol/framework/ProtocolSessionPromise.java @@ -7,6 +7,7 @@ */ package org.opendaylight.protocol.framework; +import com.google.common.base.Preconditions; import io.netty.bootstrap.Bootstrap; import io.netty.channel.ChannelFuture; import io.netty.channel.ChannelFutureListener; @@ -16,17 +17,12 @@ import io.netty.util.concurrent.EventExecutor; import io.netty.util.concurrent.Future; import io.netty.util.concurrent.FutureListener; import io.netty.util.concurrent.Promise; - import java.net.InetSocketAddress; - import javax.annotation.concurrent.GuardedBy; import javax.annotation.concurrent.ThreadSafe; - import org.slf4j.Logger; import org.slf4j.LoggerFactory; -import com.google.common.base.Preconditions; - @ThreadSafe final class ProtocolSessionPromise> extends DefaultPromise { private static final Logger LOG = LoggerFactory.getLogger(ProtocolSessionPromise.class); @@ -54,72 +50,12 @@ final class ProtocolSessionPromise> extends Default LOG.debug("Promise {} attempting connect for {}ms", lock, timeout); this.b.option(ChannelOption.CONNECT_TIMEOUT_MILLIS, timeout); - this.pending = this.b.connect(this.address).addListener(new ChannelFutureListener() { - @Override - public void operationComplete(final ChannelFuture cf) throws Exception { - synchronized (lock) { - - LOG.debug("Promise {} connection resolved", lock); - - // Triggered when a connection attempt is resolved. - Preconditions.checkState(ProtocolSessionPromise.this.pending.equals(cf)); - - /* - * The promise we gave out could have been cancelled, - * which cascades to the connect getting cancelled, - * but there is a slight race window, where the connect - * is already resolved, but the listener has not yet - * been notified -- cancellation at that point won't - * stop the notification arriving, so we have to close - * the race here. - */ - if (isCancelled()) { - if (cf.isSuccess()) { - LOG.debug("Closing channel for cancelled promise {}", lock); - cf.channel().close(); - } - return; - } - - if (!cf.isSuccess()) { - LOG.debug("Attempt to connect to {} failed", ProtocolSessionPromise.this.address, cf.cause()); - - final Future rf = ProtocolSessionPromise.this.strategy.scheduleReconnect(cf.cause()); - rf.addListener(new FutureListener() { - @Override - public void operationComplete(final Future sf) { - synchronized (lock) { - // Triggered when a connection attempt is to be made. - Preconditions.checkState(ProtocolSessionPromise.this.pending.equals(sf)); - - /* - * The promise we gave out could have been cancelled, - * which cascades to the reconnect attempt getting - * cancelled, but there is a slight race window, where - * the reconnect attempt is already enqueued, but the - * listener has not yet been notified -- if cancellation - * happens at that point, we need to catch it here. - */ - if (!isCancelled()) { - if (sf.isSuccess()) { - connect(); - } else { - setFailure(sf.cause()); - } - } - } - } - }); - - ProtocolSessionPromise.this.pending = rf; - } else { - LOG.debug("Promise {} connection successful", lock); - } - } - } - }); + final ChannelFuture connectFuture = this.b.connect(this.address); + // Add listener that attempts reconnect by invoking this method again. + connectFuture.addListener(new BootstrapConnectListener(lock)); + this.pending = connectFuture; } catch (final Exception e) { - LOG.info("Failed to connect to {}", e); + LOG.info("Failed to connect to {}", address, e); setFailure(e); } } @@ -140,4 +76,79 @@ final class ProtocolSessionPromise> extends Default this.strategy.reconnectSuccessful(); return super.setSuccess(result); } + + private class BootstrapConnectListener implements ChannelFutureListener { + private final Object lock; + + public BootstrapConnectListener(final Object lock) { + this.lock = lock; + } + + @Override + public void operationComplete(final ChannelFuture cf) throws Exception { + synchronized (lock) { + + LOG.debug("Promise {} connection resolved", lock); + + // Triggered when a connection attempt is resolved. + Preconditions.checkState(ProtocolSessionPromise.this.pending.equals(cf)); + + /* + * The promise we gave out could have been cancelled, + * which cascades to the connect getting cancelled, + * but there is a slight race window, where the connect + * is already resolved, but the listener has not yet + * been notified -- cancellation at that point won't + * stop the notification arriving, so we have to close + * the race here. + */ + if (isCancelled()) { + if (cf.isSuccess()) { + LOG.debug("Closing channel for cancelled promise {}", lock); + cf.channel().close(); + } + return; + } + + if(cf.isSuccess()) { + LOG.debug("Promise {} connection successful", lock); + return; + } + + LOG.debug("Attempt to connect to {} failed", ProtocolSessionPromise.this.address, cf.cause()); + + final Future rf = ProtocolSessionPromise.this.strategy.scheduleReconnect(cf.cause()); + rf.addListener(new ReconnectingStrategyListener()); + ProtocolSessionPromise.this.pending = rf; + } + } + + private class ReconnectingStrategyListener implements FutureListener { + @Override + public void operationComplete(final Future sf) { + synchronized (lock) { + // Triggered when a connection attempt is to be made. + Preconditions.checkState(ProtocolSessionPromise.this.pending.equals(sf)); + + /* + * The promise we gave out could have been cancelled, + * which cascades to the reconnect attempt getting + * cancelled, but there is a slight race window, where + * the reconnect attempt is already enqueued, but the + * listener has not yet been notified -- if cancellation + * happens at that point, we need to catch it here. + */ + if (!isCancelled()) { + if (sf.isSuccess()) { + connect(); + } else { + setFailure(sf.cause()); + } + } + } + } + } + + } + } diff --git a/opendaylight/commons/protocol-framework/src/main/java/org/opendaylight/protocol/framework/ReconnectPromise.java b/opendaylight/commons/protocol-framework/src/main/java/org/opendaylight/protocol/framework/ReconnectPromise.java index 1fa6a81753..fe1012f443 100644 --- a/opendaylight/commons/protocol-framework/src/main/java/org/opendaylight/protocol/framework/ReconnectPromise.java +++ b/opendaylight/commons/protocol-framework/src/main/java/org/opendaylight/protocol/framework/ReconnectPromise.java @@ -7,176 +7,100 @@ */ package org.opendaylight.protocol.framework; -import io.netty.channel.ChannelFuture; +import com.google.common.base.Preconditions; +import io.netty.bootstrap.Bootstrap; +import io.netty.channel.ChannelHandlerContext; +import io.netty.channel.ChannelInboundHandlerAdapter; import io.netty.channel.socket.SocketChannel; import io.netty.util.concurrent.DefaultPromise; import io.netty.util.concurrent.EventExecutor; import io.netty.util.concurrent.Future; -import io.netty.util.concurrent.FutureListener; import io.netty.util.concurrent.Promise; - -import java.io.Closeable; import java.net.InetSocketAddress; -import java.util.concurrent.atomic.AtomicBoolean; - -import org.opendaylight.protocol.framework.AbstractDispatcher.PipelineInitializer; - -import com.google.common.base.Preconditions; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; final class ReconnectPromise, L extends SessionListener> extends DefaultPromise { + private static final Logger LOG = LoggerFactory.getLogger(ReconnectPromise.class); + private final AbstractDispatcher dispatcher; private final InetSocketAddress address; private final ReconnectStrategyFactory strategyFactory; - private final ReconnectStrategy strategy; - private final PipelineInitializer initializer; + private final Bootstrap b; + private final AbstractDispatcher.PipelineInitializer initializer; private Future pending; - private final AtomicBoolean negotiationFinished = new AtomicBoolean(false); - public ReconnectPromise(final EventExecutor executor, final AbstractDispatcher dispatcher, final InetSocketAddress address, - final ReconnectStrategyFactory connectStrategyFactory, final ReconnectStrategy reestablishStrategy, - final PipelineInitializer initializer) { + final ReconnectStrategyFactory connectStrategyFactory, final Bootstrap b, final AbstractDispatcher.PipelineInitializer initializer) { super(executor); + this.b = b; + this.initializer = Preconditions.checkNotNull(initializer); this.dispatcher = Preconditions.checkNotNull(dispatcher); this.address = Preconditions.checkNotNull(address); this.strategyFactory = Preconditions.checkNotNull(connectStrategyFactory); - this.strategy = Preconditions.checkNotNull(reestablishStrategy); - this.initializer = Preconditions.checkNotNull(initializer); } - // FIXME: BUG-190: refactor - synchronized void connect() { - negotiationFinished.set(false); - final ReconnectStrategy cs = this.strategyFactory.createReconnectStrategy(); - final ReconnectStrategy rs = new ReconnectStrategy() { - @Override - public Future scheduleReconnect(final Throwable cause) { - return cs.scheduleReconnect(cause); - } - @Override - public void reconnectSuccessful() { - cs.reconnectSuccessful(); - } - - @Override - public int getConnectTimeout() throws Exception { - final int cst = cs.getConnectTimeout(); - final int rst = ReconnectPromise.this.strategy.getConnectTimeout(); - - if (cst == 0) { - return rst; - } - if (rst == 0) { - return cst; - } - return Math.min(cst, rst); - } - }; - - final Future cf = this.dispatcher.createClient(this.address, rs, new PipelineInitializer() { + // Set up a client with pre-configured bootstrap, but add a closed channel handler into the pipeline to support reconnect attempts + pending = this.dispatcher.createClient(this.address, cs, b, new AbstractDispatcher.PipelineInitializer() { @Override public void initializeChannel(final SocketChannel channel, final Promise promise) { - addChannelClosedListener(channel.closeFuture()); initializer.initializeChannel(channel, promise); + + // add closed channel handler + channel.pipeline().addFirst(new ClosedChannelHandler(ReconnectPromise.this)); } }); + } - final Object lock = this; - this.pending = cf; + /** + * + * @return true if initial connection was established successfully, false if initial connection failed due to e.g. Connection refused, Negotiation failed + */ + private boolean isInitialConnectFinished() { + Preconditions.checkNotNull(pending); + return pending.isDone() && pending.isSuccess(); + } - cf.addListener(new FutureListener() { + @Override + public synchronized boolean cancel(final boolean mayInterruptIfRunning) { + if (super.cancel(mayInterruptIfRunning)) { + Preconditions.checkNotNull(pending); + this.pending.cancel(mayInterruptIfRunning); + return true; + } - @Override - public void operationComplete(final Future future) { - synchronized (lock) { - if (!future.isSuccess()) { - final Future rf = ReconnectPromise.this.strategy.scheduleReconnect(cf.cause()); - - if(rf == null) { - // This should reflect: no more reconnecting strategies, enough - // Currently all reconnect strategies fail with exception, should return null - return; - } - - ReconnectPromise.this.pending = rf; - - rf.addListener(new FutureListener() { - @Override - public void operationComplete(final Future sf) { - synchronized (lock) { - /* - * The promise we gave out could have been cancelled, - * which cascades to the reconnect attempt getting - * cancelled, but there is a slight race window, where - * the reconnect attempt is already enqueued, but the - * listener has not yet been notified -- if cancellation - * happens at that point, we need to catch it here. - */ - if (!isCancelled()) { - if (sf.isSuccess()) { - connect(); - } else { - setFailure(sf.cause()); - } - } - } - } - }); - } else { - /* - * FIXME: BUG-190: we have a slight race window with cancellation - * here. Analyze and define its semantics. - */ - ReconnectPromise.this.strategy.reconnectSuccessful(); - negotiationFinished.set(true); - } - } - } - }); + return false; } - private final ClosedChannelListener closedChannelListener = new ClosedChannelListener(); - - class ClosedChannelListener implements Closeable, FutureListener { + /** + * Channel handler that responds to channelInactive event and reconnects the session. + * Only if the initial connection was successfully established and promise was not canceled. + */ + private static final class ClosedChannelHandler extends ChannelInboundHandlerAdapter { + private final ReconnectPromise promise; - private final AtomicBoolean stop = new AtomicBoolean(false); + public ClosedChannelHandler(final ReconnectPromise promise) { + this.promise = promise; + } @Override - public void operationComplete(final Future future) throws Exception { - if (stop.get()) { + public void channelInactive(final ChannelHandlerContext ctx) throws Exception { + if (promise.isCancelled()) { return; } - // Start reconnecting crashed session after negotiation was successful - if (!negotiationFinished.get()) { + // Check if initial connection was fully finished. If the session was dropped during negotiation, reconnect will not happen. + // Session can be dropped during negotiation on purpose by the client side and would make no sense to initiate reconnect + if (promise.isInitialConnectFinished() == false) { return; } - connect(); - } - - @Override - public void close() { - this.stop.set(true); + LOG.debug("Reconnecting after connection to {} was dropped", promise.address); + promise.connect(); } } - private void addChannelClosedListener(final ChannelFuture channelFuture) { - channelFuture.addListener(closedChannelListener); - } - - @Override - public synchronized boolean cancel(final boolean mayInterruptIfRunning) { - closedChannelListener.close(); - - if (super.cancel(mayInterruptIfRunning)) { - this.pending.cancel(mayInterruptIfRunning); - return true; - } - - return false; - } } diff --git a/opendaylight/commons/protocol-framework/src/main/java/org/opendaylight/protocol/framework/SessionListener.java b/opendaylight/commons/protocol-framework/src/main/java/org/opendaylight/protocol/framework/SessionListener.java index 3c429fc774..a756a0da7e 100644 --- a/opendaylight/commons/protocol-framework/src/main/java/org/opendaylight/protocol/framework/SessionListener.java +++ b/opendaylight/commons/protocol-framework/src/main/java/org/opendaylight/protocol/framework/SessionListener.java @@ -10,7 +10,7 @@ package org.opendaylight.protocol.framework; import java.util.EventListener; /** - * Listener that receives session state informations. This interface should be + * Listener that receives session state information. This interface should be * implemented by a protocol specific abstract class, that is extended by * a final class that implements the methods. */ diff --git a/opendaylight/commons/protocol-framework/src/test/java/org/opendaylight/protocol/framework/ServerTest.java b/opendaylight/commons/protocol-framework/src/test/java/org/opendaylight/protocol/framework/ServerTest.java index bead1ee49e..63026e384c 100644 --- a/opendaylight/commons/protocol-framework/src/test/java/org/opendaylight/protocol/framework/ServerTest.java +++ b/opendaylight/commons/protocol-framework/src/test/java/org/opendaylight/protocol/framework/ServerTest.java @@ -9,6 +9,14 @@ package org.opendaylight.protocol.framework; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertFalse; +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.timeout; +import static org.mockito.Mockito.times; +import static org.mockito.Mockito.verify; + import io.netty.channel.Channel; import io.netty.channel.ChannelFuture; import io.netty.channel.nio.NioEventLoopGroup; @@ -16,50 +24,139 @@ import io.netty.util.concurrent.DefaultPromise; import io.netty.util.concurrent.Future; import io.netty.util.concurrent.GlobalEventExecutor; import io.netty.util.concurrent.Promise; - +import io.netty.util.concurrent.SucceededFuture; import java.io.IOException; import java.net.InetSocketAddress; import java.util.concurrent.ExecutionException; import java.util.concurrent.TimeUnit; import java.util.concurrent.TimeoutException; - import org.junit.After; import org.junit.Before; import org.junit.Test; +import org.mockito.Mockito; public class ServerTest { SimpleDispatcher clientDispatcher, dispatcher; - final SimpleSessionListener pce = new SimpleSessionListener(); - SimpleSession session = null; ChannelFuture server = null; InetSocketAddress serverAddress; private NioEventLoopGroup eventLoopGroup; - + // Dedicated loop group for server, needed for testing reconnection client + // With dedicated server group we can simulate session drop by shutting only the server group down + private NioEventLoopGroup serverLoopGroup; @Before public void setUp() { final int port = 10000 + (int)(10000 * Math.random()); serverAddress = new InetSocketAddress("127.0.0.1", port); eventLoopGroup = new NioEventLoopGroup(); + serverLoopGroup = new NioEventLoopGroup(); + } + + @After + public void tearDown() throws IOException, InterruptedException, ExecutionException { + if(server != null) { + this.server.channel().close(); + } + this.eventLoopGroup.shutdownGracefully().get(); + this.serverLoopGroup.shutdownGracefully().get(); + try { + Thread.sleep(500); + } catch (final InterruptedException e) { + throw new RuntimeException(e); + } } @Test - public void testConnectionEstablished() throws Exception { + public void testConnectionRefused() throws Exception { + this.clientDispatcher = getClientDispatcher(); + + final ReconnectStrategy mockReconnectStrategy = getMockedReconnectStrategy(); + + this.clientDispatcher.createClient(this.serverAddress, + mockReconnectStrategy, new SessionListenerFactory() { + @Override + public SimpleSessionListener getSessionListener() { + return new SimpleSessionListener(); + } + }); + + Mockito.verify(mockReconnectStrategy, timeout(5000).atLeast(2)).scheduleReconnect(any(Throwable.class)); + } + + @Test + public void testConnectionReestablishInitial() throws Exception { + this.clientDispatcher = getClientDispatcher(); + + final ReconnectStrategy mockReconnectStrategy = getMockedReconnectStrategy(); + + this.clientDispatcher.createClient(this.serverAddress, + mockReconnectStrategy, new SessionListenerFactory() { + @Override + public SimpleSessionListener getSessionListener() { + return new SimpleSessionListener(); + } + }); + + Mockito.verify(mockReconnectStrategy, timeout(5000).atLeast(2)).scheduleReconnect(any(Throwable.class)); + + final Promise p = new DefaultPromise<>(GlobalEventExecutor.INSTANCE); + this.dispatcher = getServerDispatcher(p); + + this.server = this.dispatcher.createServer(this.serverAddress, new SessionListenerFactory() { + @Override + public SimpleSessionListener getSessionListener() { + return new SimpleSessionListener(); + } + }); + + this.server.get(); + + assertEquals(true, p.get(3, TimeUnit.SECONDS)); + } + + @Test + public void testConnectionDrop() throws Exception { final Promise p = new DefaultPromise<>(GlobalEventExecutor.INSTANCE); - this.dispatcher = new SimpleDispatcher(new SessionNegotiatorFactory() { + this.dispatcher = getServerDispatcher(p); + this.server = this.dispatcher.createServer(this.serverAddress, new SessionListenerFactory() { @Override - public SessionNegotiator getSessionNegotiator(final SessionListenerFactory factory, - final Channel channel, final Promise promise) { - p.setSuccess(true); - return new SimpleSessionNegotiator(promise, channel); + public SimpleSessionListener getSessionListener() { + return new SimpleSessionListener(); } - }, new DefaultPromise(GlobalEventExecutor.INSTANCE), eventLoopGroup); + }); + + this.server.get(); + + this.clientDispatcher = getClientDispatcher(); + + final ReconnectStrategy reconnectStrategy = getMockedReconnectStrategy(); + this.session = this.clientDispatcher.createClient(this.serverAddress, + reconnectStrategy, new SessionListenerFactory() { + @Override + public SimpleSessionListener getSessionListener() { + return new SimpleSessionListener(); + } + }).get(6, TimeUnit.SECONDS); + + assertEquals(true, p.get(3, TimeUnit.SECONDS)); + + shutdownServer(); + + // No reconnect should be scheduled after server drops connection with not-reconnecting client + verify(reconnectStrategy, times(0)).scheduleReconnect(any(Throwable.class)); + } + + @Test + public void testConnectionReestablishAfterDrop() throws Exception { + final Promise p = new DefaultPromise<>(GlobalEventExecutor.INSTANCE); + + this.dispatcher = getServerDispatcher(p); this.server = this.dispatcher.createServer(this.serverAddress, new SessionListenerFactory() { @Override @@ -70,13 +167,42 @@ public class ServerTest { this.server.get(); - this.clientDispatcher = new SimpleDispatcher(new SessionNegotiatorFactory() { + this.clientDispatcher = getClientDispatcher(); + + final ReconnectStrategyFactory reconnectStrategyFactory = mock(ReconnectStrategyFactory.class); + final ReconnectStrategy reconnectStrategy = getMockedReconnectStrategy(); + doReturn(reconnectStrategy).when(reconnectStrategyFactory).createReconnectStrategy(); + + this.clientDispatcher.createReconnectingClient(this.serverAddress, + reconnectStrategyFactory, new SessionListenerFactory() { + @Override + public SimpleSessionListener getSessionListener() { + return new SimpleSessionListener(); + } + }); + + assertEquals(true, p.get(3, TimeUnit.SECONDS)); + shutdownServer(); + + verify(reconnectStrategyFactory, timeout(20000).atLeast(2)).createReconnectStrategy(); + } + + @Test + public void testConnectionEstablished() throws Exception { + final Promise p = new DefaultPromise<>(GlobalEventExecutor.INSTANCE); + + this.dispatcher = getServerDispatcher(p); + + this.server = this.dispatcher.createServer(this.serverAddress, new SessionListenerFactory() { @Override - public SessionNegotiator getSessionNegotiator(final SessionListenerFactory factory, - final Channel channel, final Promise promise) { - return new SimpleSessionNegotiator(promise, channel); + public SimpleSessionListener getSessionListener() { + return new SimpleSessionListener(); } - }, new DefaultPromise(GlobalEventExecutor.INSTANCE), eventLoopGroup); + }); + + this.server.get(); + + this.clientDispatcher = getClientDispatcher(); this.session = this.clientDispatcher.createClient(this.serverAddress, new NeverReconnectStrategy(GlobalEventExecutor.INSTANCE, 5000), new SessionListenerFactory() { @@ -93,15 +219,7 @@ public class ServerTest { public void testConnectionFailed() throws IOException, InterruptedException, ExecutionException, TimeoutException { final Promise p = new DefaultPromise<>(GlobalEventExecutor.INSTANCE); - this.dispatcher = new SimpleDispatcher(new SessionNegotiatorFactory() { - - @Override - public SessionNegotiator getSessionNegotiator(final SessionListenerFactory factory, - final Channel channel, final Promise promise) { - p.setSuccess(true); - return new SimpleSessionNegotiator(promise, channel); - } - }, new DefaultPromise(GlobalEventExecutor.INSTANCE), eventLoopGroup); + this.dispatcher = getServerDispatcher(p); this.server = this.dispatcher.createServer(this.serverAddress, new SessionListenerFactory() { @Override @@ -112,13 +230,7 @@ public class ServerTest { this.server.get(); - this.clientDispatcher = new SimpleDispatcher(new SessionNegotiatorFactory() { - @Override - public SessionNegotiator getSessionNegotiator(final SessionListenerFactory factory, - final Channel channel, final Promise promise) { - return new SimpleSessionNegotiator(promise, channel); - } - }, new DefaultPromise(GlobalEventExecutor.INSTANCE), eventLoopGroup); + this.clientDispatcher = getClientDispatcher(); this.session = this.clientDispatcher.createClient(this.serverAddress, new NeverReconnectStrategy(GlobalEventExecutor.INSTANCE, 5000), new SessionListenerFactory() { @@ -138,14 +250,89 @@ public class ServerTest { assertFalse(session.isSuccess()); } - @After - public void tearDown() throws IOException, InterruptedException { - this.server.channel().close(); - this.eventLoopGroup.shutdownGracefully(); - try { - Thread.sleep(500); - } catch (final InterruptedException e) { - throw new RuntimeException(e); - } + @Test + public void testNegotiationFailedNoReconnect() throws Exception { + final Promise p = new DefaultPromise<>(GlobalEventExecutor.INSTANCE); + + this.dispatcher = getServerDispatcher(p); + + this.server = this.dispatcher.createServer(this.serverAddress, new SessionListenerFactory() { + @Override + public SimpleSessionListener getSessionListener() { + return new SimpleSessionListener(); + } + }); + + this.server.get(); + + this.clientDispatcher = new SimpleDispatcher(new SessionNegotiatorFactory() { + @Override + public SessionNegotiator getSessionNegotiator(final SessionListenerFactory factory, + final Channel channel, final Promise promise) { + + return new SimpleSessionNegotiator(promise, channel) { + @Override + protected void startNegotiation() throws Exception { + negotiationFailed(new IllegalStateException("Negotiation failed")); + } + }; + } + }, new DefaultPromise(GlobalEventExecutor.INSTANCE), eventLoopGroup); + + final ReconnectStrategyFactory reconnectStrategyFactory = mock(ReconnectStrategyFactory.class); + final ReconnectStrategy reconnectStrategy = getMockedReconnectStrategy(); + doReturn(reconnectStrategy).when(reconnectStrategyFactory).createReconnectStrategy(); + + this.clientDispatcher.createReconnectingClient(this.serverAddress, + reconnectStrategyFactory, new SessionListenerFactory() { + @Override + public SimpleSessionListener getSessionListener() { + return new SimpleSessionListener(); + } + }); + + + // Only one strategy should be created for initial connect, no more = no reconnects + verify(reconnectStrategyFactory, times(1)).createReconnectStrategy(); } + + private SimpleDispatcher getClientDispatcher() { + return new SimpleDispatcher(new SessionNegotiatorFactory() { + @Override + public SessionNegotiator getSessionNegotiator(final SessionListenerFactory factory, + final Channel channel, final Promise promise) { + return new SimpleSessionNegotiator(promise, channel); + } + }, new DefaultPromise(GlobalEventExecutor.INSTANCE), eventLoopGroup); + } + + private ReconnectStrategy getMockedReconnectStrategy() throws Exception { + final ReconnectStrategy mockReconnectStrategy = mock(ReconnectStrategy.class); + final Future future = new SucceededFuture<>(GlobalEventExecutor.INSTANCE, null); + doReturn(future).when(mockReconnectStrategy).scheduleReconnect(any(Throwable.class)); + doReturn(5000).when(mockReconnectStrategy).getConnectTimeout(); + doNothing().when(mockReconnectStrategy).reconnectSuccessful(); + return mockReconnectStrategy; + } + + + private void shutdownServer() throws InterruptedException, ExecutionException { + // Shutdown server + server.channel().close().get(); + // Closing server channel does not close established connections, eventLoop has to be closed as well to simulate dropped session + serverLoopGroup.shutdownGracefully().get(); + } + + private SimpleDispatcher getServerDispatcher(final Promise p) { + return new SimpleDispatcher(new SessionNegotiatorFactory() { + + @Override + public SessionNegotiator getSessionNegotiator(final SessionListenerFactory factory, + final Channel channel, final Promise promise) { + p.setSuccess(true); + return new SimpleSessionNegotiator(promise, channel); + } + }, null, serverLoopGroup); + } + } diff --git a/opendaylight/commons/protocol-framework/src/test/java/org/opendaylight/protocol/framework/SimpleDispatcher.java b/opendaylight/commons/protocol-framework/src/test/java/org/opendaylight/protocol/framework/SimpleDispatcher.java index 12aac9ecc5..d83738520c 100644 --- a/opendaylight/commons/protocol-framework/src/test/java/org/opendaylight/protocol/framework/SimpleDispatcher.java +++ b/opendaylight/commons/protocol-framework/src/test/java/org/opendaylight/protocol/framework/SimpleDispatcher.java @@ -54,6 +54,10 @@ public class SimpleDispatcher extends AbstractDispatcher createReconnectingClient(final InetSocketAddress address, final ReconnectStrategyFactory strategy, final SessionListenerFactory listenerFactory) { + return super.createReconnectingClient(address, strategy, new SimplePipelineInitializer(listenerFactory)); + } + public ChannelFuture createServer(final InetSocketAddress address, final SessionListenerFactory listenerFactory) { return super.createServer(address, new SimplePipelineInitializer(listenerFactory)); } diff --git a/opendaylight/config/config-manager/pom.xml b/opendaylight/config/config-manager/pom.xml index fc2c0fd85b..c98a47660e 100644 --- a/opendaylight/config/config-manager/pom.xml +++ b/opendaylight/config/config-manager/pom.xml @@ -91,16 +91,6 @@ org.apache.maven.plugins maven-jar-plugin - - org.apache.maven.plugins - maven-surefire-plugin - - 1 - false - false - 1 - - diff --git a/opendaylight/config/config-manager/src/main/java/org/opendaylight/controller/config/manager/impl/osgi/mapping/CodecRegistryProvider.java b/opendaylight/config/config-manager/src/main/java/org/opendaylight/controller/config/manager/impl/osgi/mapping/CodecRegistryProvider.java index ec46219aaf..6050f7c070 100644 --- a/opendaylight/config/config-manager/src/main/java/org/opendaylight/controller/config/manager/impl/osgi/mapping/CodecRegistryProvider.java +++ b/opendaylight/config/config-manager/src/main/java/org/opendaylight/controller/config/manager/impl/osgi/mapping/CodecRegistryProvider.java @@ -14,7 +14,7 @@ import org.opendaylight.yangtools.sal.binding.generator.api.ClassLoadingStrategy import org.opendaylight.yangtools.sal.binding.generator.impl.RuntimeGeneratedMappingServiceImpl; import org.opendaylight.yangtools.yang.data.impl.codec.BindingIndependentMappingService; import org.opendaylight.yangtools.yang.data.impl.codec.CodecRegistry; -import org.opendaylight.yangtools.yang.model.api.SchemaServiceListener; +import org.opendaylight.yangtools.yang.model.api.SchemaContextListener; import org.osgi.framework.BundleContext; /** @@ -31,7 +31,7 @@ public class CodecRegistryProvider implements AutoCloseable { public CodecRegistryProvider(final ClassLoadingStrategy classLoadingStrategy, final BundleContext context) { service = new RuntimeGeneratedMappingServiceImpl(CLASS_POOL, classLoadingStrategy); registration = OsgiRegistrationUtil.registerService(context, service, - SchemaServiceListener.class, BindingIndependentMappingService.class); + SchemaContextListener.class, BindingIndependentMappingService.class); } public CodecRegistry getCodecRegistry() { diff --git a/opendaylight/config/config-manager/src/test/java/org/opendaylight/controller/config/manager/impl/runtimembean/RuntimeBeanRegistratorImplTest.java b/opendaylight/config/config-manager/src/test/java/org/opendaylight/controller/config/manager/impl/runtimembean/RuntimeBeanRegistratorImplTest.java index ce3648d160..16de00508a 100644 --- a/opendaylight/config/config-manager/src/test/java/org/opendaylight/controller/config/manager/impl/runtimembean/RuntimeBeanRegistratorImplTest.java +++ b/opendaylight/config/config-manager/src/test/java/org/opendaylight/controller/config/manager/impl/runtimembean/RuntimeBeanRegistratorImplTest.java @@ -7,10 +7,12 @@ */ package org.opendaylight.controller.config.manager.impl.runtimembean; +import static org.hamcrest.CoreMatchers.containsString; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertThat; import static org.junit.Assert.fail; -import static org.junit.internal.matchers.StringContains.containsString; +import com.google.common.collect.ImmutableMap; +import com.google.common.collect.Maps; import java.lang.management.ManagementFactory; import java.util.Map; @@ -29,9 +31,6 @@ import org.opendaylight.controller.config.manager.impl.jmx.BaseJMXRegistrator; import org.opendaylight.controller.config.manager.impl.jmx.HierarchicalRuntimeBeanRegistrationImpl; import org.opendaylight.controller.config.manager.impl.jmx.RootRuntimeBeanRegistratorImpl; -import com.google.common.collect.ImmutableMap; -import com.google.common.collect.Maps; - public class RuntimeBeanRegistratorImplTest extends AbstractLockedPlatformMBeanServerTest { static final String module1 = "module1"; @@ -60,11 +59,11 @@ public class RuntimeBeanRegistratorImplTest extends assertEquals(0, baseJMXRegistrator.getRegisteredObjectNames().size()); } - protected void checkExists(ObjectName on) throws Exception { + protected void checkExists(final ObjectName on) throws Exception { platformMBeanServer.getMBeanInfo(on); } - protected void checkNotExists(ObjectName on) throws Exception { + protected void checkNotExists(final ObjectName on) throws Exception { try { platformMBeanServer.getMBeanInfo(on); fail(); @@ -98,7 +97,7 @@ public class RuntimeBeanRegistratorImplTest extends } private HierarchicalRuntimeBeanRegistration createAdditional( - HierarchicalRuntimeBeanRegistrationImpl rootRegistration) + final HierarchicalRuntimeBeanRegistrationImpl rootRegistration) throws Exception { HierarchicalRuntimeBeanRegistrationImpl registration = rootRegistration diff --git a/opendaylight/config/config-manager/src/test/java/org/opendaylight/controller/config/manager/testingservices/parallelapsp/test/DependentWiringTest.java b/opendaylight/config/config-manager/src/test/java/org/opendaylight/controller/config/manager/testingservices/parallelapsp/test/DependentWiringTest.java index c9810d0521..165a6c7ed6 100644 --- a/opendaylight/config/config-manager/src/test/java/org/opendaylight/controller/config/manager/testingservices/parallelapsp/test/DependentWiringTest.java +++ b/opendaylight/config/config-manager/src/test/java/org/opendaylight/controller/config/manager/testingservices/parallelapsp/test/DependentWiringTest.java @@ -7,14 +7,16 @@ */ package org.opendaylight.controller.config.manager.testingservices.parallelapsp.test; +import static org.hamcrest.CoreMatchers.containsString; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertThat; import static org.junit.Assert.assertTrue; import static org.junit.Assert.fail; -import static org.junit.internal.matchers.StringContains.containsString; import java.util.Map; + import javax.management.ObjectName; + import org.junit.After; import org.junit.Before; import org.junit.Test; diff --git a/opendaylight/config/config-netty-config/pom.xml b/opendaylight/config/config-netty-config/pom.xml new file mode 100644 index 0000000000..8dc31dcc4e --- /dev/null +++ b/opendaylight/config/config-netty-config/pom.xml @@ -0,0 +1,46 @@ + + + + + 4.0.0 + + org.opendaylight.controller + config-subsystem + 0.2.5-SNAPSHOT + + config-netty-config + Configuration files for sal-rest-connector + jar + + + + org.codehaus.mojo + build-helper-maven-plugin + + + attach-artifacts + + attach-artifact + + package + + + + ${project.build.directory}/classes/initial/00-netty.xml + xml + config + + + + + + + + + diff --git a/opendaylight/distribution/opendaylight/src/main/resources/configuration/initial/00-netty.xml b/opendaylight/config/config-netty-config/src/main/resources/initial/00-netty.xml similarity index 99% rename from opendaylight/distribution/opendaylight/src/main/resources/configuration/initial/00-netty.xml rename to opendaylight/config/config-netty-config/src/main/resources/initial/00-netty.xml index 686d363110..2bf5b36d7a 100644 --- a/opendaylight/distribution/opendaylight/src/main/resources/configuration/initial/00-netty.xml +++ b/opendaylight/config/config-netty-config/src/main/resources/initial/00-netty.xml @@ -15,7 +15,7 @@ urn:opendaylight:params:xml:ns:yang:controller:netty:timer?module=netty-timer&revision=2013-11-19 - + @@ -35,7 +35,7 @@ singleton - + netty:netty-threadgroup diff --git a/opendaylight/config/config-util/pom.xml b/opendaylight/config/config-util/pom.xml index 7429f4d574..fd9c1b91e3 100644 --- a/opendaylight/config/config-util/pom.xml +++ b/opendaylight/config/config-util/pom.xml @@ -32,16 +32,6 @@ org.apache.maven.plugins maven-jar-plugin - - org.apache.maven.plugins - maven-surefire-plugin - - 1 - false - false - 1 - - org.apache.felix maven-bundle-plugin diff --git a/opendaylight/config/pom.xml b/opendaylight/config/pom.xml index 66bb01f051..343d13e9c1 100644 --- a/opendaylight/config/pom.xml +++ b/opendaylight/config/pom.xml @@ -39,6 +39,7 @@ shutdown-impl netconf-config-dispatcher config-module-archetype + config-netty-config @@ -93,18 +94,6 @@ - - org.apache.maven.plugins - maven-surefire-plugin - - true - classes - 1C - false - true - 2 - - org.codehaus.groovy.maven gmaven-plugin diff --git a/opendaylight/config/yang-jmx-generator-it/pom.xml b/opendaylight/config/yang-jmx-generator-it/pom.xml index c91881bd3e..f9e0c7036a 100644 --- a/opendaylight/config/yang-jmx-generator-it/pom.xml +++ b/opendaylight/config/yang-jmx-generator-it/pom.xml @@ -42,39 +42,4 @@ test - - - - - org.apache.maven.plugins - maven-surefire-plugin - - 1 - false - false - - - - default-test - - true - - - - integration-tests - - test - - integration-test - - - **/org/opendaylight/controller/config/yangjmxgenerator/it/*.java - - false - - - - - - diff --git a/opendaylight/config/yang-jmx-generator/src/test/java/org/opendaylight/controller/config/yangjmxgenerator/RuntimeBeanEntryTest.java b/opendaylight/config/yang-jmx-generator/src/test/java/org/opendaylight/controller/config/yangjmxgenerator/RuntimeBeanEntryTest.java index b570302563..e80ebc67a5 100644 --- a/opendaylight/config/yang-jmx-generator/src/test/java/org/opendaylight/controller/config/yangjmxgenerator/RuntimeBeanEntryTest.java +++ b/opendaylight/config/yang-jmx-generator/src/test/java/org/opendaylight/controller/config/yangjmxgenerator/RuntimeBeanEntryTest.java @@ -7,7 +7,22 @@ */ package org.opendaylight.controller.config.yangjmxgenerator; +import static junit.framework.Assert.assertNotNull; +import static junit.framework.Assert.assertNull; +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertTrue; +import static org.mockito.Mockito.doReturn; + +import java.util.ArrayList; +import java.util.Collection; import java.util.HashMap; +import java.util.HashSet; +import java.util.List; +import java.util.Map; + +import javax.management.openmbean.SimpleType; + import org.junit.Test; import org.mockito.Mockito; import org.opendaylight.controller.config.yangjmxgenerator.attribute.JavaAttribute; @@ -18,20 +33,6 @@ import org.opendaylight.yangtools.yang.model.api.IdentitySchemaNode; import org.opendaylight.yangtools.yang.model.api.LeafSchemaNode; import org.opendaylight.yangtools.yang.model.api.UnknownSchemaNode; -import javax.management.openmbean.SimpleType; -import java.util.ArrayList; -import java.util.Collection; -import java.util.HashSet; -import java.util.List; -import java.util.Map; - -import static junit.framework.Assert.assertNotNull; -import static junit.framework.Assert.assertNull; -import static org.hamcrest.CoreMatchers.is; - -import static org.junit.Assert.assertThat; -import static org.mockito.Mockito.doReturn; - public class RuntimeBeanEntryTest extends AbstractYangTest { public static final String PACKAGE_NAME = "packages.sis"; @@ -54,10 +55,10 @@ public class RuntimeBeanEntryTest extends AbstractYangTest { Map runtimeBeans = RuntimeBeanEntry .extractClassNameToRuntimeBeanMap(PACKAGE_NAME, caseNode, "test-name", new TypeProviderWrapper(new TypeProviderImpl(context)), "test", jmxImplModule); - assertThat(runtimeBeans.size(), is(1)); + assertEquals(1, runtimeBeans.size()); RuntimeBeanEntry runtimeMXBean = runtimeBeans.get("testRuntimeMXBean"); - assertThat(runtimeMXBean.isRoot(), is(true)); - assertThat(runtimeMXBean.getYangName(), is("test-name")); + assertTrue(runtimeMXBean.isRoot()); + assertEquals("test-name", runtimeMXBean.getYangName()); } @Test @@ -72,7 +73,7 @@ public class RuntimeBeanEntryTest extends AbstractYangTest { threadsJavaModule, modulesToSIEs, context, new TypeProviderWrapper(new TypeProviderImpl(context)), PACKAGE_NAME); - assertThat(namesToMBEs.isEmpty(), is(false)); + assertFalse(namesToMBEs.isEmpty()); // get threadfactory-naming bean ModuleMXBeanEntry threadfactoryNamingMXBean = namesToMBEs @@ -82,13 +83,13 @@ public class RuntimeBeanEntryTest extends AbstractYangTest { // get runtime beans Collection runtimeBeanEntries = threadfactoryNamingMXBean .getRuntimeBeans(); - assertThat(runtimeBeanEntries.isEmpty(), is(false)); + assertFalse(runtimeBeanEntries.isEmpty()); // get root runtime bean RuntimeBeanEntry threadfactoryRuntimeBeanEntry = getRuntimeBeanEntryByJavaName( runtimeBeanEntries, "NamingThreadFactoryRuntimeMXBean"); assertNotNull(threadfactoryRuntimeBeanEntry); - assertThat(threadfactoryRuntimeBeanEntry.isRoot(), is(true)); + assertTrue(threadfactoryRuntimeBeanEntry.isRoot()); // get thread runtime bean RuntimeBeanEntry runtimeBeanEntry = getRuntimeBeanEntryByJavaName( @@ -96,43 +97,41 @@ public class RuntimeBeanEntryTest extends AbstractYangTest { assertNotNull(runtimeBeanEntry); // test thread runtime bean properties - assertThat(runtimeBeanEntry.getJavaNamePrefix(), - is(THREAD_RUNTIME_BEAN_JAVA_PREFIX)); - assertThat(runtimeBeanEntry.getPackageName(), is(PACKAGE_NAME)); - assertThat(runtimeBeanEntry.getFullyQualifiedName(runtimeBeanEntry - .getJavaNameOfRuntimeMXBean()), is(PACKAGE_NAME + "." - + THREAD_RUNTIME_BEAN_JAVA_NAME)); - assertThat(runtimeBeanEntry.getYangName(), - is(THREAD_RUNTIME_BEAN_YANG_NAME)); + assertEquals(THREAD_RUNTIME_BEAN_JAVA_PREFIX, runtimeBeanEntry.getJavaNamePrefix()); + assertEquals(PACKAGE_NAME, runtimeBeanEntry.getPackageName()); + assertEquals(PACKAGE_NAME + "." + THREAD_RUNTIME_BEAN_JAVA_NAME, + runtimeBeanEntry.getFullyQualifiedName(runtimeBeanEntry + .getJavaNameOfRuntimeMXBean())); + assertEquals(THREAD_RUNTIME_BEAN_YANG_NAME, runtimeBeanEntry.getYangName()); // get thread runtime bean rpcs List rpcs = new ArrayList( runtimeBeanEntry.getRpcs()); - assertThat(rpcs.size(), is(2)); + assertEquals(2, rpcs.size()); // get sleep rpc and test it RuntimeBeanEntry.Rpc rpc = getRpcByName(rpcs, SLEEP_RPC_NAME); assertNotNull(rpc); - assertThat(rpc.getYangName(), is(SLEEP_RPC_NAME)); + assertEquals(SLEEP_RPC_NAME, rpc.getYangName()); - assertThat(((JavaAttribute)rpc.getReturnType()).getType().getFullyQualifiedName().endsWith(SLEEP_RPC_OUTPUT), is(true)); + assertTrue(((JavaAttribute)rpc.getReturnType()).getType().getFullyQualifiedName().endsWith(SLEEP_RPC_OUTPUT)); // get sleep rpc input attribute and test it List attributes = rpc.getParameters(); - assertThat(attributes.size(), is(1)); + assertEquals(1, attributes.size()); JavaAttribute attribute = attributes.get(0); - assertThat(attribute.getAttributeYangName(), is(SLEEP_RPC_INPUT_NAME)); - assertThat(attribute.getType().getName(), is(SLEEP_RPC_INPUT_TYPE)); - assertThat(attribute.getLowerCaseCammelCase(), is(SLEEP_RPC_INPUT_NAME)); - assertThat(attribute.getUpperCaseCammelCase(), is("Millis")); + assertEquals(SLEEP_RPC_INPUT_NAME, attribute.getAttributeYangName()); + assertEquals(SLEEP_RPC_INPUT_TYPE, attribute.getType().getName()); + assertEquals(SLEEP_RPC_INPUT_NAME, attribute.getLowerCaseCammelCase()); + assertEquals("Millis", attribute.getUpperCaseCammelCase()); assertNull(attribute.getNullableDefault()); assertNull(attribute.getNullableDescription()); - assertThat(attribute.getOpenType(), is(SimpleType.class)); + assertTrue(attribute.getOpenType() instanceof SimpleType); } private RuntimeBeanEntry getRuntimeBeanEntryByJavaName( final Collection runtimeBeanEntries, - String javaName) { + final String javaName) { if (runtimeBeanEntries != null && !runtimeBeanEntries.isEmpty()) { for (RuntimeBeanEntry runtimeBeanEntry : runtimeBeanEntries) { if (runtimeBeanEntry.getJavaNameOfRuntimeMXBean().equals( @@ -145,7 +144,7 @@ public class RuntimeBeanEntryTest extends AbstractYangTest { } private RuntimeBeanEntry.Rpc getRpcByName( - final List rpcs, String name) { + final List rpcs, final String name) { if (rpcs != null && !rpcs.isEmpty()) { for (RuntimeBeanEntry.Rpc rpc : rpcs) { if (rpc.getName().equals(name)) { diff --git a/opendaylight/distribution/opendaylight-karaf/pom.xml b/opendaylight/distribution/opendaylight-karaf/pom.xml index 977fab1334..5effbb09fc 100644 --- a/opendaylight/distribution/opendaylight-karaf/pom.xml +++ b/opendaylight/distribution/opendaylight-karaf/pom.xml @@ -64,7 +64,6 @@ org.opendaylight.controller config-netty-features - ${config.version} features xml runtime @@ -74,7 +73,6 @@ org.opendaylight.controller features-adsal - ${sal.version} features xml runtime @@ -92,7 +90,6 @@ org.opendaylight.controller mdsal-features - ${mdsal.version} features xml runtime diff --git a/opendaylight/distribution/opendaylight/pom.xml b/opendaylight/distribution/opendaylight/pom.xml index 541c1300f3..7ab56e6d03 100644 --- a/opendaylight/distribution/opendaylight/pom.xml +++ b/opendaylight/distribution/opendaylight/pom.xml @@ -745,8 +745,8 @@ generate-resources ${project.build.directory}/configuration - sal-rest-connector-config - **\/*.xml + sal-rest-connector-config,config-netty-config,md-sal-config,netconf-config,toaster-config,netconf-connector-config,sal-clustering-config + **\/*.xml,**/*.conf true false @@ -1034,6 +1034,26 @@ org.opendaylight.controller sal-rest-connector-config + + org.opendaylight.controller + config-netty-config + + + org.opendaylight.controller + md-sal-config + + + org.opendaylight.controller + netconf-config + + + org.opendaylight.controller + netconf-connector-config + + + org.opendaylight.controller.samples + toaster-config + org.opendaylight.controller sal-rest-docgen @@ -1042,6 +1062,11 @@ org.opendaylight.controller sal-restconf-broker + + org.opendaylight.controller + sal-remoterpc-connector + + org.opendaylight.controller @@ -1214,6 +1239,10 @@ org.opendaylight.yangtools yang-parser-impl + + org.opendaylight.yangtools + yang-data-composite-node + org.opendaylight.yangtools.model @@ -1267,6 +1296,14 @@ jeromq 0.3.1 + + org.opendaylight.controller + sal-distributed-datastore + + + org.opendaylight.controller + sal-clustering-config + @@ -1318,7 +1355,7 @@ generate-resources ${project.build.directory}/configuration - sal-rest-connector-config + sal-rest-connector-config,config-netty-config,md-sal-config,netconf-config,toaster-config,netconf-connector-config **\/*.xml true false diff --git a/opendaylight/hosttracker/api/src/main/java/org/opendaylight/controller/hosttracker/IHostTrackerShell.java b/opendaylight/hosttracker/api/src/main/java/org/opendaylight/controller/hosttracker/IHostTrackerShell.java new file mode 100644 index 0000000000..5d11be4826 --- /dev/null +++ b/opendaylight/hosttracker/api/src/main/java/org/opendaylight/controller/hosttracker/IHostTrackerShell.java @@ -0,0 +1,9 @@ +package org.opendaylight.controller.hosttracker; + +import java.util.List; + +public interface IHostTrackerShell{ + + public List dumpPendingArpReqList(); + public List dumpFailedArpReqList(); +} \ No newline at end of file diff --git a/opendaylight/hosttracker/implementation/src/main/java/org/opendaylight/controller/hosttracker/internal/Activator.java b/opendaylight/hosttracker/implementation/src/main/java/org/opendaylight/controller/hosttracker/internal/Activator.java index 825b2453aa..7e527712b1 100644 --- a/opendaylight/hosttracker/implementation/src/main/java/org/opendaylight/controller/hosttracker/internal/Activator.java +++ b/opendaylight/hosttracker/implementation/src/main/java/org/opendaylight/controller/hosttracker/internal/Activator.java @@ -16,6 +16,7 @@ import java.util.Set; import org.apache.felix.dm.Component; import org.opendaylight.controller.clustering.services.ICacheUpdateAware; import org.opendaylight.controller.clustering.services.IClusterContainerServices; +import org.opendaylight.controller.hosttracker.IHostTrackerShell; import org.opendaylight.controller.hosttracker.IfHostListener; import org.opendaylight.controller.hosttracker.IfIptoHost; import org.opendaylight.controller.hosttracker.IfNewHostNotify; @@ -78,6 +79,7 @@ public class Activator extends ComponentActivatorAbstractBase { IInventoryListener.class.getName(), IfIptoHost.class.getName(), IfHostListener.class.getName(), + IHostTrackerShell.class.getName(), ITopologyManagerAware.class.getName(), ICacheUpdateAware.class.getName() }, props); diff --git a/opendaylight/hosttracker/implementation/src/main/java/org/opendaylight/controller/hosttracker/internal/HostTracker.java b/opendaylight/hosttracker/implementation/src/main/java/org/opendaylight/controller/hosttracker/internal/HostTracker.java index ce49b599e1..f728b35bbf 100644 --- a/opendaylight/hosttracker/implementation/src/main/java/org/opendaylight/controller/hosttracker/internal/HostTracker.java +++ b/opendaylight/hosttracker/implementation/src/main/java/org/opendaylight/controller/hosttracker/internal/HostTracker.java @@ -39,6 +39,7 @@ import org.opendaylight.controller.clustering.services.IClusterContainerServices import org.opendaylight.controller.clustering.services.IClusterServices; import org.opendaylight.controller.hosttracker.HostIdFactory; import org.opendaylight.controller.hosttracker.IHostId; +import org.opendaylight.controller.hosttracker.IHostTrackerShell; import org.opendaylight.controller.hosttracker.IPHostId; import org.opendaylight.controller.hosttracker.IPMacHostId; import org.opendaylight.controller.hosttracker.IfHostListener; @@ -100,7 +101,7 @@ import org.slf4j.LoggerFactory; * */ -public class HostTracker implements IfIptoHost, IfHostListener, ISwitchManagerAware, IInventoryListener, +public class HostTracker implements IfIptoHost, IfHostListener, IHostTrackerShell, ISwitchManagerAware, IInventoryListener, ITopologyManagerAware, ICacheUpdateAware, CommandProvider { static final String ACTIVE_HOST_CACHE = "hosttracker.ActiveHosts"; static final String INACTIVE_HOST_CACHE = "hosttracker.InactiveHosts"; @@ -1618,4 +1619,24 @@ public class HostTracker implements IfIptoHost, IfHostListener, ISwitchManagerAw IHostId id = HostIdFactory.create(addr, null); return getHostNetworkHierarchy(id); } + + @Override + public List dumpPendingArpReqList() { + ARPPending arphost; + List arpReq = new ArrayList(); + for (Entry entry : ARPPendingList.entrySet()) { + arpReq.add(entry.getValue().getHostId().toString()); + } + return arpReq; + } + + @Override + public List dumpFailedArpReqList() { + ARPPending arphost; + List arpReq = new ArrayList(); + for (Entry entry : failedARPReqList.entrySet()) { + arpReq.add(entry.getValue().getHostId().toString()); + } + return arpReq; + } } diff --git a/opendaylight/hosttracker/shell/pom.xml b/opendaylight/hosttracker/shell/pom.xml new file mode 100644 index 0000000000..3f73303180 --- /dev/null +++ b/opendaylight/hosttracker/shell/pom.xml @@ -0,0 +1,52 @@ + + + 4.0.0 + + org.opendaylight.controller + commons.opendaylight + 1.4.2-SNAPSHOT + ../../commons/opendaylight + + hosttracker.shell + ${hosttracker.shell.version} + bundle + + + junit + junit + + + org.apache.karaf.shell + org.apache.karaf.shell.console + 3.0.0 + + + org.mockito + mockito-all + + + org.opendaylight.controller + hosttracker.implementation + ${hosttracker.implementation.version} + + + + + + + org.apache.felix + maven-bundle-plugin + ${bundle.plugin.version} + + + org.apache.felix.service.command, + org.apache.karaf.shell.commands, + org.apache.karaf.shell.console, + * + + + + + + + diff --git a/opendaylight/hosttracker/shell/src/main/java/org/opendaylight/controller/hosttracker/shell/DumpFailedARPReqList.java b/opendaylight/hosttracker/shell/src/main/java/org/opendaylight/controller/hosttracker/shell/DumpFailedARPReqList.java new file mode 100644 index 0000000000..ec9971f3c8 --- /dev/null +++ b/opendaylight/hosttracker/shell/src/main/java/org/opendaylight/controller/hosttracker/shell/DumpFailedARPReqList.java @@ -0,0 +1,28 @@ +package org.opendaylight.controller.hosttracker.shell; +/** +* Copyright (c) 2014 Inocybe Technologies, 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 +*/ + +import org.apache.felix.gogo.commands.Command; +import org.apache.karaf.shell.console.OsgiCommandSupport; +import org.opendaylight.controller.hosttracker.IHostTrackerShell; + +@Command(scope = "hosttracker", name = "dumpFailedARPReqList", description="Display the dump failed ARPReqList") +public class DumpFailedARPReqList extends OsgiCommandSupport{ + + private IHostTrackerShell hostTracker; + + @Override + protected Object doExecute() throws Exception { + System.out.print(hostTracker.dumpFailedArpReqList()); + return null; + } + + public void setHostTracker(IHostTrackerShell hostTracker){ + this.hostTracker = hostTracker; + } +} diff --git a/opendaylight/hosttracker/shell/src/main/java/org/opendaylight/controller/hosttracker/shell/DumpPendingARPReqList.java b/opendaylight/hosttracker/shell/src/main/java/org/opendaylight/controller/hosttracker/shell/DumpPendingARPReqList.java new file mode 100644 index 0000000000..7f52a55bd1 --- /dev/null +++ b/opendaylight/hosttracker/shell/src/main/java/org/opendaylight/controller/hosttracker/shell/DumpPendingARPReqList.java @@ -0,0 +1,28 @@ +package org.opendaylight.controller.hosttracker.shell; +/** +* Copyright (c) 2014 Inocybe Technologies, 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 +*/ + +import org.apache.felix.gogo.commands.Command; +import org.apache.karaf.shell.console.OsgiCommandSupport; +import org.opendaylight.controller.hosttracker.IHostTrackerShell; + +@Command(scope = "hosttracker", name = "dumpPendingARPReqList", description="Display the dump pending ARPReqList") +public class DumpPendingARPReqList extends OsgiCommandSupport{ + + private IHostTrackerShell hostTracker; + + @Override + protected Object doExecute() throws Exception { + System.out.print(hostTracker.dumpPendingArpReqList()); + return null; + } + + public void setHostTracker(IHostTrackerShell hostTracker){ + this.hostTracker = hostTracker; + } +} \ No newline at end of file diff --git a/opendaylight/hosttracker/shell/src/main/resources/OSGI-INF/blueprint/blueprint.xml b/opendaylight/hosttracker/shell/src/main/resources/OSGI-INF/blueprint/blueprint.xml new file mode 100644 index 0000000000..ba79b5d8c5 --- /dev/null +++ b/opendaylight/hosttracker/shell/src/main/resources/OSGI-INF/blueprint/blueprint.xml @@ -0,0 +1,17 @@ + + + + + + + + + + + + + + + + + diff --git a/opendaylight/hosttracker/shell/src/test/java/org/opendaylight/controller/hosttracker/shell/HostTrackerShellTest.java b/opendaylight/hosttracker/shell/src/test/java/org/opendaylight/controller/hosttracker/shell/HostTrackerShellTest.java new file mode 100644 index 0000000000..a0a5a2e610 --- /dev/null +++ b/opendaylight/hosttracker/shell/src/test/java/org/opendaylight/controller/hosttracker/shell/HostTrackerShellTest.java @@ -0,0 +1,47 @@ +package org.opendaylight.controller.hosttracker.shell; + +import java.io.ByteArrayOutputStream; +import java.io.PrintStream; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; + +import org.junit.Assert; +import org.junit.Test; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.when; +import org.opendaylight.controller.hosttracker.IHostTrackerShell; + +public class HostTrackerShellTest { + + private final long COMMAND_TIMEOUT = 1000; + private IHostTrackerShell hostTracker; + + @Test + public void testDumpPendingARPReqList() throws Exception { + DumpPendingARPReqList dumpPendTest = new DumpPendingARPReqList(); + hostTracker = mock(IHostTrackerShell.class); + List failedList = new ArrayList(Arrays.asList("a", "b", "c")); + when(hostTracker.dumpPendingArpReqList()).thenReturn(failedList); + dumpPendTest.setHostTracker(hostTracker); + ByteArrayOutputStream baos = new ByteArrayOutputStream(); + System.setOut(new PrintStream(baos)); + dumpPendTest.doExecute(); + //Assert.assertTrue(true); + Assert.assertEquals("[a, b, c]", baos.toString()); + } + + @Test + public void testDumpFailedARPReqList() throws Exception { + DumpFailedARPReqList dumpFailTest = new DumpFailedARPReqList(); + hostTracker = mock(IHostTrackerShell.class); + List failedList = new ArrayList(Arrays.asList("a", "b", "c")); + when(hostTracker.dumpFailedArpReqList()).thenReturn(failedList); + dumpFailTest.setHostTracker(hostTracker); + ByteArrayOutputStream baos = new ByteArrayOutputStream(); + System.setOut(new PrintStream(baos)); + dumpFailTest.doExecute(); + //Assert.assertTrue(true); + Assert.assertEquals("[a, b, c]", baos.toString()); + } +} diff --git a/opendaylight/md-sal/compatibility/flow-management-compatibility/pom.xml b/opendaylight/md-sal/compatibility/flow-management-compatibility/pom.xml deleted file mode 100644 index 7770c15349..0000000000 --- a/opendaylight/md-sal/compatibility/flow-management-compatibility/pom.xml +++ /dev/null @@ -1,74 +0,0 @@ - - - 4.0.0 - - org.opendaylight.controller - compatibility-parent - 1.1-SNAPSHOT - - flow-management-compatibility - bundle - - - - com.google.guava - guava - - - org.opendaylight.controller - forwardingrulesmanager - - - org.opendaylight.controller - sal-binding-api - - - org.opendaylight.controller - sal-common-util - - - org.opendaylight.controller - sal-compatibility - - - org.opendaylight.controller.model - model-flow-management - - - org.slf4j - slf4j-api - - - junit - junit - test - - - org.mockito - mockito-all - test - - - - - - - - org.apache.felix - maven-bundle-plugin - true - - - Forwarding Rules Manager Adapter for MD-SAL - - - - - - - scm:git:ssh://git.opendaylight.org:29418/controller.git - scm:git:ssh://git.opendaylight.org:29418/controller.git - HEAD - https://wiki.opendaylight.org/view/OpenDaylight_Controller:MD-SAL - - diff --git a/opendaylight/md-sal/compatibility/flow-management-compatibility/src/main/java/org/opendaylight/controller/md/frm/compatibility/ConfigurationReader.java b/opendaylight/md-sal/compatibility/flow-management-compatibility/src/main/java/org/opendaylight/controller/md/frm/compatibility/ConfigurationReader.java deleted file mode 100644 index 411af282bd..0000000000 --- a/opendaylight/md-sal/compatibility/flow-management-compatibility/src/main/java/org/opendaylight/controller/md/frm/compatibility/ConfigurationReader.java +++ /dev/null @@ -1,62 +0,0 @@ -/** - * Copyright (c) 2014 Cisco Systems, Inc. and others. All rights reserved. - * - * This program and the accompanying materials are made available under the - * terms of the Eclipse Public License v1.0 which accompanies this distribution, - * and is available at http://www.eclipse.org/legal/epl-v10.html - */ -package org.opendaylight.controller.md.frm.compatibility; - -import java.text.MessageFormat; -import java.util.ArrayList; -import java.util.List; - -import org.opendaylight.controller.forwardingrulesmanager.FlowConfig; -import org.opendaylight.controller.forwardingrulesmanager.IForwardingRulesManager; -import org.opendaylight.controller.sal.compatibility.NodeMapping; -import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.config.rev130819.Flows; -import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.config.rev130819.FlowsBuilder; -import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.config.rev130819.flows.Flow; -import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.config.rev130819.flows.FlowKey; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -public class ConfigurationReader implements FlowManagementReader { - - private final static Logger LOG = LoggerFactory.getLogger(ConfigurationReader.class); - - private IForwardingRulesManager manager; - - @Override - public Flows readAllFlows() { - List staticFlows = this.manager.getStaticFlows(); - List flowMap = new ArrayList(staticFlows.size()); - - for (FlowConfig conf : staticFlows) { - flowMap.add(FlowConfigMapping.toConfigurationFlow(conf)); - } - final FlowsBuilder flowsBuilder = new FlowsBuilder(); - return (flowsBuilder.setFlow(flowMap)).build(); - } - - @Override - public Flow readFlow(final FlowKey key) { - try { - final FlowConfig flowConf = - this.manager.getStaticFlow(String.valueOf(key.getId()), NodeMapping.toADNode(key.getNode())); - return FlowConfigMapping.toConfigurationFlow(flowConf); - } catch (Exception e) { - String errMsg = MessageFormat.format("readFlow by key {} fail", key); - LOG.error(errMsg, e); - throw new RuntimeException(errMsg, e); - } - } - - public IForwardingRulesManager getManager() { - return this.manager; - } - - public void setManager(final IForwardingRulesManager manager) { - this.manager = manager; - } -} diff --git a/opendaylight/md-sal/compatibility/flow-management-compatibility/src/main/java/org/opendaylight/controller/md/frm/compatibility/FRMRuntimeDataProvider.java b/opendaylight/md-sal/compatibility/flow-management-compatibility/src/main/java/org/opendaylight/controller/md/frm/compatibility/FRMRuntimeDataProvider.java deleted file mode 100644 index 0653eeb2a6..0000000000 --- a/opendaylight/md-sal/compatibility/flow-management-compatibility/src/main/java/org/opendaylight/controller/md/frm/compatibility/FRMRuntimeDataProvider.java +++ /dev/null @@ -1,119 +0,0 @@ -/** - * Copyright (c) 2014 Cisco Systems, Inc. and others. All rights reserved. - * - * This program and the accompanying materials are made available under the - * terms of the Eclipse Public License v1.0 which accompanies this distribution, - * and is available at http://www.eclipse.org/legal/epl-v10.html - */ -package org.opendaylight.controller.md.frm.compatibility; - -import org.opendaylight.controller.forwardingrulesmanager.FlowConfig; -import org.opendaylight.controller.forwardingrulesmanager.IForwardingRulesManager; -import org.opendaylight.controller.md.sal.common.api.data.DataChangeListener; -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.binding.api.data.DataProviderService; -import org.opendaylight.controller.sal.binding.api.data.RuntimeDataProvider; -import org.opendaylight.controller.sal.common.util.Arguments; -import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.config.rev130819.Flows; -import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.config.rev130819.flows.FlowKey; -import org.opendaylight.yangtools.concepts.Registration; -import org.opendaylight.yangtools.yang.binding.DataObject; -import org.opendaylight.yangtools.yang.binding.Identifier; -import org.opendaylight.yangtools.yang.binding.InstanceIdentifier; -import org.opendaylight.yangtools.yang.binding.InstanceIdentifier.IdentifiableItem; -import org.opendaylight.yangtools.yang.binding.InstanceIdentifier.PathArgument; -import org.opendaylight.yangtools.yang.common.RpcResult; -import org.opendaylight.yangtools.yang.common.RpcResultBuilder; - -import com.google.common.base.Objects; -import com.google.common.base.Preconditions; - -public class FRMRuntimeDataProvider implements RuntimeDataProvider, DataCommitHandler,DataObject> { - - private final static InstanceIdentifier FLOWS_PATH = InstanceIdentifier. builder(Flows.class).toInstance(); - - private final FlowManagementReader configuration = new ConfigurationReader(); - private DataChangeListener, DataObject> changeListener; - private DataProviderService dataService; - private IForwardingRulesManager manager; - - public Registration init() { - return this.dataService.registerCommitHandler(FRMRuntimeDataProvider.FLOWS_PATH, this); - } - - @Override - public DataObject readConfigurationData(final InstanceIdentifier path) { - return this.readFrom(this.configuration, path); - } - - @Override - public DataObject readOperationalData(final InstanceIdentifier path) { - return this.readFrom(this.configuration, path); - } - - public DataObject readFrom(final FlowManagementReader store, final InstanceIdentifier path) { - if (Objects.equal(FRMRuntimeDataProvider.FLOWS_PATH, path)) { - return store.readAllFlows(); - } - if (FRMRuntimeDataProvider.FLOWS_PATH.contains(path)) { - return store.readFlow(this.toFlowKey(path)); - } - return null; - } - - @Override - public FlowCommitTransaction requestCommit(final DataModification, DataObject> modification) { - return new FlowCommitTransaction(this, modification); - } - - public FlowKey toFlowKey(final InstanceIdentifier identifier) { - Preconditions.> checkNotNull(identifier); - - Iterable path = identifier.getPathArguments(); - PathArgument get = path.iterator().next(); - final Identifier itemKey = Arguments. checkInstanceOf(get, IdentifiableItem.class).getKey(); - return Arguments. checkInstanceOf(itemKey, FlowKey.class); - } - - public RpcResult finish(final FlowCommitTransaction transaction) { - Iterable toRemove = transaction.getToRemove(); - for (final FlowConfig flow : toRemove) { - this.manager.removeStaticFlow(flow.getName(), flow.getNode()); - } - Iterable toUpdate = transaction.getToUpdate(); - for (final FlowConfig flow : toUpdate) { - this.manager.removeStaticFlow(flow.getName(), flow.getNode()); - this.manager.addStaticFlow(flow); - } - return RpcResultBuilder. success().build(); - } - - public RpcResult rollback(final FlowCommitTransaction transaction) { - return null; - } - - public DataProviderService getDataService() { - return this.dataService; - } - - public void setDataService(final DataProviderService dataService) { - this.dataService = dataService; - } - - public DataChangeListener, DataObject> getChangeListener() { - return this.changeListener; - } - - public void setChangeListener(final DataChangeListener, DataObject> changeListener) { - this.changeListener = changeListener; - } - - public IForwardingRulesManager getManager() { - return this.manager; - } - - public void setManager(final IForwardingRulesManager manager) { - this.manager = manager; - } -} diff --git a/opendaylight/md-sal/compatibility/flow-management-compatibility/src/main/java/org/opendaylight/controller/md/frm/compatibility/FlowCommitTransaction.java b/opendaylight/md-sal/compatibility/flow-management-compatibility/src/main/java/org/opendaylight/controller/md/frm/compatibility/FlowCommitTransaction.java deleted file mode 100644 index bf0050d6c0..0000000000 --- a/opendaylight/md-sal/compatibility/flow-management-compatibility/src/main/java/org/opendaylight/controller/md/frm/compatibility/FlowCommitTransaction.java +++ /dev/null @@ -1,99 +0,0 @@ -/** - * Copyright (c) 2014 Cisco Systems, Inc. and others. All rights reserved. - * - * This program and the accompanying materials are made available under the - * terms of the Eclipse Public License v1.0 which accompanies this distribution, - * and is available at http://www.eclipse.org/legal/epl-v10.html - */ -package org.opendaylight.controller.md.frm.compatibility; - -import java.util.ArrayList; -import java.util.Collections; -import java.util.HashSet; -import java.util.List; -import java.util.Map.Entry; -import java.util.Set; - -import org.opendaylight.controller.forwardingrulesmanager.FlowConfig; -import org.opendaylight.controller.md.sal.common.api.data.DataCommitHandler.DataCommitTransaction; -import org.opendaylight.controller.md.sal.common.api.data.DataModification; -import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.config.rev130819.flows.Flow; -import org.opendaylight.yangtools.yang.binding.DataObject; -import org.opendaylight.yangtools.yang.binding.InstanceIdentifier; -import org.opendaylight.yangtools.yang.common.RpcResult; - -public class FlowCommitTransaction implements DataCommitTransaction, DataObject> { - - private final DataModification, DataObject> modification; - private final HashSet toAdd = new HashSet(); - private final FRMRuntimeDataProvider flowManager; - private Iterable toUpdate; - private Iterable toRemove; - - public FlowCommitTransaction( - final FRMRuntimeDataProvider flowManager, - final DataModification, DataObject> modification) { - this.flowManager = flowManager; - this.modification = modification; - this.processModification(); - } - - @Override - public RpcResult finish() throws IllegalStateException { - return this.flowManager.finish(this); - } - - @Override - public RpcResult rollback() throws IllegalStateException { - return this.flowManager.rollback(this); - } - - public void processModification() { - final Set, DataObject>> updated = - this.modification.getUpdatedConfigurationData().entrySet(); - final List forUpdate = new ArrayList(updated.size()); - - if (updated != null && !(updated.isEmpty())) { - for (Entry, DataObject> entry : updated) { - if (FlowConfigMapping.isFlowPath(entry.getKey())) { - forUpdate.add(FlowConfigMapping.toFlowConfig((Flow) entry.getValue())); - } - } - } - this.toUpdate = Collections.unmodifiableCollection(forUpdate); - - final Set> removedConfigurationData = - this.modification.getRemovedConfigurationData(); - final List forRemove = new ArrayList(removedConfigurationData.size()); - - if (removedConfigurationData != null && !(removedConfigurationData.isEmpty())) { - for (InstanceIdentifier data : removedConfigurationData) { - if (FlowConfigMapping.isFlowPath(data)) { - forRemove.add(FlowConfigMapping.toFlowConfig(data)); - } - } - } - this.toRemove = Collections.unmodifiableCollection(forRemove); - } - - @Override - public DataModification, DataObject> getModification() { - return this.modification; - } - - public FRMRuntimeDataProvider getFlowManager() { - return this.flowManager; - } - - public HashSet getToAdd() { - return this.toAdd; - } - - public Iterable getToUpdate() { - return this.toUpdate; - } - - public Iterable getToRemove() { - return this.toRemove; - } -} diff --git a/opendaylight/md-sal/compatibility/flow-management-compatibility/src/main/java/org/opendaylight/controller/md/frm/compatibility/FlowConfigMapping.java b/opendaylight/md-sal/compatibility/flow-management-compatibility/src/main/java/org/opendaylight/controller/md/frm/compatibility/FlowConfigMapping.java deleted file mode 100644 index 58c60ec1c5..0000000000 --- a/opendaylight/md-sal/compatibility/flow-management-compatibility/src/main/java/org/opendaylight/controller/md/frm/compatibility/FlowConfigMapping.java +++ /dev/null @@ -1,109 +0,0 @@ -/** - * Copyright (c) 2014 Cisco Systems, Inc. and others. All rights reserved. - * - * This program and the accompanying materials are made available under the - * terms of the Eclipse Public License v1.0 which accompanies this distribution, - * and is available at http://www.eclipse.org/legal/epl-v10.html - */ -package org.opendaylight.controller.md.frm.compatibility; - -import java.text.MessageFormat; -import java.util.Iterator; - -import org.opendaylight.controller.forwardingrulesmanager.FlowConfig; -import org.opendaylight.controller.sal.compatibility.MDFlowMapping; -import org.opendaylight.controller.sal.compatibility.NodeMapping; -import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.config.rev130819.flows.Flow; -import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.config.rev130819.flows.FlowBuilder; -import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.config.rev130819.flows.FlowKey; -import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.service.rev130819.FlowAdded; -import org.opendaylight.yangtools.yang.binding.Identifiable; -import org.opendaylight.yangtools.yang.binding.InstanceIdentifier; -import org.opendaylight.yangtools.yang.binding.InstanceIdentifier.IdentifiableItem; -import org.opendaylight.yangtools.yang.binding.InstanceIdentifier.PathArgument; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -public class FlowConfigMapping { - - private final static Logger LOG = LoggerFactory.getLogger(FlowConfigMapping.class); - - /* nodes/node/flow -> 0 / 1 / 2 */ - private static final int FLOW_KEY_IDENTIFIER_DEEP = 2; - - public static Flow toConfigurationFlow(final FlowConfig sourceCfg) { - final FlowAdded source = MDFlowMapping.flowAdded(sourceCfg.getFlow()); - final FlowBuilder flowBuilder = new FlowBuilder(); - flowBuilder.setInstructions(source.getInstructions()); - flowBuilder.setCookie(source.getCookie()); - flowBuilder.setHardTimeout(source.getHardTimeout()); - flowBuilder.setIdleTimeout(source.getIdleTimeout()); - flowBuilder.setMatch(source.getMatch()); - flowBuilder.setNode(source.getNode()); - - FlowKey flowKey = - new FlowKey(Long.valueOf(sourceCfg.getName()), flowBuilder.getNode()); - flowBuilder.setKey(flowKey); - return flowBuilder.build(); - } - - public static FlowConfig toFlowConfig(final Flow sourceCfg) { - try { - final FlowConfig flowConfig = new FlowConfig(); - flowConfig.setName(String.valueOf(sourceCfg.getId())); - flowConfig.setNode(NodeMapping.toADNode(sourceCfg.getNode())); - return flowConfig; - } catch (Exception e) { - String errMsg = MessageFormat.format("Convert from Flow {} to FlowConfig fail", sourceCfg); - LOG.error(errMsg, e); - throw new RuntimeException(errMsg, e); - } - } - - public static FlowConfig toFlowConfig(final InstanceIdentifier identifier) { - try { - PathArgument pathArg = FlowConfigMapping.getSecondPathArgumentFromPath(identifier); - if (pathArg != null) { - final FlowConfig flowConfig = new FlowConfig(); - FlowKey key = ((IdentifiableItem) pathArg).getKey(); - flowConfig.setName(String.valueOf(key.getId())); - flowConfig.setNode(NodeMapping.toADNode(key.getNode())); - return flowConfig; - } - return null; - } catch (Exception e) { - String errMsg = MessageFormat.format("Convert from InstanceIdentifier {} to FlowConfig fail", identifier); - LOG.error(errMsg, e); - throw new RuntimeException(errMsg, e); - } - } - - public static boolean isFlowPath(final InstanceIdentifier path) { - PathArgument pathArg = FlowConfigMapping.getSecondPathArgumentFromPath(path); - if (pathArg == null) { - return false; - } - if (pathArg instanceof IdentifiableItem) { - final Identifiable key = ((IdentifiableItem>) pathArg).getKey(); - if ((key instanceof FlowKey)) { - return true; - } - } - return false; - } - - private static PathArgument getSecondPathArgumentFromPath(final InstanceIdentifier path) { - if (path != null && path.getPathArguments() != null) { - Iterator iterator = path.getPathArguments().iterator(); - int deep = 0; - while (iterator.hasNext()) { - PathArgument pathArg = iterator.next(); - if (deep == FlowConfigMapping.FLOW_KEY_IDENTIFIER_DEEP) { - return pathArg; - } - deep++; - } - } - return null; - } -} diff --git a/opendaylight/md-sal/compatibility/flow-management-compatibility/src/main/java/org/opendaylight/controller/md/frm/compatibility/FlowManagementReader.java b/opendaylight/md-sal/compatibility/flow-management-compatibility/src/main/java/org/opendaylight/controller/md/frm/compatibility/FlowManagementReader.java deleted file mode 100644 index cb61c8a095..0000000000 --- a/opendaylight/md-sal/compatibility/flow-management-compatibility/src/main/java/org/opendaylight/controller/md/frm/compatibility/FlowManagementReader.java +++ /dev/null @@ -1,20 +0,0 @@ -/** - * Copyright (c) 2014 Cisco Systems, Inc. and others. All rights reserved. - * - * This program and the accompanying materials are made available under the - * terms of the Eclipse Public License v1.0 which accompanies this distribution, - * and is available at http://www.eclipse.org/legal/epl-v10.html - */ -package org.opendaylight.controller.md.frm.compatibility; - -import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.config.rev130819.Flows; -import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.config.rev130819.flows.Flow; -import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.config.rev130819.flows.FlowKey; - -public interface FlowManagementReader { - - Flows readAllFlows(); - - Flow readFlow(FlowKey key); - -} diff --git a/opendaylight/md-sal/compatibility/flow-management-compatibility/src/main/java/org/opendaylight/controller/md/frm/compatibility/SampleConsumer.java b/opendaylight/md-sal/compatibility/flow-management-compatibility/src/main/java/org/opendaylight/controller/md/frm/compatibility/SampleConsumer.java deleted file mode 100644 index a91cef6136..0000000000 --- a/opendaylight/md-sal/compatibility/flow-management-compatibility/src/main/java/org/opendaylight/controller/md/frm/compatibility/SampleConsumer.java +++ /dev/null @@ -1,45 +0,0 @@ -/* - * Copyright (c) 2014 Cisco Systems, Inc. and others. All rights reserved. - * - * This program and the accompanying materials are made available under the - * terms of the Eclipse Public License v1.0 which accompanies this distribution, - * and is available at http://www.eclipse.org/legal/epl-v10.html - */ -package org.opendaylight.controller.md.frm.compatibility; - -import org.opendaylight.controller.sal.binding.api.BindingAwareBroker.ConsumerContext; -import org.opendaylight.controller.sal.binding.api.data.DataBrokerService; -import org.opendaylight.controller.sal.binding.api.data.DataModificationTransaction; -import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.config.rev130819.Flows; -import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.config.rev130819.flows.Flow; -import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.config.rev130819.flows.FlowBuilder; -import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.config.rev130819.flows.FlowKey; -import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.NodeRef; -import org.opendaylight.yangtools.yang.binding.InstanceIdentifier; - -public class SampleConsumer { - - ConsumerContext context; - - void addFlowExample() { - - DataBrokerService dataService = context.getSALService(DataBrokerService.class); - - DataModificationTransaction transaction = dataService.beginTransaction(); - Flow flow = createSampleFlow("foo", null); - InstanceIdentifier path = InstanceIdentifier.builder(Flows.class).child(Flow.class, flow.getKey()) - .toInstance(); - transaction.putConfigurationData(path, flow); - - transaction.commit(); - - dataService.readConfigurationData(path); - } - - Flow createSampleFlow(String name, NodeRef node) { - FlowBuilder ret = new FlowBuilder(); - FlowKey key = new FlowKey(Long.parseLong(name), node); - ret.setKey(key); - return ret.build(); - } -} diff --git a/opendaylight/md-sal/compatibility/inventory-topology-compatibility/pom.xml b/opendaylight/md-sal/compatibility/inventory-topology-compatibility/pom.xml deleted file mode 100644 index 62dc2ffa1a..0000000000 --- a/opendaylight/md-sal/compatibility/inventory-topology-compatibility/pom.xml +++ /dev/null @@ -1,90 +0,0 @@ - - - 4.0.0 - - org.opendaylight.controller - compatibility-parent - 1.1-SNAPSHOT - - inventory-topology-compatibility - bundle - - - - com.google.guava - guava - - - org.opendaylight.controller - forwardingrulesmanager - - - org.opendaylight.controller - sal-binding-api - - - org.opendaylight.controller - sal-binding-util - - - org.opendaylight.controller - sal-common-util - - - org.opendaylight.controller - sal-compatibility - - - org.opendaylight.controller - switchmanager - - - org.opendaylight.controller - topologymanager - - - org.opendaylight.controller.model - model-flow-management - - - org.opendaylight.controller.model - model-topology - - - org.slf4j - slf4j-api - - - junit - junit - test - - - org.mockito - mockito-all - test - - - - - - - org.apache.felix - maven-bundle-plugin - true - - - Forwarding Rules Manager Adapter - for MD-SAL - - - - - - - scm:git:ssh://git.opendaylight.org:29418/controller.git - scm:git:ssh://git.opendaylight.org:29418/controller.git - HEAD - https://wiki.opendaylight.org/view/OpenDaylight_Controller:MD-SAL - - diff --git a/opendaylight/md-sal/compatibility/inventory-topology-compatibility/src/main/java/org/opendaylight/controller/md/compatibility/inventory/InventoryReader.java b/opendaylight/md-sal/compatibility/inventory-topology-compatibility/src/main/java/org/opendaylight/controller/md/compatibility/inventory/InventoryReader.java deleted file mode 100644 index b37b50159f..0000000000 --- a/opendaylight/md-sal/compatibility/inventory-topology-compatibility/src/main/java/org/opendaylight/controller/md/compatibility/inventory/InventoryReader.java +++ /dev/null @@ -1,97 +0,0 @@ -/** - * Copyright (c) 2014 Cisco Systems, Inc. and others. All rights reserved. - * - * This program and the accompanying materials are made available under the - * terms of the Eclipse Public License v1.0 which accompanies this distribution, - * and is available at http://www.eclipse.org/legal/epl-v10.html - */ -package org.opendaylight.controller.md.compatibility.inventory; - -import java.util.ArrayList; -import java.util.Set; - -import org.opendaylight.controller.sal.binding.api.data.RuntimeDataProvider; -import org.opendaylight.controller.sal.compatibility.InventoryMapping; -import org.opendaylight.controller.switchmanager.ISwitchManager; -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.node.NodeConnector; -import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.node.NodeConnectorBuilder; -import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.nodes.Node; -import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.nodes.NodeBuilder; -import org.opendaylight.yangtools.yang.binding.DataObject; -import org.opendaylight.yangtools.yang.binding.InstanceIdentifier; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -public class InventoryReader implements RuntimeDataProvider { - private static final Logger LOG = LoggerFactory.getLogger(InventoryReader.class); - private ISwitchManager switchManager; - - public ISwitchManager getSwitchManager() { - return switchManager; - } - - public void setSwitchManager(final ISwitchManager switchManager) { - this.switchManager = switchManager; - } - - @Override - public DataObject readConfigurationData(final InstanceIdentifier path) { - // Topology and Inventory are operational only - return null; - } - - @SuppressWarnings("unchecked") - @Override - public DataObject readOperationalData(final InstanceIdentifier path) { - final Class type = path.getTargetType(); - if (Nodes.class.equals(type)) { - return readNodes(((InstanceIdentifier) path)); - } - if (Node.class.equals(type)) { - return readNode(((InstanceIdentifier) path)); - } - if (NodeConnector.class.equals(type)) { - return readNodeConnector(((InstanceIdentifier) path)); - } - - LOG.debug("Unsupported type {}", type); - return null; - } - - private NodeConnector readNodeConnector(final InstanceIdentifier identifier) { - return constructNodeConnector(InventoryMapping.toAdNodeConnector(identifier)); - } - - private Node readNode(final InstanceIdentifier identifier) { - return constructNode(InventoryMapping.toAdNode(identifier)); - } - - private Node constructNode(final org.opendaylight.controller.sal.core.Node node) { - final Set connectors = getSwitchManager().getNodeConnectors(node); - final ArrayList tpList = new ArrayList(connectors.size()); - for (final org.opendaylight.controller.sal.core.NodeConnector connector : connectors) { - tpList.add(constructNodeConnector(connector)); - } - - return new NodeBuilder() - .setKey(InventoryMapping.toNodeKey(node)) - .setNodeConnector(tpList) - .build(); - } - - private Nodes readNodes(final InstanceIdentifier identifier) { - final Set nodes = getSwitchManager().getNodes(); - final ArrayList nodeList = new ArrayList(nodes.size()); - for (final org.opendaylight.controller.sal.core.Node node : nodes) { - nodeList.add(constructNode(node)); - } - - return new NodesBuilder().setNode(nodeList).build(); - } - - private static NodeConnector constructNodeConnector(final org.opendaylight.controller.sal.core.NodeConnector connector) { - return new NodeConnectorBuilder().setKey(InventoryMapping.toNodeConnectorKey(connector)).build(); - } -} diff --git a/opendaylight/md-sal/compatibility/inventory-topology-compatibility/src/main/java/org/opendaylight/controller/md/compatibility/switchmanager/CompatibleSwitchManager.java b/opendaylight/md-sal/compatibility/inventory-topology-compatibility/src/main/java/org/opendaylight/controller/md/compatibility/switchmanager/CompatibleSwitchManager.java deleted file mode 100644 index 82c5b7bf61..0000000000 --- a/opendaylight/md-sal/compatibility/inventory-topology-compatibility/src/main/java/org/opendaylight/controller/md/compatibility/switchmanager/CompatibleSwitchManager.java +++ /dev/null @@ -1,347 +0,0 @@ -/** - * Copyright (c) 2014 Cisco Systems, Inc. and others. All rights reserved. - * - * This program and the accompanying materials are made available under the - * terms of the Eclipse Public License v1.0 which accompanies this distribution, - * and is available at http://www.eclipse.org/legal/epl-v10.html - */ -package org.opendaylight.controller.md.compatibility.switchmanager; - -import java.net.InetAddress; -import java.net.NetworkInterface; -import java.net.SocketException; -import java.util.ArrayList; -import java.util.Collections; -import java.util.Enumeration; -import java.util.HashSet; -import java.util.List; -import java.util.Map; -import java.util.Set; - -import org.opendaylight.controller.sal.binding.api.data.DataBrokerService; -import org.opendaylight.controller.sal.binding.api.data.DataModificationTransaction; -import org.opendaylight.controller.sal.compatibility.NodeMapping; -import org.opendaylight.controller.sal.core.Bandwidth; -import org.opendaylight.controller.sal.core.ConstructionException; -import org.opendaylight.controller.sal.core.Description; -import org.opendaylight.controller.sal.core.ForwardingMode; -import org.opendaylight.controller.sal.core.MacAddress; -import org.opendaylight.controller.sal.core.NodeConnector; -import org.opendaylight.controller.sal.core.Property; -import org.opendaylight.controller.sal.core.Tier; -import org.opendaylight.controller.sal.utils.Status; -import org.opendaylight.controller.switchmanager.ISwitchManager; -import org.opendaylight.controller.switchmanager.Subnet; -import org.opendaylight.controller.switchmanager.Switch; -import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.FlowCapableNodeConnector; -import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.NodeConnectorId; -import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.NodeConnectorRef; -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.node.NodeConnectorKey; -import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.nodes.Node; -import org.opendaylight.yangtools.yang.binding.InstanceIdentifier; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -public class CompatibleSwitchManager extends ConfigurableSwitchManager implements ISwitchManager { - private static final Logger LOG = LoggerFactory.getLogger(CompatibleSwitchManager.class); - - private DataBrokerService _dataService; - - public DataBrokerService getDataService() { - return this._dataService; - } - - public void setDataService(final DataBrokerService dataService) { - this._dataService = dataService; - } - - @Override - public Status addNodeConnectorProp(final NodeConnector nodeConnector, final Property prop) { - final DataModificationTransaction it = getDataService().beginTransaction(); - final NodeConnectorRef path = NodeMapping.toNodeConnectorRef(nodeConnector); - return null; - } - - @Override - public Property createProperty(final String propName, final String propValue) { - try { - if (propName.equalsIgnoreCase(Description.propertyName)) { - return new Description(propValue); - } else if (propName.equalsIgnoreCase(Tier.TierPropName)) { - return new Tier(Integer.parseInt(propValue)); - } else if (propName.equalsIgnoreCase(Bandwidth.BandwidthPropName)) { - return new Bandwidth(Long.parseLong(propValue)); - } else if (propName.equalsIgnoreCase(ForwardingMode.name)) { - return new ForwardingMode(Integer.parseInt(propValue)); - } else if (propName.equalsIgnoreCase(MacAddress.name)) { - return new MacAddress(propValue); - } else { - LOG.debug("Not able to create {} property", propName); - } - } catch (Exception e) { - LOG.debug("createProperty caught exception {}", e.getMessage()); - } - - return null; - } - - @Override - public boolean doesNodeConnectorExist(final NodeConnector nc) { - return (getDataService().readOperationalData(NodeMapping.toNodeConnectorRef(nc).getValue()) != null); - } - - @Override - public byte[] getControllerMAC() { - final Enumeration nis; - try { - nis = NetworkInterface.getNetworkInterfaces(); - } catch (SocketException e) { - LOG.error("Failed to acquire list of interfaces, cannot determine controller MAC", e); - return null; - } - - while (nis.hasMoreElements()) { - final NetworkInterface ni = nis.nextElement(); - try { - return ni.getHardwareAddress(); - } catch (SocketException e) { - LOG.error("Failed to acquire controller MAC from interface {}", ni, e); - } - } - - // This happens when running controller on windows VM, for example - // Try parsing the OS command output - LOG.warn("Failed to acquire controller MAC: No physical interface found"); - return null; - } - - @Override - public Map getControllerProperties() { - return Collections.emptyMap(); - } - - @Override - public Property getControllerProperty(final String propertyName) { - return null; - } - - @Override - public List getNetworkDevices() { - final InstanceIdentifier path = InstanceIdentifier.builder(Nodes.class).toInstance(); - final Nodes data = ((Nodes) getDataService().readOperationalData(path)); - final ArrayList ret = new ArrayList<>(); - for (final Node node : data.getNode()) { - try { - ret.add(toSwitch(node)); - } catch (ConstructionException e) { - throw new IllegalStateException(String.format("Failed to create switch {}", node), e); - } - } - return ret; - } - - @Override - public NodeConnector getNodeConnector(final org.opendaylight.controller.sal.core.Node node, final String nodeConnectorName) { - final NodeConnectorKey key = new NodeConnectorKey(new NodeConnectorId(nodeConnectorName)); - try { - return new NodeConnector(NodeMapping.MD_SAL_TYPE, key, node); - } catch (ConstructionException e) { - throw new IllegalStateException(String.format("Failed to create node connector for {} {}", node, nodeConnectorName), e); - } - } - - @Override - public Property getNodeConnectorProp(final NodeConnector nodeConnector, final String propName) { - return getNodeConnectorProps(nodeConnector).get(propName); - } - - @Override - public Map getNodeConnectorProps(final NodeConnector nodeConnector) { - final NodeConnectorRef ref = NodeMapping.toNodeConnectorRef(nodeConnector); - return toAdProperties(readNodeConnector(ref.getValue())); - } - - @Override - public Set getNodeConnectors(final org.opendaylight.controller.sal.core.Node node) { - final Node data = this.readNode(NodeMapping.toNodeRef(node).getValue()); - final HashSet ret = new HashSet<>(); - for (final org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.node.NodeConnector nc : data.getNodeConnector()) { - try { - ret.add(new NodeConnector(NodeMapping.MD_SAL_TYPE, nc.getKey(), node)); - } catch (ConstructionException e) { - throw new IllegalStateException(String.format("Failed to create node {} connector", node, nc.getKey()), e); - } - } - return ret; - } - - @Override - public String getNodeDescription(final org.opendaylight.controller.sal.core.Node node) { - return ((Description) getNodeProps(node).get(Description.propertyName)).getValue(); - } - - @Override - public byte[] getNodeMAC(final org.opendaylight.controller.sal.core.Node node) { - return ((MacAddress) getNodeProps(node).get(MacAddress.name)).getMacAddress(); - } - - @Override - public Property getNodeProp(final org.opendaylight.controller.sal.core.Node node, final String propName) { - return getNodeProps(node).get(propName); - } - - @Override - public Map getNodeProps(final org.opendaylight.controller.sal.core.Node node) { - final NodeRef ref = NodeMapping.toNodeRef(node); - return toAdProperties(((Node) getDataService().readOperationalData(ref.getValue()))); - } - - @Override - public Set getNodes() { - final InstanceIdentifier path = InstanceIdentifier.builder(Nodes.class).toInstance(); - final Nodes data = ((Nodes) getDataService().readOperationalData(path)); - final HashSet ret = new HashSet<>(); - for (final Node node : data.getNode()) { - try { - ret.add(new org.opendaylight.controller.sal.core.Node(NodeMapping.MD_SAL_TYPE, node.getKey())); - } catch (ConstructionException e) { - throw new IllegalStateException(String.format("Failed to create node for {}", node), e); - } - } - return ret; - } - - private static Switch toSwitch(final Node node) throws ConstructionException { - return new Switch(new org.opendaylight.controller.sal.core.Node(NodeMapping.MD_SAL_TYPE, node.getKey())); - } - - @Override - public Set getPhysicalNodeConnectors(final org.opendaylight.controller.sal.core.Node node) { - final NodeRef ref = NodeMapping.toNodeRef(node); - final Node data = readNode(ref.getValue()); - final HashSet ret = new HashSet<>(); - for (final org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.node.NodeConnector nc : data.getNodeConnector()) { - final FlowCapableNodeConnector flowConnector = nc.getAugmentation(FlowCapableNodeConnector.class); - try { - ret.add(new NodeConnector(NodeMapping.MD_SAL_TYPE, nc.getKey(), node)); - } catch (ConstructionException e) { - throw new IllegalStateException(String.format("Failed to create connector for {} on node {}", nc.getKey(), node), e); - } - } - return ret; - } - - private static Map toAdProperties(final org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.node.NodeConnector connector) { - return Collections.emptyMap(); - } - - private static Map toAdProperties(final Node connector) { - return Collections.emptyMap(); - } - - private Node readNode(final InstanceIdentifier ref) { - return (Node) getDataService().readOperationalData((ref)); - } - - private org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.node.NodeConnector readNodeConnector(final InstanceIdentifier ref) { - return ((org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.node.NodeConnector) getDataService().readOperationalData(ref)); - } - - @Override - public List getSpanPorts(final org.opendaylight.controller.sal.core.Node node) { - throw new UnsupportedOperationException("TODO: auto-generated method stub"); - } - - @Override - public Subnet getSubnetByNetworkAddress(final InetAddress networkAddress) { - throw new UnsupportedOperationException("TODO: auto-generated method stub"); - } - - @Override - public Set getUpNodeConnectors(final org.opendaylight.controller.sal.core.Node node) { - final Node data = readNode(NodeMapping.toNodeRef(node).getValue()); - final HashSet ret = new HashSet<>(); - for (final org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.node.NodeConnector nc : data.getNodeConnector()) { - final FlowCapableNodeConnector flowConn = nc.getAugmentation(FlowCapableNodeConnector.class); - if (flowConn != null && flowConn.getState() != null && !flowConn.getState().isLinkDown()) { - try { - ret.add(new NodeConnector(NodeMapping.MD_SAL_TYPE, nc.getKey(), node)); - } catch (ConstructionException e) { - throw new IllegalStateException(String.format("Failed to create node connector for node {} connector {}", node, nc), e); - } - } - } - return ret; - } - - @Override - public Boolean isNodeConnectorEnabled(final NodeConnector nodeConnector) { - final NodeConnectorRef ref = NodeMapping.toNodeConnectorRef(nodeConnector); - final org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.node.NodeConnector data = readNodeConnector(ref.getValue()); - return true; - } - - @Override - public boolean isSpecial(final NodeConnector p) { - final NodeConnectorRef ref = NodeMapping.toNodeConnectorRef(p); - final org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.node.NodeConnector data = readNodeConnector(ref.getValue()); - return true; - } - - @Override - public Status removeControllerProperty(final String propertyName) { - return null; - } - - @Override - public Status removeNodeAllProps(final org.opendaylight.controller.sal.core.Node node) { - return null; - } - - @Override - public Status removeNodeConnectorAllProps(final NodeConnector nodeConnector) { - return null; - } - - @Override - public Status removeNodeConnectorProp(final NodeConnector nc, final String propName) { - return null; - } - - @Override - public Status removeNodeProp(final org.opendaylight.controller.sal.core.Node node, final String propName) { - return null; - } - - @Override - public Status removePortsFromSubnet(final String name, final List nodeConnectors) { - return null; - } - - @Override - public Status removeSubnet(final String name) { - return null; - } - - @Override - public Status setControllerProperty(final Property property) { - return null; - } - - @Override - public void setNodeProp(final org.opendaylight.controller.sal.core.Node node, final Property prop) { - throw new UnsupportedOperationException("TODO: auto-generated method stub"); - } - - @Override - public Status addPortsToSubnet(final String name, final List nodeConnectors) { - throw new UnsupportedOperationException("TODO: auto-generated method stub"); - } - - @Override - public Set getConfiguredNotConnectedSwitches() { - return null; - } -} diff --git a/opendaylight/md-sal/compatibility/inventory-topology-compatibility/src/main/java/org/opendaylight/controller/md/compatibility/switchmanager/ConfigurableSwitchManager.java b/opendaylight/md-sal/compatibility/inventory-topology-compatibility/src/main/java/org/opendaylight/controller/md/compatibility/switchmanager/ConfigurableSwitchManager.java deleted file mode 100644 index 63f682a361..0000000000 --- a/opendaylight/md-sal/compatibility/inventory-topology-compatibility/src/main/java/org/opendaylight/controller/md/compatibility/switchmanager/ConfigurableSwitchManager.java +++ /dev/null @@ -1,86 +0,0 @@ -/** - * Copyright (c) 2014 Cisco Systems, Inc. and others. All rights reserved. - * - * This program and the accompanying materials are made available under the - * terms of the Eclipse Public License v1.0 which accompanies this distribution, - * and is available at http://www.eclipse.org/legal/epl-v10.html - */ -package org.opendaylight.controller.md.compatibility.switchmanager; - -import java.util.List; - -import org.opendaylight.controller.sal.utils.Status; -import org.opendaylight.controller.switchmanager.ISwitchManager; -import org.opendaylight.controller.switchmanager.SpanConfig; -import org.opendaylight.controller.switchmanager.SubnetConfig; -import org.opendaylight.controller.switchmanager.SwitchConfig; - -/** - * These methods should be backed by config subsystem. - */ -public abstract class ConfigurableSwitchManager implements ISwitchManager { - @Override - public Status saveSwitchConfig() { - throw new UnsupportedOperationException("TODO: auto-generated method stub"); - } - - @Override - public Status removeSpanConfig(final SpanConfig cfgObject) { - throw new UnsupportedOperationException("TODO: auto-generated method stub"); - } - - @Override - public Status addSubnet(final SubnetConfig configObject) { - throw new UnsupportedOperationException("TODO: auto-generated method stub"); - } - - @Override - public final Status addSpanConfig(final SpanConfig configObject) { - throw new UnsupportedOperationException("TODO: auto-generated method stub"); - } - - @Override - public final List getSpanConfigList() { - throw new UnsupportedOperationException("TODO: auto-generated method stub"); - } - - @Override - public final void updateSwitchConfig(final SwitchConfig cfgObject) { - throw new UnsupportedOperationException("TODO: auto-generated method stub"); - } - - @Override - public final Status updateNodeConfig(final SwitchConfig switchConfig) { - throw new UnsupportedOperationException("TODO: auto-generated method stub"); - } - - @Override - public final SubnetConfig getSubnetConfig(final String subnet) { - throw new UnsupportedOperationException("TODO: auto-generated method stub"); - } - - @Override - public final Status removeNodeConfig(final String nodeId) { - throw new UnsupportedOperationException("TODO: auto-generated method stub"); - } - - @Override - public final Status removeSubnet(final SubnetConfig configObject) { - throw new UnsupportedOperationException("TODO: auto-generated method stub"); - } - - @Override - public final List getSubnetsConfigList() { - throw new UnsupportedOperationException("TODO: auto-generated method stub"); - } - - @Override - public final SwitchConfig getSwitchConfig(final String nodeId) { - throw new UnsupportedOperationException("TODO: auto-generated method stub"); - } - - @Override - public Status modifySubnet(final SubnetConfig configObject) { - throw new UnsupportedOperationException("TODO: auto-generated method stub"); - } -} diff --git a/opendaylight/md-sal/compatibility/inventory-topology-compatibility/src/main/java/org/opendaylight/controller/md/compatibility/topology/TopologyMapping.java b/opendaylight/md-sal/compatibility/inventory-topology-compatibility/src/main/java/org/opendaylight/controller/md/compatibility/topology/TopologyMapping.java deleted file mode 100644 index 8e50bd881e..0000000000 --- a/opendaylight/md-sal/compatibility/inventory-topology-compatibility/src/main/java/org/opendaylight/controller/md/compatibility/topology/TopologyMapping.java +++ /dev/null @@ -1,82 +0,0 @@ -/** - * Copyright (c) 2014 Cisco Systems, Inc. and others. All rights reserved. - * - * This program and the accompanying materials are made available under the - * terms of the Eclipse Public License v1.0 which accompanies this distribution, - * and is available at http://www.eclipse.org/legal/epl-v10.html - */ -package org.opendaylight.controller.md.compatibility.topology; - -import java.util.Iterator; - -import org.opendaylight.controller.sal.compatibility.InventoryMapping; -import org.opendaylight.controller.sal.core.ConstructionException; -import org.opendaylight.controller.sal.core.Edge; -import org.opendaylight.controller.sal.core.NodeConnector; -import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.LinkId; -import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.NodeId; -import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.TpId; -import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.Topology; -import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.TopologyKey; -import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.topology.Link; -import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.topology.LinkKey; -import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.topology.Node; -import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.topology.NodeKey; -import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.topology.node.TerminationPoint; -import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.topology.node.TerminationPointKey; -import org.opendaylight.yangtools.yang.binding.InstanceIdentifier; -import org.opendaylight.yangtools.yang.binding.KeyedInstanceIdentifier; - -import com.google.common.base.Splitter; - -public class TopologyMapping { - private static final String HEAD_TAIL_STRING = "::::"; - private static final Splitter HEAD_TAIL_SPLITTER = Splitter.on(HEAD_TAIL_STRING); - - public TopologyMapping(final TopologyKey path, final InstanceIdentifier key) { - // No-op for now. Multi-instance will require fixing InventoryMapping first. - } - - public Edge toAdTopologyEdge(final InstanceIdentifier identifier) throws ConstructionException { - @SuppressWarnings("unchecked") - final LinkKey linkKey = ((KeyedInstanceIdentifier)identifier).getKey(); - - final Iterator it = HEAD_TAIL_SPLITTER.split(linkKey.getLinkId().getValue()).iterator(); - final NodeConnector tail = InventoryMapping.nodeConnectorFromId(it.next()); - final NodeConnector head = InventoryMapping.nodeConnectorFromId(it.next()); - return new Edge(tail, head); - } - - public NodeConnector toAdTopologyNodeConnector(final InstanceIdentifier identifier) { - @SuppressWarnings("unchecked") - final TerminationPointKey tpKey = ((KeyedInstanceIdentifier)identifier).getKey(); - - return InventoryMapping.nodeConnectorFromId(tpKey.getTpId().getValue()); - } - - public org.opendaylight.controller.sal.core.Node toAdTopologyNode(final InstanceIdentifier identifier) { - @SuppressWarnings("unchecked") - final NodeKey nodeKey = ((KeyedInstanceIdentifier)identifier).getKey(); - - return InventoryMapping.nodeFromNodeId(nodeKey.getNodeId().getValue()); - } - - public NodeKey toTopologyNodeKey(final org.opendaylight.controller.sal.core.Node node) { - return new NodeKey(new NodeId(InventoryMapping.toNodeId(node))); - } - - public TerminationPointKey toTopologyTerminationPointKey(final NodeConnector nc) { - return new TerminationPointKey(new TpId(InventoryMapping.toNodeConnectorId(nc))); - } - - public LinkKey toTopologyLinkKey(final Edge edge) { - final TerminationPointKey sourceTp = toTopologyTerminationPointKey(edge.getTailNodeConnector()); - final TerminationPointKey destTp = toTopologyTerminationPointKey(edge.getHeadNodeConnector()); - - final StringBuilder sb = new StringBuilder(); - sb.append(sourceTp.getTpId().toString()); - sb.append(HEAD_TAIL_STRING); - sb.append(destTp.getTpId().toString()); - return new LinkKey(new LinkId(sb.toString())); - } -} diff --git a/opendaylight/md-sal/compatibility/inventory-topology-compatibility/src/main/java/org/opendaylight/controller/md/compatibility/topology/TopologyReader.java b/opendaylight/md-sal/compatibility/inventory-topology-compatibility/src/main/java/org/opendaylight/controller/md/compatibility/topology/TopologyReader.java deleted file mode 100644 index a4ac6f94ee..0000000000 --- a/opendaylight/md-sal/compatibility/inventory-topology-compatibility/src/main/java/org/opendaylight/controller/md/compatibility/topology/TopologyReader.java +++ /dev/null @@ -1,199 +0,0 @@ -/** - * Copyright (c) 2014 Cisco Systems, Inc. and others. All rights reserved. - * - * This program and the accompanying materials are made available under the - * terms of the Eclipse Public License v1.0 which accompanies this distribution, - * and is available at http://www.eclipse.org/legal/epl-v10.html - */ -package org.opendaylight.controller.md.compatibility.topology; - -import java.util.ArrayList; -import java.util.Map; -import java.util.Set; - -import org.opendaylight.controller.sal.binding.api.data.RuntimeDataProvider; -import org.opendaylight.controller.sal.core.ConstructionException; -import org.opendaylight.controller.sal.core.Edge; -import org.opendaylight.controller.sal.core.NodeConnector; -import org.opendaylight.controller.sal.core.Property; -import org.opendaylight.controller.switchmanager.ISwitchManager; -import org.opendaylight.controller.topologymanager.ITopologyManager; -import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.NetworkTopology; -import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.TopologyId; -import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.link.attributes.DestinationBuilder; -import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.link.attributes.SourceBuilder; -import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.Topology; -import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.TopologyBuilder; -import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.TopologyKey; -import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.topology.Link; -import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.topology.LinkBuilder; -import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.topology.Node; -import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.topology.NodeBuilder; -import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.topology.node.TerminationPoint; -import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.topology.node.TerminationPointBuilder; -import org.opendaylight.yangtools.yang.binding.DataObject; -import org.opendaylight.yangtools.yang.binding.InstanceIdentifier; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -public class TopologyReader implements RuntimeDataProvider { - private static final Logger LOG = LoggerFactory.getLogger(TopologyReader.class); - private final InstanceIdentifier topologyPath; - private final TopologyKey topologyKey; - private final TopologyMapping mapping; - private ITopologyManager topologyManager; - private ISwitchManager switchManager; - - public ISwitchManager getSwitchManager() { - return this.switchManager; - } - - public void setSwitchManager(final ISwitchManager switchManager) { - this.switchManager = switchManager; - } - - public ITopologyManager getTopologyManager() { - return this.topologyManager; - } - - public void setTopologyManager(final ITopologyManager topologyManager) { - this.topologyManager = topologyManager; - } - - public TopologyKey getTopologyKey() { - return this.topologyKey; - } - - public TopologyMapping getMapping() { - return this.mapping; - } - - public TopologyReader() { - this.topologyKey = new TopologyKey(new TopologyId("compatibility:ad-sal")); - this.topologyPath = InstanceIdentifier.builder(NetworkTopology.class) - .child(Topology.class, topologyKey) - .toInstance(); - this.mapping = new TopologyMapping(topologyKey, topologyPath); - } - - @Override - public DataObject readConfigurationData(final InstanceIdentifier path) { - // Topology and Inventory are operational only - return null; - } - - @SuppressWarnings("unchecked") - @Override - public DataObject readOperationalData(final InstanceIdentifier path) { - if (!topologyPath.contains(path)) { - return null; - } - - final Class type = path.getTargetType(); - if (Link.class.equals(type)) { - return readLink((InstanceIdentifier) path); - } - if (Node.class.equals(type)) { - return readNode((InstanceIdentifier) path); - } - if (TerminationPoint.class.equals(type)) { - return readTerminationPoint((InstanceIdentifier) path); - - } - if (Topology.class.equals(type)) { - return readTopology((InstanceIdentifier) path); - } - - LOG.debug("Unsupported type {}", type); - return null; - } - - private Link readLink(final InstanceIdentifier identifier) { - final Edge edge; - try { - edge = this.mapping.toAdTopologyEdge(identifier); - } catch (ConstructionException e) { - throw new IllegalStateException(String.format("Failed to construct edge for link %s", identifier), e); - } - - final Map> edges; - if (topologyManager != null) { - edges = topologyManager.getEdges(); - } else { - edges = null; - } - - final Set properties; - if (edges != null) { - properties = edges.get(edge); - } else { - properties = null; - } - - return constructLink(edge); - } - - private TerminationPoint readTerminationPoint(final InstanceIdentifier identifier) { - return constructTerminationPoint(mapping.toAdTopologyNodeConnector(identifier)); - } - - private Node readNode(final InstanceIdentifier identifier) { - return constructNode(mapping.toAdTopologyNode(identifier)); - } - - private Topology readTopology(final InstanceIdentifier identifier) { - final Set nodes = getSwitchManager().getNodes(); - final ArrayList nodeList = new ArrayList(nodes.size()); - for (final org.opendaylight.controller.sal.core.Node node : nodes) { - nodeList.add(constructNode(node)); - } - - final Map> edges = getTopologyManager().getEdges(); - final ArrayList linkList = new ArrayList(edges.size()); - for (final Edge edge : edges.keySet()) { - linkList.add(constructLink(edge)); - } - - return new TopologyBuilder() - .setKey(topologyKey) - .setNode(nodeList) - .setLink(linkList) - .build(); - } - - private Link constructLink(final Edge edge) { - final NodeConnector sourceNc = edge.getTailNodeConnector(); - final NodeConnector destNc = edge.getHeadNodeConnector(); - - final LinkBuilder it = new LinkBuilder().setKey(mapping.toTopologyLinkKey(edge)); - - it.setSource(new SourceBuilder() - .setSourceNode(mapping.toTopologyNodeKey(sourceNc.getNode()).getNodeId()) - .setSourceTp(mapping.toTopologyTerminationPointKey(sourceNc).getTpId()) - .build()); - - it.setDestination(new DestinationBuilder() - .setDestNode(mapping.toTopologyNodeKey(destNc.getNode()).getNodeId()) - .setDestTp(mapping.toTopologyTerminationPointKey(destNc).getTpId()) - .build()); - - return it.build(); - } - - private Node constructNode(final org.opendaylight.controller.sal.core.Node node) { - final Set connectors = getSwitchManager().getNodeConnectors(node); - final ArrayList tpList = new ArrayList(connectors.size()); - for (final NodeConnector connector : connectors) { - tpList.add(constructTerminationPoint(connector)); - } - - return new NodeBuilder() - .setKey(mapping.toTopologyNodeKey(node)) - .setTerminationPoint(tpList) - .build(); - } - - private TerminationPoint constructTerminationPoint(final NodeConnector connector) { - return new TerminationPointBuilder().setKey(mapping.toTopologyTerminationPointKey(connector)).build(); - } -} diff --git a/opendaylight/md-sal/compatibility/inventory-topology-compatibility/src/main/java/org/opendaylight/controller/md/compatibility/topologymanager/AdSalTopologyMapping.java b/opendaylight/md-sal/compatibility/inventory-topology-compatibility/src/main/java/org/opendaylight/controller/md/compatibility/topologymanager/AdSalTopologyMapping.java deleted file mode 100644 index a7a7a9ac3a..0000000000 --- a/opendaylight/md-sal/compatibility/inventory-topology-compatibility/src/main/java/org/opendaylight/controller/md/compatibility/topologymanager/AdSalTopologyMapping.java +++ /dev/null @@ -1,109 +0,0 @@ -/** - * Copyright (c) 2014 Cisco Systems, Inc. and others. All rights reserved. - * - * This program and the accompanying materials are made available under the - * terms of the Eclipse Public License v1.0 which accompanies this distribution, - * and is available at http://www.eclipse.org/legal/epl-v10.html - */ -package org.opendaylight.controller.md.compatibility.topologymanager; - -import java.util.HashMap; -import java.util.HashSet; -import java.util.Map; -import java.util.Set; - -import org.opendaylight.controller.sal.compatibility.NodeMapping; -import org.opendaylight.controller.sal.core.ConstructionException; -import org.opendaylight.controller.sal.core.Edge; -import org.opendaylight.controller.sal.core.NodeConnector; -import org.opendaylight.controller.sal.core.Property; -import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.NodeConnectorId; -import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.node.NodeConnectorKey; -import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.nodes.NodeKey; -import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.NetworkTopology; -import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.NodeId; -import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.link.attributes.Destination; -import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.link.attributes.Source; -import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.Topology; -import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.TopologyKey; -import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.topology.Link; -import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.topology.Node; -import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.topology.node.TerminationPoint; -import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.topology.node.TerminationPointKey; -import org.opendaylight.yangtools.yang.binding.InstanceIdentifier; - -public class AdSalTopologyMapping { - private final InstanceIdentifier topologyPath; - - public AdSalTopologyMapping(final TopologyKey topology) { - this.topologyPath = InstanceIdentifier.builder(NetworkTopology.class) - .child(Topology.class, topology).toInstance(); - } - - public InstanceIdentifier getTopologyPath() { - return topologyPath; - } - - public InstanceIdentifier toTerminationPoint(final NodeConnector connector) { - return getTopologyPath().builder() - .child(Node.class) - .child(TerminationPoint.class, toTerminationPointKey(connector)) - .toInstance(); - } - - public Map> toEdgePropertiesMap(final Iterable links) { - final HashMap> ret = new HashMap<>(); - for (final Link link : links) { - try { - ret.put(toEdge(link), toProperties(link)); - } catch (ConstructionException e) { - throw new IllegalStateException(String.format("Failed to create edge properties for {}", link), e); - } - } - return ret; - } - - public static Set toEdges(final Iterable links) throws ConstructionException { - final HashSet ret = new HashSet(); - for (final Link link : links) { - ret.add(toEdge(link)); - } - return ret; - } - - public static Edge toEdge(final Link link) throws ConstructionException { - final NodeConnector tail = toNodeConnector(link.getSource()); - final NodeConnector head = toNodeConnector(link.getDestination()); - return new Edge(tail, head); - } - - public static org.opendaylight.controller.sal.core.Node toAdNode(final Node node) throws ConstructionException { - return toAdNode(node.getNodeId()); - } - - public static org.opendaylight.controller.sal.core.Node toAdNode(final NodeId node) throws ConstructionException { - final NodeKey key = new NodeKey( - new org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.NodeId(node)); - return new org.opendaylight.controller.sal.core.Node(NodeMapping.MD_SAL_TYPE, key); - } - - public static NodeConnector toNodeConnector(final Source ref) throws ConstructionException { - final org.opendaylight.controller.sal.core.Node adNode = toAdNode(ref.getSourceNode()); - final NodeConnectorKey key = new NodeConnectorKey(new NodeConnectorId(ref.getSourceTp())); - return new NodeConnector(NodeMapping.MD_SAL_TYPE, key, adNode); - } - - public static NodeConnector toNodeConnector(final Destination ref) throws ConstructionException { - final org.opendaylight.controller.sal.core.Node adNode = toAdNode(ref.getDestNode()); - final NodeConnectorKey key = new NodeConnectorKey(new NodeConnectorId(ref.getDestTp())); - return new NodeConnector(NodeMapping.MD_SAL_TYPE, key, adNode); - } - - public TerminationPointKey toTerminationPointKey(final NodeConnector connector) { - return null; - } - - public Set toProperties(final Link link) { - return null; - } -} diff --git a/opendaylight/md-sal/compatibility/inventory-topology-compatibility/src/main/java/org/opendaylight/controller/md/compatibility/topologymanager/CompatibleTopologyManager.java b/opendaylight/md-sal/compatibility/inventory-topology-compatibility/src/main/java/org/opendaylight/controller/md/compatibility/topologymanager/CompatibleTopologyManager.java deleted file mode 100644 index 11320a12cd..0000000000 --- a/opendaylight/md-sal/compatibility/inventory-topology-compatibility/src/main/java/org/opendaylight/controller/md/compatibility/topologymanager/CompatibleTopologyManager.java +++ /dev/null @@ -1,149 +0,0 @@ -/** - * Copyright (c) 2014 Cisco Systems, Inc. and others. All rights reserved. - * - * This program and the accompanying materials are made available under the - * terms of the Eclipse Public License v1.0 which accompanies this distribution, - * and is available at http://www.eclipse.org/legal/epl-v10.html - */ -package org.opendaylight.controller.md.compatibility.topologymanager; - -import java.util.HashMap; -import java.util.List; -import java.util.Map; -import java.util.Set; - -import org.opendaylight.controller.md.sal.binding.util.TypeSafeDataReader; -import org.opendaylight.controller.sal.core.ConstructionException; -import org.opendaylight.controller.sal.core.Edge; -import org.opendaylight.controller.sal.core.Host; -import org.opendaylight.controller.sal.core.NodeConnector; -import org.opendaylight.controller.sal.core.Property; -import org.opendaylight.controller.sal.core.UpdateType; -import org.opendaylight.controller.sal.utils.Status; -import org.opendaylight.controller.topologymanager.ITopologyManager; -import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.NodeId; -import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.TpId; -import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.Topology; -import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.topology.Link; -import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.topology.Node; -import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.topology.node.TerminationPoint; -import org.opendaylight.yangtools.yang.binding.InstanceIdentifier; - -import com.google.common.base.Predicate; -import com.google.common.collect.FluentIterable; - -@SuppressWarnings("all") -public class CompatibleTopologyManager extends ConfigurableLinkManager implements ITopologyManager { - private AdSalTopologyMapping topologyMapping; - private TypeSafeDataReader dataReader; - - public TypeSafeDataReader getDataReader() { - return dataReader; - } - - public void setDataReader(final TypeSafeDataReader dataReader) { - this.dataReader = dataReader; - } - - public AdSalTopologyMapping getTopologyMapping() { - return topologyMapping; - } - - public void setTopologyMapping(final AdSalTopologyMapping topologyMapping) { - this.topologyMapping = topologyMapping; - } - - @Override - public Map> getEdges() { - final Topology topology = getDataReader().readOperationalData(topologyMapping.getTopologyPath()); - return this.topologyMapping.toEdgePropertiesMap(topology.getLink()); - } - - @Override - public Map> getNodeEdges() { - final Topology topology = getDataReader().readOperationalData(topologyMapping.getTopologyPath()); - final HashMap> ret = new HashMap<>(); - for (final Node node : topology.getNode()) { - try { - ret.put(topologyMapping.toAdNode(node), topologyMapping.toEdges( - FluentIterable.from(topology.getLink()).filter(new Predicate() { - @Override - public boolean apply(final Link input) { - final NodeId nodeId = node.getNodeId(); - if (nodeId.equals(input.getSource().getSourceNode())) { - return true; - } - if (nodeId.equals(input.getDestination().getDestNode())) { - return true; - } - - return false; - } - }))); - } catch (ConstructionException e) { - throw new IllegalStateException(String.format("Failed to construct node for {}", node), e); - } - } - return ret; - } - - /** - * Returns true if point is connected to link - */ - private boolean isInternal(final TerminationPoint point) { - final Topology topology = getDataReader().readConfigurationData(topologyMapping.getTopologyPath()); - final TpId tpId = point.getKey().getTpId(); - return FluentIterable.from(topology.getLink()).anyMatch(new Predicate() { - @Override - public boolean apply(final Link input) { - if (tpId.equals(input.getSource().getSourceTp())) { - return true; - } - if (tpId.equals(input.getDestination().getDestTp())) { - return true; - } - return false; - } - }); - } - - @Override - public Set getNodeConnectorWithHost() { - return null; - } - - @Override - public Host getHostAttachedToNodeConnector(final NodeConnector p) { - final InstanceIdentifier tpPath = topologyMapping.toTerminationPoint(p); - throw new UnsupportedOperationException("TODO: auto-generated method stub"); - } - - @Override - public List getHostsAttachedToNodeConnector(final NodeConnector p) { - final Topology topology = getDataReader().readOperationalData(topologyMapping.getTopologyPath()); - throw new UnsupportedOperationException("Hosts not mapped yet"); - } - - @Override - public Map> getNodesWithNodeConnectorHost() { - throw new UnsupportedOperationException("TODO: auto-generated method stub"); - } - - @Override - public boolean isInternal(final NodeConnector p) { - final TerminationPoint connector = getDataReader() - .readConfigurationData(topologyMapping.toTerminationPoint(p)); - return this.isInternal(connector); - } - - @Override - public void updateHostLink(final NodeConnector p, final Host h, final UpdateType t, final Set props) { - // Update app defined topology - } - - @Override - public Status saveConfig() { - // FIXME: commit configuration - return null; - } -} diff --git a/opendaylight/md-sal/compatibility/inventory-topology-compatibility/src/main/java/org/opendaylight/controller/md/compatibility/topologymanager/ConfigurableLinkManager.java b/opendaylight/md-sal/compatibility/inventory-topology-compatibility/src/main/java/org/opendaylight/controller/md/compatibility/topologymanager/ConfigurableLinkManager.java deleted file mode 100644 index 2d85f76278..0000000000 --- a/opendaylight/md-sal/compatibility/inventory-topology-compatibility/src/main/java/org/opendaylight/controller/md/compatibility/topologymanager/ConfigurableLinkManager.java +++ /dev/null @@ -1,31 +0,0 @@ -/** - * Copyright (c) 2014 Cisco Systems, Inc. and others. All rights reserved. - * - * This program and the accompanying materials are made available under the - * terms of the Eclipse Public License v1.0 which accompanies this distribution, - * and is available at http://www.eclipse.org/legal/epl-v10.html - */ -package org.opendaylight.controller.md.compatibility.topologymanager; - -import java.util.concurrent.ConcurrentMap; - -import org.opendaylight.controller.sal.utils.Status; -import org.opendaylight.controller.topologymanager.ITopologyManager; -import org.opendaylight.controller.topologymanager.TopologyUserLinkConfig; - -public abstract class ConfigurableLinkManager implements ITopologyManager { - @Override - public final Status addUserLink(final TopologyUserLinkConfig link) { - throw new UnsupportedOperationException("TODO: auto-generated method stub"); - } - - @Override - public final Status deleteUserLink(final String linkName) { - throw new UnsupportedOperationException("TODO: auto-generated method stub"); - } - - @Override - public final ConcurrentMap getUserLinks() { - throw new UnsupportedOperationException("TODO: auto-generated method stub"); - } -} diff --git a/opendaylight/md-sal/compatibility/pom.xml b/opendaylight/md-sal/compatibility/pom.xml index 688e6ac09b..b9e9d19b48 100644 --- a/opendaylight/md-sal/compatibility/pom.xml +++ b/opendaylight/md-sal/compatibility/pom.xml @@ -12,8 +12,6 @@ sal-compatibility - inventory-topology-compatibility - flow-management-compatibility diff --git a/opendaylight/md-sal/forwardingrules-manager/pom.xml b/opendaylight/md-sal/forwardingrules-manager/pom.xml index ed5e192193..5a9b190219 100644 --- a/opendaylight/md-sal/forwardingrules-manager/pom.xml +++ b/opendaylight/md-sal/forwardingrules-manager/pom.xml @@ -19,10 +19,6 @@ org.opendaylight.controller sal-binding-api - - org.opendaylight.controller.model - model-flow-management - org.opendaylight.controller.model model-flow-service diff --git a/opendaylight/md-sal/md-sal-config/pom.xml b/opendaylight/md-sal/md-sal-config/pom.xml new file mode 100644 index 0000000000..2e19b5a60c --- /dev/null +++ b/opendaylight/md-sal/md-sal-config/pom.xml @@ -0,0 +1,46 @@ + + + + + 4.0.0 + + org.opendaylight.controller + sal-parent + 1.1-SNAPSHOT + + md-sal-config + Configuration files for md-sal + jar + + + + org.codehaus.mojo + build-helper-maven-plugin + + + attach-artifacts + + attach-artifact + + package + + + + ${project.build.directory}/classes/initial/01-md-sal.xml + xml + config + + + + + + + + + diff --git a/opendaylight/distribution/opendaylight/src/main/resources/configuration/initial/01-md-sal.xml b/opendaylight/md-sal/md-sal-config/src/main/resources/initial/01-md-sal.xml similarity index 100% rename from opendaylight/distribution/opendaylight/src/main/resources/configuration/initial/01-md-sal.xml rename to opendaylight/md-sal/md-sal-config/src/main/resources/initial/01-md-sal.xml diff --git a/opendaylight/md-sal/pom.xml b/opendaylight/md-sal/pom.xml index 3f02765aff..6c6760d789 100644 --- a/opendaylight/md-sal/pom.xml +++ b/opendaylight/md-sal/pom.xml @@ -32,6 +32,9 @@ sal-binding-util + + md-sal-config + samples @@ -63,12 +66,18 @@ sal-inmemory-datastore - - sal-protocolbuffer-encoding + + sal-clustering-commons + + + sal-clustering-config sal-distributed-datastore + + sal-dom-xsql + sal-test-model diff --git a/opendaylight/md-sal/sal-akka-raft/src/main/java/org/opendaylight/controller/cluster/example/ExampleActor.java b/opendaylight/md-sal/sal-akka-raft/src/main/java/org/opendaylight/controller/cluster/example/ExampleActor.java index 641ec0582c..cbd7ca2d70 100644 --- a/opendaylight/md-sal/sal-akka-raft/src/main/java/org/opendaylight/controller/cluster/example/ExampleActor.java +++ b/opendaylight/md-sal/sal-akka-raft/src/main/java/org/opendaylight/controller/cluster/example/ExampleActor.java @@ -11,10 +11,12 @@ package org.opendaylight.controller.cluster.example; import akka.actor.ActorRef; import akka.actor.Props; import akka.japi.Creator; +import com.google.common.base.Optional; import org.opendaylight.controller.cluster.example.messages.KeyValue; import org.opendaylight.controller.cluster.example.messages.KeyValueSaved; import org.opendaylight.controller.cluster.example.messages.PrintRole; import org.opendaylight.controller.cluster.example.messages.PrintState; +import org.opendaylight.controller.cluster.raft.ConfigParams; import org.opendaylight.controller.cluster.raft.RaftActor; import org.opendaylight.controller.cluster.raft.protobuff.client.messages.Payload; @@ -31,15 +33,17 @@ public class ExampleActor extends RaftActor { private long persistIdentifier = 1; - public ExampleActor(String id, Map peerAddresses) { - super(id, peerAddresses); + public ExampleActor(String id, Map peerAddresses, + Optional configParams) { + super(id, peerAddresses, configParams); } - public static Props props(final String id, final Map peerAddresses){ + public static Props props(final String id, final Map peerAddresses, + final Optional configParams){ return Props.create(new Creator(){ @Override public ExampleActor create() throws Exception { - return new ExampleActor(id, peerAddresses); + return new ExampleActor(id, peerAddresses, configParams); } }); } @@ -56,10 +60,12 @@ public class ExampleActor extends RaftActor { } } else if (message instanceof PrintState) { - LOG.debug("State of the node:"+getId() + " has = "+state.size() + " entries"); + LOG.debug("State of the node:{} has entries={}, {}", + getId(), state.size(), getReplicatedLogState()); } else if (message instanceof PrintRole) { - LOG.debug(getId() + " = " + getRaftState()); + LOG.debug("{} = {}, Peers={}", getId(), getRaftState(),getPeers()); + } else { super.onReceiveCommand(message); } @@ -83,6 +89,11 @@ public class ExampleActor extends RaftActor { @Override protected void applySnapshot(Object snapshot) { state.clear(); state.putAll((HashMap) snapshot); + LOG.debug("Snapshot applied to state :" + ((HashMap) snapshot).size()); + } + + @Override protected void onStateChanged() { + } @Override public void onReceiveRecover(Object message) { diff --git a/opendaylight/md-sal/sal-akka-raft/src/main/java/org/opendaylight/controller/cluster/example/ExampleConfigParamsImpl.java b/opendaylight/md-sal/sal-akka-raft/src/main/java/org/opendaylight/controller/cluster/example/ExampleConfigParamsImpl.java new file mode 100644 index 0000000000..d11377dbcb --- /dev/null +++ b/opendaylight/md-sal/sal-akka-raft/src/main/java/org/opendaylight/controller/cluster/example/ExampleConfigParamsImpl.java @@ -0,0 +1,20 @@ +/* + * 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.cluster.example; + +import org.opendaylight.controller.cluster.raft.DefaultConfigParamsImpl; + +/** + * Implementation of ConfigParams for Example + */ +public class ExampleConfigParamsImpl extends DefaultConfigParamsImpl { + @Override + public long getSnapshotBatchCount() { + return 50; + } +} diff --git a/opendaylight/md-sal/sal-akka-raft/src/main/java/org/opendaylight/controller/cluster/example/Main.java b/opendaylight/md-sal/sal-akka-raft/src/main/java/org/opendaylight/controller/cluster/example/Main.java index a148ed4009..0e5d643a64 100644 --- a/opendaylight/md-sal/sal-akka-raft/src/main/java/org/opendaylight/controller/cluster/example/Main.java +++ b/opendaylight/md-sal/sal-akka-raft/src/main/java/org/opendaylight/controller/cluster/example/Main.java @@ -11,7 +11,9 @@ package org.opendaylight.controller.cluster.example; import akka.actor.ActorRef; import akka.actor.ActorSystem; import akka.actor.PoisonPill; +import com.google.common.base.Optional; import org.opendaylight.controller.cluster.example.messages.KeyValue; +import org.opendaylight.controller.cluster.raft.ConfigParams; import java.io.BufferedReader; import java.io.InputStreamReader; @@ -34,15 +36,15 @@ public class Main { public static void main(String[] args) throws Exception{ ActorRef example1Actor = actorSystem.actorOf(ExampleActor.props("example-1", - withoutPeer("example-1")), "example-1"); + withoutPeer("example-1"), Optional.absent()), "example-1"); ActorRef example2Actor = actorSystem.actorOf(ExampleActor.props("example-2", - withoutPeer("example-2")), "example-2"); + withoutPeer("example-2"), Optional.absent()), "example-2"); ActorRef example3Actor = actorSystem.actorOf(ExampleActor.props("example-3", - withoutPeer("example-3")), "example-3"); + withoutPeer("example-3"), Optional.absent()), "example-3"); List examples = Arrays.asList(example1Actor, example2Actor, example3Actor); @@ -74,7 +76,8 @@ public class Main { String actorName = "example-" + i; examples.add(i - 1, actorSystem.actorOf(ExampleActor.props(actorName, - withoutPeer(actorName)), actorName)); + withoutPeer(actorName), Optional.absent()), + actorName)); System.out.println("Created actor : " + actorName); continue; } diff --git a/opendaylight/md-sal/sal-akka-raft/src/main/java/org/opendaylight/controller/cluster/example/TestDriver.java b/opendaylight/md-sal/sal-akka-raft/src/main/java/org/opendaylight/controller/cluster/example/TestDriver.java index c2d0b3a6b7..fd6e192bf0 100644 --- a/opendaylight/md-sal/sal-akka-raft/src/main/java/org/opendaylight/controller/cluster/example/TestDriver.java +++ b/opendaylight/md-sal/sal-akka-raft/src/main/java/org/opendaylight/controller/cluster/example/TestDriver.java @@ -2,8 +2,10 @@ package org.opendaylight.controller.cluster.example; import akka.actor.ActorRef; import akka.actor.ActorSystem; +import com.google.common.base.Optional; import org.opendaylight.controller.cluster.example.messages.PrintRole; import org.opendaylight.controller.cluster.example.messages.PrintState; +import org.opendaylight.controller.cluster.raft.ConfigParams; import org.opendaylight.controller.cluster.raft.client.messages.AddRaftPeer; import org.opendaylight.controller.cluster.raft.client.messages.RemoveRaftPeer; @@ -11,14 +13,13 @@ import java.io.BufferedReader; import java.io.InputStreamReader; import java.util.HashMap; import java.util.Map; -import java.util.Random; import java.util.concurrent.ConcurrentHashMap; /** * This is a test driver for testing akka-raft implementation * Its uses ExampleActors and threads to push content(key-vals) to these actors * Each ExampleActor can have one or more ClientActors. Each ClientActor spawns - * a thread and starts push logs to the actor its assignged to. + * a thread and starts push logs to the actor its assigned to. */ public class TestDriver { @@ -26,7 +27,9 @@ public class TestDriver { private static Map allPeers = new HashMap<>(); private static Map clientActorRefs = new HashMap(); private static Map actorRefs = new HashMap(); - private static LogGenerator logGenerator = new LogGenerator();; + private static LogGenerator logGenerator = new LogGenerator(); + private int nameCounter = 0; + private static ConfigParams configParams = new ExampleConfigParamsImpl(); /** * Create nodes, add clients and start logging. @@ -35,6 +38,7 @@ public class TestDriver { * createNodes:{num} * addNodes:{num} * stopNode:{nodeName} + * reinstateNode:{nodeName} * addClients:{num} * addClientsToNode:{nodeName, num} * startLogging @@ -83,6 +87,10 @@ public class TestDriver { String[] arr = command.split(":"); td.stopNode(arr[1]); + } else if (command.startsWith("reinstateNode")) { + String[] arr = command.split(":"); + td.reinstateNode(arr[1]); + } else if (command.startsWith("startLogging")) { td.startAllLogging(); @@ -106,15 +114,19 @@ public class TestDriver { } } + public static ActorRef createExampleActor(String name) { + return actorSystem.actorOf(ExampleActor.props(name, withoutPeer(name), + Optional.of(configParams)), name); + } + public void createNodes(int num) { for (int i=0; i < num; i++) { - int rand = getUnusedRandom(num); - allPeers.put("example-"+rand, "akka://default/user/example-"+rand); + nameCounter = nameCounter + 1; + allPeers.put("example-"+nameCounter, "akka://default/user/example-"+nameCounter); } for (String s : allPeers.keySet()) { - ActorRef exampleActor = actorSystem.actorOf( - ExampleActor.props(s, withoutPeer(s)), s); + ActorRef exampleActor = createExampleActor(s); actorRefs.put(s, exampleActor); System.out.println("Created node:"+s); @@ -125,15 +137,14 @@ public class TestDriver { public void addNodes(int num) { Map newPeers = new HashMap<>(); for (int i=0; i < num; i++) { - int rand = getUnusedRandom(num); - newPeers.put("example-"+rand, "akka://default/user/example-"+rand); - allPeers.put("example-"+rand, "akka://default/user/example-"+rand); + nameCounter = nameCounter + 1; + newPeers.put("example-"+nameCounter, "akka://default/user/example-"+nameCounter); + allPeers.put("example-"+nameCounter, "akka://default/user/example-"+nameCounter); } Map newActorRefs = new HashMap(num); for (Map.Entry entry : newPeers.entrySet()) { - ActorRef exampleActor = actorSystem.actorOf( - ExampleActor.props(entry.getKey(), withoutPeer(entry.getKey())), entry.getKey()); + ActorRef exampleActor = createExampleActor(entry.getKey()); newActorRefs.put(entry.getKey(), exampleActor); //now also add these new nodes as peers from the previous nodes @@ -165,7 +176,7 @@ public class TestDriver { public void addClientsToNode(String actorName, int num) { ActorRef actorRef = actorRefs.get(actorName); for (int i=0; i < num; i++) { - String clientName = "client-" + i + "-" + actorRef; + String clientName = "client-" + i + "-" + actorName; clientActorRefs.put(clientName, actorSystem.actorOf(ClientActor.props(actorRef), clientName)); System.out.println("Added client-node:" + clientName); @@ -174,11 +185,13 @@ public class TestDriver { public void stopNode(String actorName) { ActorRef actorRef = actorRefs.get(actorName); - String clientName = "client-"+actorName; - if(clientActorRefs.containsKey(clientName)) { - actorSystem.stop(clientActorRefs.get(clientName)); - clientActorRefs.remove(clientName); + + for (Map.Entry entry : clientActorRefs.entrySet()) { + if (entry.getKey().endsWith(actorName)) { + actorSystem.stop(entry.getValue()); + } } + actorSystem.stop(actorRef); actorRefs.remove(actorName); @@ -187,7 +200,21 @@ public class TestDriver { } allPeers.remove(actorName); + } + public void reinstateNode(String actorName) { + String address = "akka://default/user/"+actorName; + allPeers.put(actorName, address); + + ActorRef exampleActor = createExampleActor(actorName); + + for (ActorRef actor : actorRefs.values()) { + actor.tell(new AddRaftPeer(actorName, address), null); + } + + actorRefs.put(actorName, exampleActor); + + addClientsToNode(actorName, 1); } public void startAllLogging() { @@ -232,14 +259,6 @@ public class TestDriver { return null; } - private int getUnusedRandom(int num) { - int rand = -1; - do { - rand = (new Random()).nextInt(num * num); - } while (allPeers.keySet().contains("example-"+rand)); - - return rand; - } private static Map withoutPeer(String peerId) { Map without = new ConcurrentHashMap<>(allPeers); diff --git a/opendaylight/md-sal/sal-akka-raft/src/main/java/org/opendaylight/controller/cluster/raft/AbstractReplicatedLogImpl.java b/opendaylight/md-sal/sal-akka-raft/src/main/java/org/opendaylight/controller/cluster/raft/AbstractReplicatedLogImpl.java new file mode 100644 index 0000000000..b5b034afb9 --- /dev/null +++ b/opendaylight/md-sal/sal-akka-raft/src/main/java/org/opendaylight/controller/cluster/raft/AbstractReplicatedLogImpl.java @@ -0,0 +1,163 @@ +/* + * 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.cluster.raft; + +import java.util.ArrayList; +import java.util.List; + +/** + * Abstract class handling the mapping of + * logical LogEntry Index and the physical list index. + */ +public abstract class AbstractReplicatedLogImpl implements ReplicatedLog { + + protected final List journal; + protected final Object snapshot; + protected long snapshotIndex = -1; + protected long snapshotTerm = -1; + + public AbstractReplicatedLogImpl(Object state, long snapshotIndex, + long snapshotTerm, List unAppliedEntries) { + this.snapshot = state; + this.snapshotIndex = snapshotIndex; + this.snapshotTerm = snapshotTerm; + this.journal = new ArrayList<>(unAppliedEntries); + } + + + public AbstractReplicatedLogImpl() { + this.snapshot = null; + this.journal = new ArrayList<>(); + } + + protected int adjustedIndex(long logEntryIndex) { + if(snapshotIndex < 0){ + return (int) logEntryIndex; + } + return (int) (logEntryIndex - (snapshotIndex + 1)); + } + + @Override + public ReplicatedLogEntry get(long logEntryIndex) { + int adjustedIndex = adjustedIndex(logEntryIndex); + + if (adjustedIndex < 0 || adjustedIndex >= journal.size()) { + // physical index should be less than list size and >= 0 + return null; + } + + return journal.get(adjustedIndex); + } + + @Override + public ReplicatedLogEntry last() { + if (journal.isEmpty()) { + return null; + } + // get the last entry directly from the physical index + return journal.get(journal.size() - 1); + } + + @Override + public long lastIndex() { + if (journal.isEmpty()) { + // it can happen that after snapshot, all the entries of the + // journal are trimmed till lastApplied, so lastIndex = snapshotIndex + return snapshotIndex; + } + return last().getIndex(); + } + + @Override + public long lastTerm() { + if (journal.isEmpty()) { + // it can happen that after snapshot, all the entries of the + // journal are trimmed till lastApplied, so lastTerm = snapshotTerm + return snapshotTerm; + } + return last().getTerm(); + } + + @Override + public void removeFrom(long logEntryIndex) { + int adjustedIndex = adjustedIndex(logEntryIndex); + if (adjustedIndex < 0 || adjustedIndex >= journal.size()) { + // physical index should be less than list size and >= 0 + return; + } + journal.subList(adjustedIndex , journal.size()).clear(); + } + + @Override + public void append(ReplicatedLogEntry replicatedLogEntry) { + journal.add(replicatedLogEntry); + } + + @Override + public List getFrom(long logEntryIndex) { + return getFrom(logEntryIndex, journal.size()); + } + + @Override + public List getFrom(long logEntryIndex, int max) { + int adjustedIndex = adjustedIndex(logEntryIndex); + int size = journal.size(); + List entries = new ArrayList<>(100); + if (adjustedIndex >= 0 && adjustedIndex < size) { + // physical index should be less than list size and >= 0 + int maxIndex = adjustedIndex + max; + if(maxIndex > size){ + maxIndex = size; + } + entries.addAll(journal.subList(adjustedIndex, maxIndex)); + } + return entries; + } + + + @Override + public long size() { + return journal.size(); + } + + @Override + public boolean isPresent(long logEntryIndex) { + if (logEntryIndex > lastIndex()) { + // if the request logical index is less than the last present in the list + return false; + } + int adjustedIndex = adjustedIndex(logEntryIndex); + return (adjustedIndex >= 0); + } + + @Override + public boolean isInSnapshot(long logEntryIndex) { + return logEntryIndex <= snapshotIndex; + } + + @Override + public Object getSnapshot() { + return snapshot; + } + + @Override + public long getSnapshotIndex() { + return snapshotIndex; + } + + @Override + public long getSnapshotTerm() { + return snapshotTerm; + } + + @Override + public abstract void appendAndPersist(ReplicatedLogEntry replicatedLogEntry); + + @Override + public abstract void removeFromAndPersist(long index); +} diff --git a/opendaylight/md-sal/sal-akka-raft/src/main/java/org/opendaylight/controller/cluster/raft/ConfigParams.java b/opendaylight/md-sal/sal-akka-raft/src/main/java/org/opendaylight/controller/cluster/raft/ConfigParams.java new file mode 100644 index 0000000000..4c6434aec4 --- /dev/null +++ b/opendaylight/md-sal/sal-akka-raft/src/main/java/org/opendaylight/controller/cluster/raft/ConfigParams.java @@ -0,0 +1,55 @@ +/* + * 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.cluster.raft; + +import scala.concurrent.duration.FiniteDuration; + +/** + * Configuration Parameter interface for configuring the Raft consensus system + *

+ * Any component using this implementation might want to provide an implementation of + * this interface to configure + * + * A default implementation will be used if none is provided. + * + * @author Kamal Rameshan + */ +public interface ConfigParams { + /** + * The minimum number of entries to be present in the in-memory Raft log + * for a snapshot to be taken + * + * @return long + */ + public long getSnapshotBatchCount(); + + /** + * The interval at which a heart beat message will be sent to the remote + * RaftActor + * + * @return FiniteDuration + */ + public FiniteDuration getHeartBeatInterval(); + + /** + * The interval in which a new election would get triggered if no leader is found + * + * Normally its set to atleast twice the heart beat interval + * + * @return FiniteDuration + */ + public FiniteDuration getElectionTimeOutInterval(); + + /** + * The maximum election time variance. The election is scheduled using both + * the Election Timeout and Variance + * + * @return int + */ + public int getElectionTimeVariance(); +} diff --git a/opendaylight/md-sal/sal-akka-raft/src/main/java/org/opendaylight/controller/cluster/raft/DefaultConfigParamsImpl.java b/opendaylight/md-sal/sal-akka-raft/src/main/java/org/opendaylight/controller/cluster/raft/DefaultConfigParamsImpl.java new file mode 100644 index 0000000000..6432fa4811 --- /dev/null +++ b/opendaylight/md-sal/sal-akka-raft/src/main/java/org/opendaylight/controller/cluster/raft/DefaultConfigParamsImpl.java @@ -0,0 +1,61 @@ +/* + * 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.cluster.raft; + +import scala.concurrent.duration.FiniteDuration; + +import java.util.concurrent.TimeUnit; + +/** + * Default implementation of the ConfigParams + * + * If no implementation is provided for ConfigParams, then this will be used. + */ +public class DefaultConfigParamsImpl implements ConfigParams { + + private static final int SNAPSHOT_BATCH_COUNT = 100000; + + /** + * The maximum election time variance + */ + private static final int ELECTION_TIME_MAX_VARIANCE = 100; + + + /** + * The interval at which a heart beat message will be sent to the remote + * RaftActor + *

+ * Since this is set to 100 milliseconds the Election timeout should be + * at least 200 milliseconds + */ + public static final FiniteDuration HEART_BEAT_INTERVAL = + new FiniteDuration(100, TimeUnit.MILLISECONDS); + + + @Override + public long getSnapshotBatchCount() { + return SNAPSHOT_BATCH_COUNT; + } + + @Override + public FiniteDuration getHeartBeatInterval() { + return HEART_BEAT_INTERVAL; + } + + + @Override + public FiniteDuration getElectionTimeOutInterval() { + // returns 2 times the heart beat interval + return getHeartBeatInterval().$times(2); + } + + @Override + public int getElectionTimeVariance() { + return ELECTION_TIME_MAX_VARIANCE; + } +} diff --git a/opendaylight/md-sal/sal-akka-raft/src/main/java/org/opendaylight/controller/cluster/raft/RaftActor.java b/opendaylight/md-sal/sal-akka-raft/src/main/java/org/opendaylight/controller/cluster/raft/RaftActor.java index b8e9653bc5..0a979d24ee 100644 --- a/opendaylight/md-sal/sal-akka-raft/src/main/java/org/opendaylight/controller/cluster/raft/RaftActor.java +++ b/opendaylight/md-sal/sal-akka-raft/src/main/java/org/opendaylight/controller/cluster/raft/RaftActor.java @@ -22,6 +22,7 @@ import akka.persistence.UntypedPersistentActor; import org.opendaylight.controller.cluster.raft.base.messages.ApplySnapshot; import org.opendaylight.controller.cluster.raft.base.messages.ApplyState; import org.opendaylight.controller.cluster.raft.base.messages.Replicate; +import com.google.common.base.Optional; import org.opendaylight.controller.cluster.raft.behaviors.Candidate; import org.opendaylight.controller.cluster.raft.behaviors.Follower; import org.opendaylight.controller.cluster.raft.behaviors.Leader; @@ -33,7 +34,6 @@ import org.opendaylight.controller.cluster.raft.client.messages.RemoveRaftPeer; import org.opendaylight.controller.cluster.raft.protobuff.client.messages.Payload; import java.io.Serializable; -import java.util.ArrayList; import java.util.List; import java.util.Map; @@ -100,14 +100,22 @@ public abstract class RaftActor extends UntypedPersistentActor { public RaftActor(String id, Map peerAddresses) { + this(id, peerAddresses, Optional.absent()); + } + + public RaftActor(String id, Map peerAddresses, + Optional configParams) { + context = new RaftActorContextImpl(this.getSelf(), - this.getContext(), - id, new ElectionTermImpl(), - -1, -1, replicatedLog, peerAddresses, LOG); + this.getContext(), id, new ElectionTermImpl(), + -1, -1, replicatedLog, peerAddresses, + (configParams.isPresent() ? configParams.get(): new DefaultConfigParamsImpl()), + LOG); } @Override public void onReceiveRecover(Object message) { if (message instanceof SnapshotOffer) { + LOG.debug("SnapshotOffer called.."); SnapshotOffer offer = (SnapshotOffer) message; Snapshot snapshot = (Snapshot) offer.snapshot(); @@ -116,6 +124,13 @@ public abstract class RaftActor extends UntypedPersistentActor { // when we need to install it on a peer replicatedLog = new ReplicatedLogImpl(snapshot); + context.setReplicatedLog(replicatedLog); + + LOG.debug("Applied snapshot to replicatedLog. " + + "snapshotIndex={}, snapshotTerm={}, journal-size={}", + replicatedLog.snapshotIndex, replicatedLog.snapshotTerm, + replicatedLog.size()); + // Apply the snapshot to the actors state applySnapshot(snapshot.getState()); @@ -127,8 +142,13 @@ public abstract class RaftActor extends UntypedPersistentActor { context.getTermInformation().update(((UpdateElectionTerm) message).getCurrentTerm(), ((UpdateElectionTerm) message).getVotedFor()); } else if (message instanceof RecoveryCompleted) { LOG.debug( - "Last index in log : " + replicatedLog.lastIndex()); + "RecoveryCompleted - Switching actor to Follower - " + + "Last index in log:{}, snapshotIndex={}, snapshotTerm={}, " + + "journal-size={}", + replicatedLog.lastIndex(), replicatedLog.snapshotIndex, + replicatedLog.snapshotTerm, replicatedLog.size()); currentBehavior = switchBehavior(RaftState.Follower); + onStateChanged(); } } @@ -187,10 +207,23 @@ public abstract class RaftActor extends UntypedPersistentActor { RaftState state = currentBehavior.handleMessage(getSender(), message); + RaftActorBehavior oldBehavior = currentBehavior; currentBehavior = switchBehavior(state); + if(oldBehavior != currentBehavior){ + onStateChanged(); + } } } + public java.util.Set getPeers() { + return context.getPeerAddresses().keySet(); + } + + protected String getReplicatedLogState() { + return "snapshotIndex=" + context.getReplicatedLog().getSnapshotIndex() + + ", snapshotTerm=" + context.getReplicatedLog().getSnapshotTerm() + + ", im-mem journal size=" + context.getReplicatedLog().size(); + } /** @@ -243,9 +276,21 @@ public abstract class RaftActor extends UntypedPersistentActor { String peerAddress = context.getPeerAddress(leaderId); LOG.debug("getLeader leaderId = " + leaderId + " peerAddress = " + peerAddress); + + if(peerAddress == null){ + return null; + } return context.actorSelection(peerAddress); } + /** + * + * @return the current leader's id + */ + protected String getLeaderId(){ + return currentBehavior.getLeaderId(); + } + protected RaftState getRaftState() { return currentBehavior.state(); } @@ -313,6 +358,13 @@ public abstract class RaftActor extends UntypedPersistentActor { */ protected abstract void applySnapshot(Object snapshot); + /** + * This method will be called by the RaftActor when the state of the + * RaftActor changes. The derived actor can then use methods like + * isLeader or getLeader to do something useful + */ + protected abstract void onStateChanged(); + private RaftActorBehavior switchBehavior(RaftState state) { if (currentBehavior != null) { if (currentBehavior.state() == state) { @@ -339,89 +391,40 @@ public abstract class RaftActor extends UntypedPersistentActor { } else { behavior = new Leader(context); } + + + return behavior; } private void trimPersistentData(long sequenceNumber) { - // Trim snapshots + // Trim akka snapshots // FIXME : Not sure how exactly the SnapshotSelectionCriteria is applied // For now guessing that it is ANDed. deleteSnapshots(new SnapshotSelectionCriteria( - sequenceNumber - 100000, 43200000)); + sequenceNumber - context.getConfigParams().getSnapshotBatchCount(), 43200000)); - // Trim journal + // Trim akka journal deleteMessages(sequenceNumber); } - private class ReplicatedLogImpl implements ReplicatedLog { - private final List journal; - private final Object snapshot; - private long snapshotIndex = -1; - private long snapshotTerm = -1; + private class ReplicatedLogImpl extends AbstractReplicatedLogImpl { public ReplicatedLogImpl(Snapshot snapshot) { - this.snapshot = snapshot.getState(); - this.snapshotIndex = snapshot.getLastAppliedIndex(); - this.snapshotTerm = snapshot.getLastAppliedTerm(); - - this.journal = new ArrayList<>(snapshot.getUnAppliedEntries()); + super(snapshot.getState(), + snapshot.getLastAppliedIndex(), snapshot.getLastAppliedTerm(), + snapshot.getUnAppliedEntries()); } public ReplicatedLogImpl() { - this.snapshot = null; - this.journal = new ArrayList<>(); - } - - @Override public ReplicatedLogEntry get(long index) { - int adjustedIndex = adjustedIndex(index); - - if (adjustedIndex < 0 || adjustedIndex >= journal.size()) { - return null; - } - - return journal.get(adjustedIndex); - } - - @Override public ReplicatedLogEntry last() { - if (journal.size() == 0) { - return null; - } - return get(journal.size() - 1); - } - - @Override public long lastIndex() { - if (journal.size() == 0) { - return -1; - } - - return last().getIndex(); - } - - @Override public long lastTerm() { - if (journal.size() == 0) { - return -1; - } - - return last().getTerm(); + super(); } + @Override public void removeFromAndPersist(long logEntryIndex) { + int adjustedIndex = adjustedIndex(logEntryIndex); - @Override public void removeFrom(long index) { - int adjustedIndex = adjustedIndex(index); - - if (adjustedIndex < 0 || adjustedIndex >= journal.size()) { - return; - } - - journal.subList(adjustedIndex , journal.size()).clear(); - } - - - @Override public void removeFromAndPersist(long index) { - int adjustedIndex = adjustedIndex(index); - - if (adjustedIndex < 0 || adjustedIndex >= journal.size()) { + if (adjustedIndex < 0) { return; } @@ -435,29 +438,6 @@ public abstract class RaftActor extends UntypedPersistentActor { //FIXME : Doing nothing for now } }); - - - } - - @Override public void append( - final ReplicatedLogEntry replicatedLogEntry) { - journal.add(replicatedLogEntry); - } - - @Override public List getFrom(long index) { - int adjustedIndex = adjustedIndex(index); - - List entries = new ArrayList<>(100); - if (adjustedIndex < 0 || adjustedIndex >= journal.size()) { - return entries; - } - - - for (int i = adjustedIndex; - i < journal.size(); i++) { - entries.add(journal.get(i)); - } - return entries; } @Override public void appendAndPersist( @@ -482,20 +462,42 @@ public abstract class RaftActor extends UntypedPersistentActor { new Procedure() { public void apply(ReplicatedLogEntry evt) throws Exception { // FIXME : Tentatively create a snapshot every hundred thousand entries. To be tuned. - if (size() > 100000) { - ReplicatedLogEntry lastAppliedEntry = - get(context.getLastApplied()); + if (journal.size() > context.getConfigParams().getSnapshotBatchCount()) { + LOG.info("Initiating Snapshot Capture.."); long lastAppliedIndex = -1; long lastAppliedTerm = -1; + + ReplicatedLogEntry lastAppliedEntry = get(context.getLastApplied()); if (lastAppliedEntry != null) { lastAppliedIndex = lastAppliedEntry.getIndex(); lastAppliedTerm = lastAppliedEntry.getTerm(); } - saveSnapshot(Snapshot.create(createSnapshot(), + LOG.debug("Snapshot Capture logSize: {}", journal.size()); + LOG.debug("Snapshot Capture lastApplied:{} ", context.getLastApplied()); + LOG.debug("Snapshot Capture lastAppliedIndex:{}", lastAppliedIndex); + LOG.debug("Snapshot Capture lastAppliedTerm:{}", lastAppliedTerm); + + // create a snapshot object from the state provided and save it + // when snapshot is saved async, SaveSnapshotSuccess is raised. + Snapshot sn = Snapshot.create(createSnapshot(), getFrom(context.getLastApplied() + 1), lastIndex(), lastTerm(), lastAppliedIndex, - lastAppliedTerm)); + lastAppliedTerm); + saveSnapshot(sn); + + LOG.info("Persisting of snapshot done:{}", sn.getLogMessage()); + + //be greedy and remove entries from in-mem journal which are in the snapshot + // and update snapshotIndex and snapshotTerm without waiting for the success, + // TODO: damage-recovery to be done on failure + journal.subList(0, (int) (lastAppliedIndex - snapshotIndex)).clear(); + snapshotIndex = lastAppliedIndex; + snapshotTerm = lastAppliedTerm; + + LOG.info("Removed in-memory snapshotted entries, " + + "adjusted snaphsotIndex:{}" + + "and term:{}", snapshotIndex, lastAppliedTerm); } // Send message for replication if (clientActor != null) { @@ -509,46 +511,8 @@ public abstract class RaftActor extends UntypedPersistentActor { ); } - @Override public long size() { - return journal.size() + snapshotIndex + 1; - } - - @Override public boolean isPresent(long index) { - int adjustedIndex = adjustedIndex(index); - - if (adjustedIndex < 0 || adjustedIndex >= journal.size()) { - return false; - } - return true; - } - - @Override public boolean isInSnapshot(long index) { - return index <= snapshotIndex; - } - - @Override public Object getSnapshot() { - return snapshot; - } - - @Override public long getSnapshotIndex() { - return snapshotIndex; - } - - @Override public long getSnapshotTerm() { - return snapshotTerm; - } - - private int adjustedIndex(long index) { - if(snapshotIndex < 0){ - return (int) index; - } - return (int) (index - snapshotIndex); - } } - - - private static class DeleteEntries implements Serializable { private final int fromIndex; @@ -609,6 +573,17 @@ public abstract class RaftActor extends UntypedPersistentActor { public long getLastAppliedTerm() { return lastAppliedTerm; } + + public String getLogMessage() { + StringBuilder sb = new StringBuilder(); + return sb.append("Snapshot={") + .append("lastTerm:" + this.getLastTerm() + ", ") + .append("LastAppliedIndex:" + this.getLastAppliedIndex() + ", ") + .append("LastAppliedTerm:" + this.getLastAppliedTerm() + ", ") + .append("UnAppliedEntries size:" + this.getUnAppliedEntries().size() + "}") + .toString(); + + } } private class ElectionTermImpl implements ElectionTerm { diff --git a/opendaylight/md-sal/sal-akka-raft/src/main/java/org/opendaylight/controller/cluster/raft/RaftActorContext.java b/opendaylight/md-sal/sal-akka-raft/src/main/java/org/opendaylight/controller/cluster/raft/RaftActorContext.java index ae9431a43a..0eb4b73779 100644 --- a/opendaylight/md-sal/sal-akka-raft/src/main/java/org/opendaylight/controller/cluster/raft/RaftActorContext.java +++ b/opendaylight/md-sal/sal-akka-raft/src/main/java/org/opendaylight/controller/cluster/raft/RaftActorContext.java @@ -85,6 +85,12 @@ public interface RaftActorContext { */ void setLastApplied(long lastApplied); + /** + * + * @param replicatedLog + */ + public void setReplicatedLog(ReplicatedLog replicatedLog); + /** * @return A representation of the log */ @@ -155,4 +161,9 @@ public interface RaftActorContext { * @param peerAddress */ void setPeerAddress(String peerId, String peerAddress); + + /** + * @return ConfigParams + */ + public ConfigParams getConfigParams(); } diff --git a/opendaylight/md-sal/sal-akka-raft/src/main/java/org/opendaylight/controller/cluster/raft/RaftActorContextImpl.java b/opendaylight/md-sal/sal-akka-raft/src/main/java/org/opendaylight/controller/cluster/raft/RaftActorContextImpl.java index 833c8a9e8a..25da37105c 100644 --- a/opendaylight/md-sal/sal-akka-raft/src/main/java/org/opendaylight/controller/cluster/raft/RaftActorContextImpl.java +++ b/opendaylight/md-sal/sal-akka-raft/src/main/java/org/opendaylight/controller/cluster/raft/RaftActorContextImpl.java @@ -19,7 +19,7 @@ import java.util.Map; import static com.google.common.base.Preconditions.checkState; -public class RaftActorContextImpl implements RaftActorContext{ +public class RaftActorContextImpl implements RaftActorContext { private final ActorRef actor; @@ -33,16 +33,20 @@ public class RaftActorContextImpl implements RaftActorContext{ private long lastApplied; - private final ReplicatedLog replicatedLog; + private ReplicatedLog replicatedLog; private final Map peerAddresses; private final LoggingAdapter LOG; + private final ConfigParams configParams; + public RaftActorContextImpl(ActorRef actor, UntypedActorContext context, String id, ElectionTerm termInformation, long commitIndex, - long lastApplied, ReplicatedLog replicatedLog, Map peerAddresses, LoggingAdapter logger) { + long lastApplied, ReplicatedLog replicatedLog, + Map peerAddresses, ConfigParams configParams, + LoggingAdapter logger) { this.actor = actor; this.context = context; this.id = id; @@ -51,6 +55,7 @@ public class RaftActorContextImpl implements RaftActorContext{ this.lastApplied = lastApplied; this.replicatedLog = replicatedLog; this.peerAddresses = peerAddresses; + this.configParams = configParams; this.LOG = logger; } @@ -90,6 +95,10 @@ public class RaftActorContextImpl implements RaftActorContext{ this.lastApplied = lastApplied; } + @Override public void setReplicatedLog(ReplicatedLog replicatedLog) { + this.replicatedLog = replicatedLog; + } + @Override public ReplicatedLog getReplicatedLog() { return replicatedLog; } @@ -110,6 +119,10 @@ public class RaftActorContextImpl implements RaftActorContext{ return peerAddresses.get(peerId); } + @Override public ConfigParams getConfigParams() { + return configParams; + } + @Override public void addToPeers(String name, String address) { peerAddresses.put(name, address); } diff --git a/opendaylight/md-sal/sal-akka-raft/src/main/java/org/opendaylight/controller/cluster/raft/ReplicatedLog.java b/opendaylight/md-sal/sal-akka-raft/src/main/java/org/opendaylight/controller/cluster/raft/ReplicatedLog.java index b7c8955aad..e6e160bc02 100644 --- a/opendaylight/md-sal/sal-akka-raft/src/main/java/org/opendaylight/controller/cluster/raft/ReplicatedLog.java +++ b/opendaylight/md-sal/sal-akka-raft/src/main/java/org/opendaylight/controller/cluster/raft/ReplicatedLog.java @@ -84,6 +84,11 @@ public interface ReplicatedLog { */ List getFrom(long index); + /** + * + * @param index the index of the log entry + */ + List getFrom(long index, int max); /** * diff --git a/opendaylight/md-sal/sal-akka-raft/src/main/java/org/opendaylight/controller/cluster/raft/behaviors/AbstractRaftActorBehavior.java b/opendaylight/md-sal/sal-akka-raft/src/main/java/org/opendaylight/controller/cluster/raft/behaviors/AbstractRaftActorBehavior.java index f7281bb8e3..0a553b40fd 100644 --- a/opendaylight/md-sal/sal-akka-raft/src/main/java/org/opendaylight/controller/cluster/raft/behaviors/AbstractRaftActorBehavior.java +++ b/opendaylight/md-sal/sal-akka-raft/src/main/java/org/opendaylight/controller/cluster/raft/behaviors/AbstractRaftActorBehavior.java @@ -43,27 +43,6 @@ public abstract class AbstractRaftActorBehavior implements RaftActorBehavior { */ protected final RaftActorContext context; - /** - * The maximum election time variance - */ - private static final int ELECTION_TIME_MAX_VARIANCE = 100; - - /** - * The interval at which a heart beat message will be sent to the remote - * RaftActor - *

- * Since this is set to 100 milliseconds the Election timeout should be - * at least 200 milliseconds - */ - protected static final FiniteDuration HEART_BEAT_INTERVAL = - new FiniteDuration(100, TimeUnit.MILLISECONDS); - - /** - * The interval in which a new election would get triggered if no leader is found - */ - private static final long ELECTION_TIME_INTERVAL = - HEART_BEAT_INTERVAL.toMillis() * 2; - /** * */ @@ -208,9 +187,9 @@ public abstract class AbstractRaftActorBehavior implements RaftActorBehavior { * @return */ protected FiniteDuration electionDuration() { - long variance = new Random().nextInt(ELECTION_TIME_MAX_VARIANCE); - return new FiniteDuration(ELECTION_TIME_INTERVAL + variance, - TimeUnit.MILLISECONDS); + long variance = new Random().nextInt(context.getConfigParams().getElectionTimeVariance()); + return context.getConfigParams().getElectionTimeOutInterval().$plus( + new FiniteDuration(variance, TimeUnit.MILLISECONDS)); } /** diff --git a/opendaylight/md-sal/sal-akka-raft/src/main/java/org/opendaylight/controller/cluster/raft/behaviors/Follower.java b/opendaylight/md-sal/sal-akka-raft/src/main/java/org/opendaylight/controller/cluster/raft/behaviors/Follower.java index db62dfc2ac..c8cd41dfa1 100644 --- a/opendaylight/md-sal/sal-akka-raft/src/main/java/org/opendaylight/controller/cluster/raft/behaviors/Follower.java +++ b/opendaylight/md-sal/sal-akka-raft/src/main/java/org/opendaylight/controller/cluster/raft/behaviors/Follower.java @@ -126,15 +126,10 @@ public class Follower extends AbstractRaftActorBehavior { int addEntriesFrom = 0; if (context.getReplicatedLog().size() > 0) { - // Find the entry up until which the one that is not in the - // follower's log - for (int i = 0; - i < appendEntries.getEntries() - .size(); i++, addEntriesFrom++) { - ReplicatedLogEntry matchEntry = - appendEntries.getEntries().get(i); - ReplicatedLogEntry newEntry = context.getReplicatedLog() - .get(matchEntry.getIndex()); + // Find the entry up until which the one that is not in the follower's log + for (int i = 0;i < appendEntries.getEntries().size(); i++, addEntriesFrom++) { + ReplicatedLogEntry matchEntry = appendEntries.getEntries().get(i); + ReplicatedLogEntry newEntry = context.getReplicatedLog().get(matchEntry.getIndex()); if (newEntry == null) { //newEntry not found in the log diff --git a/opendaylight/md-sal/sal-akka-raft/src/main/java/org/opendaylight/controller/cluster/raft/behaviors/Leader.java b/opendaylight/md-sal/sal-akka-raft/src/main/java/org/opendaylight/controller/cluster/raft/behaviors/Leader.java index 53e47c2f84..a50666233c 100644 --- a/opendaylight/md-sal/sal-akka-raft/src/main/java/org/opendaylight/controller/cluster/raft/behaviors/Leader.java +++ b/opendaylight/md-sal/sal-akka-raft/src/main/java/org/opendaylight/controller/cluster/raft/behaviors/Leader.java @@ -112,8 +112,8 @@ public class Leader extends AbstractRaftActorBehavior { scheduleHeartBeat(new FiniteDuration(0, TimeUnit.SECONDS)); scheduleInstallSnapshotCheck( - new FiniteDuration(HEART_BEAT_INTERVAL.length() * 1000, - HEART_BEAT_INTERVAL.unit()) + new FiniteDuration(context.getConfigParams().getHeartBeatInterval().length() * 1000, + context.getConfigParams().getHeartBeatInterval().unit()) ); } @@ -241,7 +241,7 @@ public class Leader extends AbstractRaftActorBehavior { (InstallSnapshotReply) message); } } finally { - scheduleHeartBeat(HEART_BEAT_INTERVAL); + scheduleHeartBeat(context.getConfigParams().getHeartBeatInterval()); } return super.handleMessage(sender, message); @@ -310,7 +310,7 @@ public class Leader extends AbstractRaftActorBehavior { // that has fallen too far behind with the log but yet is not // eligible to receive a snapshot entries = - context.getReplicatedLog().getFrom(nextIndex); + context.getReplicatedLog().getFrom(nextIndex, 1); } followerActor.tell( diff --git a/opendaylight/md-sal/sal-akka-raft/src/test/java/org/opendaylight/controller/cluster/raft/AbstractReplicatedLogImplTest.java b/opendaylight/md-sal/sal-akka-raft/src/test/java/org/opendaylight/controller/cluster/raft/AbstractReplicatedLogImplTest.java new file mode 100644 index 0000000000..913665861d --- /dev/null +++ b/opendaylight/md-sal/sal-akka-raft/src/test/java/org/opendaylight/controller/cluster/raft/AbstractReplicatedLogImplTest.java @@ -0,0 +1,171 @@ +/* + * 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.cluster.raft; + +import junit.framework.Assert; +import org.junit.After; +import org.junit.Before; +import org.junit.Test; + +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertNull; +import static org.junit.Assert.assertTrue; +import static org.opendaylight.controller.cluster.raft.MockRaftActorContext.MockPayload; +import static org.opendaylight.controller.cluster.raft.MockRaftActorContext.MockReplicatedLogEntry; +/** +* +*/ +public class AbstractReplicatedLogImplTest { + + private MockAbstractReplicatedLogImpl replicatedLogImpl; + + @Before + public void setUp() { + replicatedLogImpl = new MockAbstractReplicatedLogImpl(); + // create a set of initial entries in the in-memory log + replicatedLogImpl.append(new MockReplicatedLogEntry(1, 0, new MockPayload("A"))); + replicatedLogImpl.append(new MockReplicatedLogEntry(1, 1, new MockPayload("B"))); + replicatedLogImpl.append(new MockReplicatedLogEntry(1, 2, new MockPayload("C"))); + replicatedLogImpl.append(new MockReplicatedLogEntry(2, 3, new MockPayload("D"))); + + } + + @After + public void tearDown() { + replicatedLogImpl.journal.clear(); + replicatedLogImpl.setSnapshotIndex(-1); + replicatedLogImpl.setSnapshotTerm(-1); + replicatedLogImpl = null; + } + + @Test + public void testIndexOperations() { + + // check if the values returned are correct, with snapshotIndex = -1 + assertEquals("B", replicatedLogImpl.get(1).getData().toString()); + assertEquals("D", replicatedLogImpl.last().getData().toString()); + assertEquals(3, replicatedLogImpl.lastIndex()); + assertEquals(2, replicatedLogImpl.lastTerm()); + assertEquals(2, replicatedLogImpl.getFrom(2).size()); + assertEquals(4, replicatedLogImpl.size()); + assertTrue(replicatedLogImpl.isPresent(2)); + assertFalse(replicatedLogImpl.isPresent(4)); + assertFalse(replicatedLogImpl.isInSnapshot(2)); + + // now create a snapshot of 3 entries, with 1 unapplied entry left in the log + // It removes the entries which have made it to snapshot + // and updates the snapshot index and term + Map state = takeSnapshot(3); + + // check the values after the snapshot. + // each index value passed in the test is the logical index (log entry index) + // which gets mapped to the list's physical index + assertEquals("D", replicatedLogImpl.get(3).getData().toString()); + assertEquals("D", replicatedLogImpl.last().getData().toString()); + assertNull(replicatedLogImpl.get(1)); + assertEquals(3, replicatedLogImpl.lastIndex()); + assertEquals(2, replicatedLogImpl.lastTerm()); + assertEquals(0, replicatedLogImpl.getFrom(2).size()); + assertEquals(1, replicatedLogImpl.size()); + assertFalse(replicatedLogImpl.isPresent(2)); + assertTrue(replicatedLogImpl.isPresent(3)); + assertFalse(replicatedLogImpl.isPresent(4)); + assertTrue(replicatedLogImpl.isInSnapshot(2)); + + // append few more entries + replicatedLogImpl.append(new MockReplicatedLogEntry(2, 4, new MockPayload("E"))); + replicatedLogImpl.append(new MockReplicatedLogEntry(2, 5, new MockPayload("F"))); + replicatedLogImpl.append(new MockReplicatedLogEntry(3, 6, new MockPayload("G"))); + replicatedLogImpl.append(new MockReplicatedLogEntry(3, 7, new MockPayload("H"))); + + // check their values as well + assertEquals(5, replicatedLogImpl.size()); + assertEquals("D", replicatedLogImpl.get(3).getData().toString()); + assertEquals("E", replicatedLogImpl.get(4).getData().toString()); + assertEquals("H", replicatedLogImpl.last().getData().toString()); + assertEquals(3, replicatedLogImpl.lastTerm()); + assertEquals(7, replicatedLogImpl.lastIndex()); + assertTrue(replicatedLogImpl.isPresent(7)); + assertFalse(replicatedLogImpl.isInSnapshot(7)); + assertEquals(1, replicatedLogImpl.getFrom(7).size()); + assertEquals(2, replicatedLogImpl.getFrom(6).size()); + + // take a second snapshot with 5 entries with 0 unapplied entries left in the log + state = takeSnapshot(5); + + assertEquals(0, replicatedLogImpl.size()); + assertNull(replicatedLogImpl.last()); + assertNull(replicatedLogImpl.get(7)); + assertNull(replicatedLogImpl.get(1)); + assertFalse(replicatedLogImpl.isPresent(7)); + assertTrue(replicatedLogImpl.isInSnapshot(7)); + assertEquals(0, replicatedLogImpl.getFrom(7).size()); + assertEquals(0, replicatedLogImpl.getFrom(6).size()); + + } + + @Test + public void testGetFromWithMax(){ + List from = replicatedLogImpl.getFrom(0, 1); + Assert.assertEquals(1, from.size()); + Assert.assertEquals(1, from.get(0).getTerm()); + + from = replicatedLogImpl.getFrom(0, 20); + Assert.assertEquals(4, from.size()); + Assert.assertEquals(2, from.get(3).getTerm()); + + from = replicatedLogImpl.getFrom(1, 2); + Assert.assertEquals(2, from.size()); + Assert.assertEquals(1, from.get(1).getTerm()); + + } + + // create a snapshot for test + public Map takeSnapshot(int numEntries) { + Map map = new HashMap(numEntries); + List entries = replicatedLogImpl.getEntriesTill(numEntries); + for (ReplicatedLogEntry entry : entries) { + map.put(entry.getIndex(), entry.getData().toString()); + } + + int term = (int) replicatedLogImpl.lastTerm(); + int lastIndex = (int) entries.get(entries.size() - 1).getIndex(); + entries.clear(); + replicatedLogImpl.setSnapshotTerm(term); + replicatedLogImpl.setSnapshotIndex(lastIndex); + + return map; + + } + class MockAbstractReplicatedLogImpl extends AbstractReplicatedLogImpl { + @Override + public void appendAndPersist(ReplicatedLogEntry replicatedLogEntry) { + } + + @Override + public void removeFromAndPersist(long index) { + } + + public void setSnapshotIndex(long snapshotIndex) { + this.snapshotIndex = snapshotIndex; + } + + public void setSnapshotTerm(long snapshotTerm) { + this.snapshotTerm = snapshotTerm; + } + + public List getEntriesTill(int index) { + return journal.subList(0, index); + } + } +} diff --git a/opendaylight/md-sal/sal-akka-raft/src/test/java/org/opendaylight/controller/cluster/raft/MockRaftActorContext.java b/opendaylight/md-sal/sal-akka-raft/src/test/java/org/opendaylight/controller/cluster/raft/MockRaftActorContext.java index 2e200cba27..70671a6a21 100644 --- a/opendaylight/md-sal/sal-akka-raft/src/test/java/org/opendaylight/controller/cluster/raft/MockRaftActorContext.java +++ b/opendaylight/md-sal/sal-akka-raft/src/test/java/org/opendaylight/controller/cluster/raft/MockRaftActorContext.java @@ -177,7 +177,10 @@ public class MockRaftActorContext implements RaftActorContext { this.peerAddresses = peerAddresses; } - + @Override + public ConfigParams getConfigParams() { + return new DefaultConfigParamsImpl(); + } public static class SimpleReplicatedLog implements ReplicatedLog { private final List log = new ArrayList<>(); @@ -245,6 +248,23 @@ public class MockRaftActorContext implements RaftActorContext { return entries; } + @Override public List getFrom(long index, int max) { + if(index >= log.size() || index < 0){ + return Collections.EMPTY_LIST; + } + List entries = new ArrayList<>(); + int maxIndex = (int) index + max; + if(maxIndex > log.size()){ + maxIndex = log.size(); + } + + for(int i=(int) index ; i < maxIndex ; i++) { + entries.add(get(i)); + } + return entries; + + } + @Override public long size() { return log.size(); } diff --git a/opendaylight/md-sal/sal-akka-raft/src/test/java/org/opendaylight/controller/cluster/raft/behaviors/CandidateTest.java b/opendaylight/md-sal/sal-akka-raft/src/test/java/org/opendaylight/controller/cluster/raft/behaviors/CandidateTest.java index c763683705..d478b17555 100644 --- a/opendaylight/md-sal/sal-akka-raft/src/test/java/org/opendaylight/controller/cluster/raft/behaviors/CandidateTest.java +++ b/opendaylight/md-sal/sal-akka-raft/src/test/java/org/opendaylight/controller/cluster/raft/behaviors/CandidateTest.java @@ -6,6 +6,7 @@ import akka.testkit.JavaTestKit; import junit.framework.Assert; import org.junit.Before; import org.junit.Test; +import org.opendaylight.controller.cluster.raft.DefaultConfigParamsImpl; import org.opendaylight.controller.cluster.raft.MockRaftActorContext; import org.opendaylight.controller.cluster.raft.RaftActorContext; import org.opendaylight.controller.cluster.raft.RaftState; @@ -80,12 +81,12 @@ public class CandidateTest extends AbstractRaftActorBehaviorTest { public void testThatAnElectionTimeoutIsTriggered(){ new JavaTestKit(getSystem()) {{ - new Within(duration("1 seconds")) { + new Within(DefaultConfigParamsImpl.HEART_BEAT_INTERVAL.$times(6)) { protected void run() { Candidate candidate = new Candidate(createActorContext(getTestActor())); - final Boolean out = new ExpectMsg(duration("1 seconds"), "ElectionTimeout") { + final Boolean out = new ExpectMsg(DefaultConfigParamsImpl.HEART_BEAT_INTERVAL.$times(6), "ElectionTimeout") { // do not put code outside this method, will run afterwards protected Boolean match(Object in) { if (in instanceof ElectionTimeout) { diff --git a/opendaylight/md-sal/sal-akka-raft/src/test/java/org/opendaylight/controller/cluster/raft/behaviors/FollowerTest.java b/opendaylight/md-sal/sal-akka-raft/src/test/java/org/opendaylight/controller/cluster/raft/behaviors/FollowerTest.java index c015d950c4..c5a81aa1c9 100644 --- a/opendaylight/md-sal/sal-akka-raft/src/test/java/org/opendaylight/controller/cluster/raft/behaviors/FollowerTest.java +++ b/opendaylight/md-sal/sal-akka-raft/src/test/java/org/opendaylight/controller/cluster/raft/behaviors/FollowerTest.java @@ -5,6 +5,7 @@ import akka.actor.Props; import akka.testkit.JavaTestKit; import junit.framework.Assert; import org.junit.Test; +import org.opendaylight.controller.cluster.raft.DefaultConfigParamsImpl; import org.opendaylight.controller.cluster.raft.MockRaftActorContext; import org.opendaylight.controller.cluster.raft.RaftActorContext; import org.opendaylight.controller.cluster.raft.RaftState; @@ -41,12 +42,12 @@ public class FollowerTest extends AbstractRaftActorBehaviorTest { public void testThatAnElectionTimeoutIsTriggered(){ new JavaTestKit(getSystem()) {{ - new Within(duration("1 seconds")) { + new Within(DefaultConfigParamsImpl.HEART_BEAT_INTERVAL.$times(6)) { protected void run() { Follower follower = new Follower(createActorContext(getTestActor())); - final Boolean out = new ExpectMsg(duration("1 seconds"), "ElectionTimeout") { + final Boolean out = new ExpectMsg(DefaultConfigParamsImpl.HEART_BEAT_INTERVAL.$times(6), "ElectionTimeout") { // do not put code outside this method, will run afterwards protected Boolean match(Object in) { if (in instanceof ElectionTimeout) { diff --git a/opendaylight/md-sal/sal-binding-api/src/main/java/org/opendaylight/controller/md/sal/binding/api/ReadTransaction.java b/opendaylight/md-sal/sal-binding-api/src/main/java/org/opendaylight/controller/md/sal/binding/api/ReadTransaction.java index cc85d4337b..b0c93734e0 100644 --- a/opendaylight/md-sal/sal-binding-api/src/main/java/org/opendaylight/controller/md/sal/binding/api/ReadTransaction.java +++ b/opendaylight/md-sal/sal-binding-api/src/main/java/org/opendaylight/controller/md/sal/binding/api/ReadTransaction.java @@ -9,11 +9,12 @@ package org.opendaylight.controller.md.sal.binding.api; import org.opendaylight.controller.md.sal.common.api.data.AsyncReadTransaction; import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType; +import org.opendaylight.controller.md.sal.common.api.data.ReadFailedException; import org.opendaylight.yangtools.yang.binding.DataObject; import org.opendaylight.yangtools.yang.binding.InstanceIdentifier; import com.google.common.base.Optional; -import com.google.common.util.concurrent.ListenableFuture; +import com.google.common.util.concurrent.CheckedFuture; /** * A transaction that provides read access to a logical data store. @@ -33,14 +34,17 @@ public interface ReadTransaction extends AsyncReadTransaction - *

  • If data at supplied path exists the - * {@link ListeblaFuture#get()} returns Optional object containing - * data once read is done. - *
  • If data at supplied path does not exists the - * {@link ListenbleFuture#get()} returns {@link Optional#absent()}. + *
  • If the data at the supplied path exists, the Future returns an Optional object + * containing the data.
  • + *
  • If the data at the supplied path does not exist, the Future returns + * Optional#absent().
  • + *
  • If the read of the data fails, the Future will fail with a + * {@link ReadFailedException} or an exception derived from ReadFailedException.
  • * */ - ListenableFuture> read(LogicalDatastoreType store, InstanceIdentifier path); + CheckedFuture,ReadFailedException> read( + LogicalDatastoreType store, InstanceIdentifier path); } diff --git a/opendaylight/md-sal/sal-binding-broker/src/main/java/org/opendaylight/controller/config/yang/md/sal/binding/impl/RuntimeMappingModule.java b/opendaylight/md-sal/sal-binding-broker/src/main/java/org/opendaylight/controller/config/yang/md/sal/binding/impl/RuntimeMappingModule.java index 823a4d9f32..b0c2d742e2 100644 --- a/opendaylight/md-sal/sal-binding-broker/src/main/java/org/opendaylight/controller/config/yang/md/sal/binding/impl/RuntimeMappingModule.java +++ b/opendaylight/md-sal/sal-binding-broker/src/main/java/org/opendaylight/controller/config/yang/md/sal/binding/impl/RuntimeMappingModule.java @@ -23,7 +23,7 @@ import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier; import org.opendaylight.yangtools.yang.data.impl.codec.BindingIndependentMappingService; import org.opendaylight.yangtools.yang.data.impl.codec.CodecRegistry; import org.opendaylight.yangtools.yang.data.impl.codec.DeserializationException; -import org.opendaylight.yangtools.yang.model.api.SchemaServiceListener; +import org.opendaylight.yangtools.yang.model.api.SchemaContextListener; import org.osgi.framework.BundleContext; import org.osgi.framework.ServiceReference; import org.slf4j.Logger; @@ -74,7 +74,7 @@ public final class RuntimeMappingModule extends } final RuntimeGeneratedMappingServiceImpl service = new RuntimeGeneratedMappingServiceImpl(SingletonHolder.CLASS_POOL); - bundleContext.registerService(SchemaServiceListener.class, service, new Hashtable()); + bundleContext.registerService(SchemaContextListener.class, service, new Hashtable()); return service; } diff --git a/opendaylight/md-sal/sal-binding-broker/src/main/java/org/opendaylight/controller/md/sal/binding/impl/AbstractForwardedDataBroker.java b/opendaylight/md-sal/sal-binding-broker/src/main/java/org/opendaylight/controller/md/sal/binding/impl/AbstractForwardedDataBroker.java index 15e4a466cf..e632e6336a 100644 --- a/opendaylight/md-sal/sal-binding-broker/src/main/java/org/opendaylight/controller/md/sal/binding/impl/AbstractForwardedDataBroker.java +++ b/opendaylight/md-sal/sal-binding-broker/src/main/java/org/opendaylight/controller/md/sal/binding/impl/AbstractForwardedDataBroker.java @@ -41,7 +41,6 @@ import org.opendaylight.yangtools.yang.data.impl.codec.BindingIndependentMapping import org.opendaylight.yangtools.yang.data.impl.codec.DeserializationException; import org.opendaylight.yangtools.yang.model.api.SchemaContext; import org.opendaylight.yangtools.yang.model.api.SchemaContextListener; -import org.opendaylight.yangtools.yang.model.api.SchemaServiceListener; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -58,14 +57,14 @@ public abstract class AbstractForwardedDataBroker implements Delegator schemaListenerRegistration; + private final ListenerRegistration schemaListenerRegistration; protected AbstractForwardedDataBroker(final DOMDataBroker domDataBroker, final BindingIndependentMappingService mappingService,final SchemaService schemaService) { this.domDataBroker = domDataBroker; this.mappingService = mappingService; this.codec = new BindingToNormalizedNodeCodec(mappingService); - this.schemaListenerRegistration = schemaService.registerSchemaServiceListener(this); + this.schemaListenerRegistration = schemaService.registerSchemaContextListener(this); } protected BindingToNormalizedNodeCodec getCodec() { @@ -98,6 +97,7 @@ public abstract class AbstractForwardedDataBroker implements Delegator, DataObject> toBinding( + InstanceIdentifier path, final Map> normalized) { Map, DataObject> newMap = new HashMap<>(); @@ -108,6 +108,11 @@ public abstract class AbstractForwardedDataBroker implements Delegator, DataObject> binding = potential.get(); newMap.put(binding.getKey(), binding.getValue()); + } else if (entry.getKey().getLastPathArgument() instanceof YangInstanceIdentifier.AugmentationIdentifier) { + DataObject bindingDataObject = getCodec().toBinding(path, entry.getValue()); + if (bindingDataObject != null) { + newMap.put(path, bindingDataObject); + } } } catch (DeserializationException e) { LOG.warn("Failed to transform {}, omitting it", entry, e); @@ -149,7 +154,7 @@ public abstract class AbstractForwardedDataBroker implements Delegator> toBinding( + protected Set> toBinding(InstanceIdentifier path, final Set normalized) { Set> hashSet = new HashSet<>(); for (YangInstanceIdentifier normalizedPath : normalized) { @@ -158,6 +163,8 @@ public abstract class AbstractForwardedDataBroker implements Delegator binding = potential.get(); hashSet.add(binding); + } else if (normalizedPath.getLastPathArgument() instanceof YangInstanceIdentifier.AugmentationIdentifier) { + hashSet.add(path); } } catch (DeserializationException e) { LOG.warn("Failed to transform {}, omitting it", normalizedPath, e); @@ -220,7 +227,7 @@ public abstract class AbstractForwardedDataBroker implements Delegator, DataObject> getCreatedData() { if (createdCache == null) { - createdCache = Collections.unmodifiableMap(toBinding(domEvent.getCreatedData())); + createdCache = Collections.unmodifiableMap(toBinding(path, domEvent.getCreatedData())); } return createdCache; } @@ -228,7 +235,7 @@ public abstract class AbstractForwardedDataBroker implements Delegator, DataObject> getUpdatedData() { if (updatedCache == null) { - updatedCache = Collections.unmodifiableMap(toBinding(domEvent.getUpdatedData())); + updatedCache = Collections.unmodifiableMap(toBinding(path, domEvent.getUpdatedData())); } return updatedCache; @@ -237,7 +244,7 @@ public abstract class AbstractForwardedDataBroker implements Delegator> getRemovedPaths() { if (removedCache == null) { - removedCache = Collections.unmodifiableSet(toBinding(domEvent.getRemovedPaths())); + removedCache = Collections.unmodifiableSet(toBinding(path, domEvent.getRemovedPaths())); } return removedCache; } @@ -245,7 +252,7 @@ public abstract class AbstractForwardedDataBroker implements Delegator, DataObject> getOriginalData() { if (originalCache == null) { - originalCache = Collections.unmodifiableMap(toBinding(domEvent.getOriginalData())); + originalCache = Collections.unmodifiableMap(toBinding(path, domEvent.getOriginalData())); } return originalCache; diff --git a/opendaylight/md-sal/sal-binding-broker/src/main/java/org/opendaylight/controller/md/sal/binding/impl/AbstractForwardedTransaction.java b/opendaylight/md-sal/sal-binding-broker/src/main/java/org/opendaylight/controller/md/sal/binding/impl/AbstractForwardedTransaction.java index e52fcdce23..96a3f1cc3b 100644 --- a/opendaylight/md-sal/sal-binding-broker/src/main/java/org/opendaylight/controller/md/sal/binding/impl/AbstractForwardedTransaction.java +++ b/opendaylight/md-sal/sal-binding-broker/src/main/java/org/opendaylight/controller/md/sal/binding/impl/AbstractForwardedTransaction.java @@ -9,17 +9,19 @@ package org.opendaylight.controller.md.sal.binding.impl; import org.opendaylight.controller.md.sal.common.api.data.AsyncTransaction; import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType; +import org.opendaylight.controller.md.sal.common.api.data.ReadFailedException; import org.opendaylight.controller.md.sal.dom.api.DOMDataReadTransaction; import org.opendaylight.yangtools.concepts.Delegator; import org.opendaylight.yangtools.concepts.Identifiable; +import org.opendaylight.yangtools.util.concurrent.MappingCheckedFuture; import org.opendaylight.yangtools.yang.binding.DataObject; import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier; import org.opendaylight.yangtools.yang.data.api.schema.NormalizedNode; 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.ListenableFuture; abstract class AbstractForwardedTransaction>> @@ -54,8 +56,13 @@ abstract class AbstractForwardedTransaction ListenableFuture> doRead(final DOMDataReadTransaction readTx, - final LogicalDatastoreType store, final org.opendaylight.yangtools.yang.binding.InstanceIdentifier path) { - return Futures.transform(readTx.read(store, codec.toNormalized(path)), codec.deserializeFunction(path)); + protected final CheckedFuture,ReadFailedException> doRead( + final DOMDataReadTransaction readTx, final LogicalDatastoreType store, + final org.opendaylight.yangtools.yang.binding.InstanceIdentifier path) { + + return MappingCheckedFuture.create( + Futures.transform(readTx.read(store, codec.toNormalized(path)), + codec.deserializeFunction(path)), + ReadFailedException.MAPPER); } } diff --git a/opendaylight/md-sal/sal-binding-broker/src/main/java/org/opendaylight/controller/md/sal/binding/impl/BindingDataReadTransactionImpl.java b/opendaylight/md-sal/sal-binding-broker/src/main/java/org/opendaylight/controller/md/sal/binding/impl/BindingDataReadTransactionImpl.java index bb942047f2..fd0945f1a6 100644 --- a/opendaylight/md-sal/sal-binding-broker/src/main/java/org/opendaylight/controller/md/sal/binding/impl/BindingDataReadTransactionImpl.java +++ b/opendaylight/md-sal/sal-binding-broker/src/main/java/org/opendaylight/controller/md/sal/binding/impl/BindingDataReadTransactionImpl.java @@ -9,12 +9,13 @@ package org.opendaylight.controller.md.sal.binding.impl; import org.opendaylight.controller.md.sal.binding.api.ReadOnlyTransaction; import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType; +import org.opendaylight.controller.md.sal.common.api.data.ReadFailedException; import org.opendaylight.controller.md.sal.dom.api.DOMDataReadOnlyTransaction; import org.opendaylight.yangtools.yang.binding.DataObject; import org.opendaylight.yangtools.yang.binding.InstanceIdentifier; import com.google.common.base.Optional; -import com.google.common.util.concurrent.ListenableFuture; +import com.google.common.util.concurrent.CheckedFuture; class BindingDataReadTransactionImpl extends AbstractForwardedTransaction implements ReadOnlyTransaction { @@ -25,8 +26,8 @@ class BindingDataReadTransactionImpl extends AbstractForwardedTransaction ListenableFuture> read(final LogicalDatastoreType store, - final InstanceIdentifier path) { + public CheckedFuture,ReadFailedException> read( + final LogicalDatastoreType store, final InstanceIdentifier path) { return doRead(getDelegate(),store, path); } diff --git a/opendaylight/md-sal/sal-binding-broker/src/main/java/org/opendaylight/controller/md/sal/binding/impl/BindingDataReadWriteTransactionImpl.java b/opendaylight/md-sal/sal-binding-broker/src/main/java/org/opendaylight/controller/md/sal/binding/impl/BindingDataReadWriteTransactionImpl.java index c8b9d9347a..a1da029c24 100644 --- a/opendaylight/md-sal/sal-binding-broker/src/main/java/org/opendaylight/controller/md/sal/binding/impl/BindingDataReadWriteTransactionImpl.java +++ b/opendaylight/md-sal/sal-binding-broker/src/main/java/org/opendaylight/controller/md/sal/binding/impl/BindingDataReadWriteTransactionImpl.java @@ -9,12 +9,13 @@ package org.opendaylight.controller.md.sal.binding.impl; import org.opendaylight.controller.md.sal.binding.api.ReadWriteTransaction; import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType; +import org.opendaylight.controller.md.sal.common.api.data.ReadFailedException; import org.opendaylight.controller.md.sal.dom.api.DOMDataReadWriteTransaction; import org.opendaylight.yangtools.yang.binding.DataObject; import org.opendaylight.yangtools.yang.binding.InstanceIdentifier; import com.google.common.base.Optional; -import com.google.common.util.concurrent.ListenableFuture; +import com.google.common.util.concurrent.CheckedFuture; class BindingDataReadWriteTransactionImpl extends BindingDataWriteTransactionImpl implements ReadWriteTransaction { @@ -25,8 +26,8 @@ class BindingDataReadWriteTransactionImpl extends } @Override - public ListenableFuture> read(final LogicalDatastoreType store, - final InstanceIdentifier path) { + public CheckedFuture,ReadFailedException> read( + final LogicalDatastoreType store, final InstanceIdentifier path) { return doRead(getDelegate(), store, path); } } \ No newline at end of file diff --git a/opendaylight/md-sal/sal-binding-broker/src/main/java/org/opendaylight/controller/sal/binding/impl/MountPointManagerImpl.java b/opendaylight/md-sal/sal-binding-broker/src/main/java/org/opendaylight/controller/sal/binding/impl/MountPointManagerImpl.java index df09f78620..05651bfabe 100644 --- a/opendaylight/md-sal/sal-binding-broker/src/main/java/org/opendaylight/controller/sal/binding/impl/MountPointManagerImpl.java +++ b/opendaylight/md-sal/sal-binding-broker/src/main/java/org/opendaylight/controller/sal/binding/impl/MountPointManagerImpl.java @@ -9,6 +9,7 @@ package org.opendaylight.controller.sal.binding.impl; import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.ConcurrentMap; +import java.util.concurrent.Executors; import org.opendaylight.controller.md.sal.binding.util.AbstractBindingSalProviderInstance; import org.opendaylight.controller.sal.binding.api.mount.MountProviderInstance; @@ -20,6 +21,7 @@ import org.slf4j.Logger; import org.slf4j.LoggerFactory; import com.google.common.util.concurrent.ListeningExecutorService; +import com.google.common.util.concurrent.MoreExecutors; public class MountPointManagerImpl implements MountProviderService { @@ -82,7 +84,7 @@ public class MountPointManagerImpl implements MountProviderService { RpcProviderRegistryImpl rpcRegistry = new RpcProviderRegistryImpl("mount"); NotificationBrokerImpl notificationBroker = new NotificationBrokerImpl(getNotificationExecutor()); DataBrokerImpl dataBroker = new DataBrokerImpl(); - dataBroker.setExecutor(getDataCommitExecutor()); + dataBroker.setExecutor(MoreExecutors.listeningDecorator(Executors.newSingleThreadExecutor())); BindingMountPointImpl mountInstance = new BindingMountPointImpl(path, rpcRegistry, notificationBroker, dataBroker); mountPoints.putIfAbsent(path, mountInstance); diff --git a/opendaylight/md-sal/sal-binding-broker/src/test/java/org/opendaylight/controller/md/sal/binding/impl/test/Bug1333DataChangeListenerTest.java b/opendaylight/md-sal/sal-binding-broker/src/test/java/org/opendaylight/controller/md/sal/binding/impl/test/Bug1333DataChangeListenerTest.java new file mode 100644 index 0000000000..60d56db581 --- /dev/null +++ b/opendaylight/md-sal/sal-binding-broker/src/test/java/org/opendaylight/controller/md/sal/binding/impl/test/Bug1333DataChangeListenerTest.java @@ -0,0 +1,145 @@ +/* + * Copyright (c) 2014 Cisco Systems, Inc. and others. All rights reserved. + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License v1.0 which accompanies this distribution, + * and is available at http://www.eclipse.org/legal/epl-v10.html + */ +package org.opendaylight.controller.md.sal.binding.impl.test; + +import static org.opendaylight.controller.md.sal.binding.test.AssertCollections.assertContains; +import static org.opendaylight.controller.md.sal.binding.test.AssertCollections.assertEmpty; +import static org.opendaylight.controller.md.sal.binding.test.AssertCollections.assertNotContains; +import static org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType.CONFIGURATION; +import static org.opendaylight.controller.md.sal.test.model.util.ListsBindingUtils.TOP_FOO_KEY; +import static org.opendaylight.controller.md.sal.test.model.util.ListsBindingUtils.USES_ONE_KEY; +import static org.opendaylight.controller.md.sal.test.model.util.ListsBindingUtils.USES_TWO_KEY; +import static org.opendaylight.controller.md.sal.test.model.util.ListsBindingUtils.complexUsesAugment; +import static org.opendaylight.controller.md.sal.test.model.util.ListsBindingUtils.path; +import static org.opendaylight.controller.md.sal.test.model.util.ListsBindingUtils.top; +import static org.opendaylight.controller.md.sal.test.model.util.ListsBindingUtils.topLevelList; + +import org.junit.Test; +import org.opendaylight.controller.md.sal.binding.api.ReadWriteTransaction; +import org.opendaylight.controller.md.sal.binding.test.AbstractDataChangeListenerTest; +import org.opendaylight.controller.md.sal.common.api.data.AsyncDataBroker.DataChangeScope; +import org.opendaylight.controller.md.sal.common.api.data.AsyncDataChangeEvent; +import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.controller.md.sal.test.augment.rev140709.TreeComplexUsesAugment; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.controller.md.sal.test.list.rev140701.Top; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.controller.md.sal.test.list.rev140701.two.level.list.TopLevelList; +import org.opendaylight.yangtools.yang.binding.DataObject; +import org.opendaylight.yangtools.yang.binding.InstanceIdentifier; + +/** + * + * This testsuite tries to replicate bug 1333 and tests regresion of it + * using test-model with similar construction as one reported. + * + * + * See https://bugs.opendaylight.org/show_bug.cgi?id=1333 for Bug Description + * + */ +public class Bug1333DataChangeListenerTest extends AbstractDataChangeListenerTest{ + + private static final InstanceIdentifier TOP_PATH = InstanceIdentifier.create(Top.class); + + private static final InstanceIdentifier AUGMENT_WILDCARD = TOP_PATH.child(TopLevelList.class).augmentation( + TreeComplexUsesAugment.class); + + public void writeTopWithListItem(final LogicalDatastoreType store) { + ReadWriteTransaction tx = getDataBroker().newReadWriteTransaction(); + Top topItem = top(topLevelList(TOP_FOO_KEY, complexUsesAugment(USES_ONE_KEY, USES_TWO_KEY))); + tx.put(store, TOP_PATH, topItem); + assertCommit(tx.submit()); + } + + public void deleteItem(final LogicalDatastoreType store, final InstanceIdentifier path) { + ReadWriteTransaction tx = getDataBroker().newReadWriteTransaction(); + tx.delete(store, path); + assertCommit(tx.submit()); + } + + @Test + public void writeTopWithListItemAugmentedListenTopSubtree() { + TestListener listener = createListener(CONFIGURATION,TOP_PATH, DataChangeScope.SUBTREE); + listener.startCapture(); + + writeTopWithListItem(CONFIGURATION); + + AsyncDataChangeEvent, DataObject> event = listener.event(); + + assertContains(event.getCreatedData(), TOP_PATH); + assertContains(event.getCreatedData(), path(TOP_FOO_KEY)); + assertContains(event.getCreatedData(), path(TOP_FOO_KEY, TreeComplexUsesAugment.class)); + assertContains(event.getCreatedData(), path(TOP_FOO_KEY, USES_ONE_KEY)); + assertContains(event.getCreatedData(), path(TOP_FOO_KEY, USES_TWO_KEY)); + + assertEmpty(event.getUpdatedData()); + assertEmpty(event.getRemovedPaths()); + } + + @Test + public void writeTopWithListItemAugmentedListenAugmentSubtreeWildcarded() { + TestListener listener = createListener(CONFIGURATION,AUGMENT_WILDCARD, DataChangeScope.SUBTREE); + listener.startCapture(); + writeTopWithListItem(CONFIGURATION); + + AsyncDataChangeEvent, DataObject> event = listener.event(); + + /* + * Event should not contain parent nodes + */ + assertNotContains(event.getCreatedData(), TOP_PATH, path(TOP_FOO_KEY)); + + assertContains(event.getCreatedData(), path(TOP_FOO_KEY, TreeComplexUsesAugment.class)); + assertContains(event.getCreatedData(), path(TOP_FOO_KEY, USES_ONE_KEY)); + assertContains(event.getCreatedData(), path(TOP_FOO_KEY, USES_TWO_KEY)); + + assertEmpty(event.getUpdatedData()); + assertEmpty(event.getRemovedPaths()); + } + + @Test + public void deleteAugmentChildListenTopSubtree() { + writeTopWithListItem(CONFIGURATION); + TestListener listener = createListener(CONFIGURATION, TOP_PATH, DataChangeScope.SUBTREE); + InstanceIdentifier deletePath = path(TOP_FOO_KEY,USES_ONE_KEY); + deleteItem(CONFIGURATION,deletePath); + + AsyncDataChangeEvent, DataObject> event = listener.event(); + + + assertEmpty(event.getCreatedData()); + + assertContains(event.getRemovedPaths(), deletePath); + + assertContains(event.getUpdatedData(), TOP_PATH); + assertContains(event.getUpdatedData(), path(TOP_FOO_KEY)); + assertContains(event.getUpdatedData(), path(TOP_FOO_KEY, TreeComplexUsesAugment.class)); + + assertNotContains(event.getCreatedData(), path(TOP_FOO_KEY, USES_TWO_KEY)); + } + + @Test + public void deleteAugmentChildListenAugmentSubtreeWildcarded() { + writeTopWithListItem(CONFIGURATION); + + TestListener listener = createListener(CONFIGURATION, AUGMENT_WILDCARD, DataChangeScope.SUBTREE); + InstanceIdentifier deletePath = path(TOP_FOO_KEY,USES_ONE_KEY); + deleteItem(CONFIGURATION,deletePath); + AsyncDataChangeEvent, DataObject> event = listener.event(); + + assertEmpty(event.getCreatedData()); + + assertContains(event.getUpdatedData(), path(TOP_FOO_KEY, TreeComplexUsesAugment.class)); + + /* + * Event should not contain parent nodes + */ + assertNotContains(event.getUpdatedData(), TOP_PATH, path(TOP_FOO_KEY)); + + assertContains(event.getRemovedPaths(), deletePath); + } + +} diff --git a/opendaylight/md-sal/sal-binding-broker/src/test/java/org/opendaylight/controller/md/sal/binding/impl/test/Bug1418AugmentationTest.java b/opendaylight/md-sal/sal-binding-broker/src/test/java/org/opendaylight/controller/md/sal/binding/impl/test/Bug1418AugmentationTest.java new file mode 100644 index 0000000000..6b5c825b83 --- /dev/null +++ b/opendaylight/md-sal/sal-binding-broker/src/test/java/org/opendaylight/controller/md/sal/binding/impl/test/Bug1418AugmentationTest.java @@ -0,0 +1,135 @@ +package org.opendaylight.controller.md.sal.binding.impl.test; + +import org.junit.Test; +import org.opendaylight.controller.md.sal.binding.api.WriteTransaction; +import org.opendaylight.controller.md.sal.binding.test.AbstractDataChangeListenerTest; +import org.opendaylight.controller.md.sal.common.api.data.AsyncDataBroker; +import org.opendaylight.controller.md.sal.common.api.data.AsyncDataChangeEvent; +import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.controller.md.sal.test.augment.rev140709.TreeComplexUsesAugment; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.controller.md.sal.test.augment.rev140709.TreeLeafOnlyUsesAugment; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.controller.md.sal.test.augment.rev140709.complex.from.grouping.ListViaUses; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.controller.md.sal.test.augment.rev140709.complex.from.grouping.ListViaUsesKey; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.controller.md.sal.test.list.rev140701.Top; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.controller.md.sal.test.list.rev140701.two.level.list.TopLevelList; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.controller.md.sal.test.list.rev140701.two.level.list.TopLevelListKey; +import org.opendaylight.yangtools.yang.binding.DataObject; +import org.opendaylight.yangtools.yang.binding.InstanceIdentifier; + +import static org.junit.Assert.assertTrue; +import static org.opendaylight.controller.md.sal.binding.test.AssertCollections.assertContains; +import static org.opendaylight.controller.md.sal.binding.test.AssertCollections.assertEmpty; +import static org.opendaylight.controller.md.sal.test.model.util.ListsBindingUtils.top; +import static org.opendaylight.controller.md.sal.test.model.util.ListsBindingUtils.TOP_FOO_KEY; +import static org.opendaylight.controller.md.sal.test.model.util.ListsBindingUtils.topLevelList; +import static org.opendaylight.controller.md.sal.test.model.util.ListsBindingUtils.leafOnlyUsesAugment; +import static org.opendaylight.controller.md.sal.test.model.util.ListsBindingUtils.complexUsesAugment; + +public class Bug1418AugmentationTest extends AbstractDataChangeListenerTest{ + private static final InstanceIdentifier TOP = InstanceIdentifier.create(Top.class); + private static final InstanceIdentifier TOP_FOO = TOP.child(TopLevelList.class, TOP_FOO_KEY); + private static final InstanceIdentifier SIMPLE_AUGMENT = + TOP.child(TopLevelList.class, TOP_FOO_KEY).augmentation(TreeLeafOnlyUsesAugment.class); + private static final InstanceIdentifier COMPLEX_AUGMENT = + TOP.child(TopLevelList.class, TOP_FOO_KEY).augmentation(TreeComplexUsesAugment.class); + private static final ListViaUsesKey LIST_VIA_USES_KEY = + new ListViaUsesKey("list key"); + private static final ListViaUsesKey LIST_VIA_USES_KEY_MOD = + new ListViaUsesKey("list key modified"); + + @Test + public void leafOnlyAugmentationCreatedTest() { + TestListener listener = createListener(LogicalDatastoreType.CONFIGURATION, SIMPLE_AUGMENT, + AsyncDataBroker.DataChangeScope.SUBTREE); + WriteTransaction writeTx = getDataBroker().newWriteOnlyTransaction(); + writeTx.put(LogicalDatastoreType.CONFIGURATION, TOP, top()); + writeTx.put(LogicalDatastoreType.CONFIGURATION, TOP_FOO, topLevelList(new TopLevelListKey(TOP_FOO_KEY))); + writeTx.put(LogicalDatastoreType.CONFIGURATION, SIMPLE_AUGMENT, leafOnlyUsesAugment("test leaf")); + assertCommit(writeTx.submit()); + assertTrue(listener.hasEvent()); + AsyncDataChangeEvent, DataObject> event = listener.event(); + assertContains(event.getCreatedData(), SIMPLE_AUGMENT); + assertEmpty(event.getUpdatedData()); + assertEmpty(event.getOriginalData()); + assertEmpty(event.getRemovedPaths()); + } + + @Test + public void leafOnlyAugmentationUpdatedTest() { + WriteTransaction writeTx = getDataBroker().newWriteOnlyTransaction(); + writeTx.put(LogicalDatastoreType.CONFIGURATION, TOP, top()); + writeTx.put(LogicalDatastoreType.CONFIGURATION, TOP_FOO, topLevelList(new TopLevelListKey(TOP_FOO_KEY))); + writeTx.put(LogicalDatastoreType.CONFIGURATION, SIMPLE_AUGMENT, leafOnlyUsesAugment("test leaf")); + assertCommit(writeTx.submit()); + TestListener listener = createListener(LogicalDatastoreType.CONFIGURATION, SIMPLE_AUGMENT, + AsyncDataBroker.DataChangeScope.SUBTREE); + writeTx = getDataBroker().newWriteOnlyTransaction(); + writeTx.put(LogicalDatastoreType.CONFIGURATION, SIMPLE_AUGMENT, leafOnlyUsesAugment("test leaf changed")); + assertCommit(writeTx.submit()); + assertTrue(listener.hasEvent()); + AsyncDataChangeEvent, DataObject> event = listener.event(); + assertContains(event.getUpdatedData(), SIMPLE_AUGMENT); + assertContains(event.getOriginalData(), SIMPLE_AUGMENT); + assertEmpty(event.getCreatedData()); + assertEmpty(event.getRemovedPaths()); + } + + @Test + public void leafOnlyAugmentationDeletedTest() { + WriteTransaction writeTx = getDataBroker().newWriteOnlyTransaction(); + writeTx.put(LogicalDatastoreType.CONFIGURATION, TOP, top()); + writeTx.put(LogicalDatastoreType.CONFIGURATION, TOP_FOO, topLevelList(new TopLevelListKey(TOP_FOO_KEY))); + writeTx.put(LogicalDatastoreType.CONFIGURATION, SIMPLE_AUGMENT, leafOnlyUsesAugment("test leaf")); + assertCommit(writeTx.submit()); + TestListener listener = createListener(LogicalDatastoreType.CONFIGURATION, SIMPLE_AUGMENT, + AsyncDataBroker.DataChangeScope.SUBTREE); + writeTx = getDataBroker().newWriteOnlyTransaction(); + writeTx.delete(LogicalDatastoreType.CONFIGURATION, SIMPLE_AUGMENT); + assertCommit(writeTx.submit()); + assertTrue(listener.hasEvent()); + AsyncDataChangeEvent, DataObject> event = listener.event(); + assertContains(event.getRemovedPaths(), SIMPLE_AUGMENT); + assertContains(event.getOriginalData(), SIMPLE_AUGMENT); + assertEmpty(event.getCreatedData()); + assertEmpty(event.getUpdatedData()); + } + + @Test + public void complexAugmentationCreatedTest() { + TestListener listener = createListener(LogicalDatastoreType.CONFIGURATION, COMPLEX_AUGMENT, + AsyncDataBroker.DataChangeScope.SUBTREE); + WriteTransaction writeTx = getDataBroker().newWriteOnlyTransaction(); + writeTx.put(LogicalDatastoreType.CONFIGURATION, TOP, top()); + writeTx.put(LogicalDatastoreType.CONFIGURATION, TOP_FOO, topLevelList(new TopLevelListKey(TOP_FOO_KEY))); + writeTx.put(LogicalDatastoreType.CONFIGURATION, COMPLEX_AUGMENT, complexUsesAugment(LIST_VIA_USES_KEY)); + assertCommit(writeTx.submit()); + assertTrue(listener.hasEvent()); + AsyncDataChangeEvent, DataObject> event = listener.event(); + assertContains(event.getCreatedData(), COMPLEX_AUGMENT); + assertContains(event.getCreatedData(), COMPLEX_AUGMENT.child(ListViaUses.class, LIST_VIA_USES_KEY)); + assertEmpty(event.getUpdatedData()); + assertEmpty(event.getOriginalData()); + assertEmpty(event.getRemovedPaths()); + } + + @Test + public void complexAugmentationUpdatedTest() { + WriteTransaction writeTx = getDataBroker().newWriteOnlyTransaction(); + writeTx.put(LogicalDatastoreType.CONFIGURATION, TOP, top()); + writeTx.put(LogicalDatastoreType.CONFIGURATION, TOP_FOO, topLevelList(new TopLevelListKey(TOP_FOO_KEY))); + writeTx.put(LogicalDatastoreType.CONFIGURATION, COMPLEX_AUGMENT, complexUsesAugment(LIST_VIA_USES_KEY)); + assertCommit(writeTx.submit()); + TestListener listener = createListener(LogicalDatastoreType.CONFIGURATION, COMPLEX_AUGMENT, + AsyncDataBroker.DataChangeScope.SUBTREE); + writeTx = getDataBroker().newWriteOnlyTransaction(); + writeTx.put(LogicalDatastoreType.CONFIGURATION, COMPLEX_AUGMENT, complexUsesAugment(LIST_VIA_USES_KEY_MOD)); + assertCommit(writeTx.submit()); + assertTrue(listener.hasEvent()); + AsyncDataChangeEvent, DataObject> event = listener.event(); + assertContains(event.getUpdatedData(), COMPLEX_AUGMENT); + assertContains(event.getCreatedData(), COMPLEX_AUGMENT.child(ListViaUses.class, LIST_VIA_USES_KEY_MOD)); + assertContains(event.getRemovedPaths(), COMPLEX_AUGMENT.child(ListViaUses.class, LIST_VIA_USES_KEY)); + assertContains(event.getOriginalData(), COMPLEX_AUGMENT); + assertContains(event.getOriginalData(), COMPLEX_AUGMENT.child(ListViaUses.class, LIST_VIA_USES_KEY)); + } +} diff --git a/opendaylight/md-sal/sal-binding-broker/src/test/java/org/opendaylight/controller/md/sal/binding/test/DataBrokerTestCustomizer.java b/opendaylight/md-sal/sal-binding-broker/src/test/java/org/opendaylight/controller/md/sal/binding/test/DataBrokerTestCustomizer.java index 79aa6b634b..e0f6f3546f 100644 --- a/opendaylight/md-sal/sal-binding-broker/src/test/java/org/opendaylight/controller/md/sal/binding/test/DataBrokerTestCustomizer.java +++ b/opendaylight/md-sal/sal-binding-broker/src/test/java/org/opendaylight/controller/md/sal/binding/test/DataBrokerTestCustomizer.java @@ -47,13 +47,13 @@ public class DataBrokerTestCustomizer { public DOMStore createConfigurationDatastore() { InMemoryDOMDataStore store = new InMemoryDOMDataStore("CFG", MoreExecutors.sameThreadExecutor()); - schemaService.registerSchemaServiceListener(store); + schemaService.registerSchemaContextListener(store); return store; } public DOMStore createOperationalDatastore() { InMemoryDOMDataStore store = new InMemoryDOMDataStore("OPER", MoreExecutors.sameThreadExecutor()); - schemaService.registerSchemaServiceListener(store); + schemaService.registerSchemaContextListener(store); return store; } 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 e82c9d385d..deb4a8aeca 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 @@ -144,8 +144,8 @@ public class BindingTestContext implements AutoCloseable { biCompatibleBroker = new BackwardsCompatibleDataBroker(newDOMDataBroker,mockSchemaService); - mockSchemaService.registerSchemaServiceListener(configStore); - mockSchemaService.registerSchemaServiceListener(operStore); + mockSchemaService.registerSchemaContextListener(configStore); + mockSchemaService.registerSchemaContextListener(operStore); biDataLegacyBroker = biCompatibleBroker; } @@ -246,7 +246,7 @@ public class BindingTestContext implements AutoCloseable { public void startBindingToDomMappingService() { checkState(classPool != null, "ClassPool needs to be present"); mappingServiceImpl = new RuntimeGeneratedMappingServiceImpl(classPool); - mockSchemaService.registerSchemaServiceListener(mappingServiceImpl); + mockSchemaService.registerSchemaContextListener(mappingServiceImpl); } private void updateYangSchema(final ImmutableSet moduleInfos) { diff --git a/opendaylight/md-sal/sal-binding-broker/src/test/java/org/opendaylight/controller/sal/binding/test/util/MockSchemaService.java b/opendaylight/md-sal/sal-binding-broker/src/test/java/org/opendaylight/controller/sal/binding/test/util/MockSchemaService.java index c8acbcd994..63a4ffb23a 100644 --- a/opendaylight/md-sal/sal-binding-broker/src/test/java/org/opendaylight/controller/sal/binding/test/util/MockSchemaService.java +++ b/opendaylight/md-sal/sal-binding-broker/src/test/java/org/opendaylight/controller/sal/binding/test/util/MockSchemaService.java @@ -13,14 +13,14 @@ import org.opendaylight.yangtools.concepts.ListenerRegistration; import org.opendaylight.yangtools.concepts.util.ListenerRegistry; import org.opendaylight.yangtools.yang.model.api.Module; import org.opendaylight.yangtools.yang.model.api.SchemaContext; -import org.opendaylight.yangtools.yang.model.api.SchemaServiceListener; +import org.opendaylight.yangtools.yang.model.api.SchemaContextListener; @SuppressWarnings("deprecation") public final class MockSchemaService implements SchemaService, SchemaContextProvider { private SchemaContext schemaContext; - ListenerRegistry listeners = ListenerRegistry.create(); + ListenerRegistry listeners = ListenerRegistry.create(); @Override public void addModule(final Module module) { @@ -38,8 +38,8 @@ public final class MockSchemaService implements SchemaService, SchemaContextProv } @Override - public ListenerRegistration registerSchemaServiceListener( - final SchemaServiceListener listener) { + public ListenerRegistration registerSchemaContextListener( + final SchemaContextListener listener) { return listeners.register(listener); } @@ -55,8 +55,8 @@ public final class MockSchemaService implements SchemaService, SchemaContextProv public synchronized void changeSchema(final SchemaContext newContext) { schemaContext = newContext; - for (ListenerRegistration listener : listeners) { + for (ListenerRegistration listener : listeners) { listener.getInstance().onGlobalContextUpdated(schemaContext); } } -} \ No newline at end of file +} diff --git a/opendaylight/md-sal/sal-binding-dom-it/pom.xml b/opendaylight/md-sal/sal-binding-dom-it/pom.xml index 42d5cfff65..7a66c41196 100644 --- a/opendaylight/md-sal/sal-binding-dom-it/pom.xml +++ b/opendaylight/md-sal/sal-binding-dom-it/pom.xml @@ -29,11 +29,6 @@ test-jar test
    - - org.opendaylight.controller.model - model-flow-management - test - org.opendaylight.controller.model model-flow-service 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 deleted file mode 100644 index 34a71ac0c4..0000000000 --- a/opendaylight/md-sal/sal-binding-dom-it/src/test/java/org/opendaylight/controller/sal/binding/test/bugfix/DOMCodecBug01Test.java +++ /dev/null @@ -1,232 +0,0 @@ -/* - * Copyright (c) 2014 Cisco Systems, Inc. and others. All rights reserved. - * - * This program and the accompanying materials are made available under the - * terms of the Eclipse Public License v1.0 which accompanies this distribution, - * and is available at http://www.eclipse.org/legal/epl-v10.html - */ -package org.opendaylight.controller.sal.binding.test.bugfix; - -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.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; -import org.opendaylight.controller.sal.binding.test.AbstractDataServiceTest; -import org.opendaylight.yang.gen.v1.urn.opendaylight.action.types.rev131112.action.action.PopMplsActionCaseBuilder; -import org.opendaylight.yang.gen.v1.urn.opendaylight.action.types.rev131112.action.action.pop.mpls.action._case.PopMplsActionBuilder; -import org.opendaylight.yang.gen.v1.urn.opendaylight.action.types.rev131112.action.list.Action; -import org.opendaylight.yang.gen.v1.urn.opendaylight.action.types.rev131112.action.list.ActionBuilder; -import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.config.rev130819.Flows; -import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.config.rev130819.flows.Flow; -import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.config.rev130819.flows.FlowBuilder; -import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.config.rev130819.flows.FlowKey; -import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.types.rev131026.flow.InstructionsBuilder; -import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.types.rev131026.flow.MatchBuilder; -import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.types.rev131026.instruction.instruction.ApplyActionsCaseBuilder; -import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.types.rev131026.instruction.instruction.apply.actions._case.ApplyActionsBuilder; -import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.types.rev131026.instruction.list.Instruction; -import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.types.rev131026.instruction.list.InstructionBuilder; -import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.NodeId; -import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.NodeRef; -import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.Nodes; -import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.nodes.Node; -import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.nodes.NodeKey; -import org.opendaylight.yang.gen.v1.urn.opendaylight.l2.types.rev130827.VlanId; -import org.opendaylight.yang.gen.v1.urn.opendaylight.model.match.types.rev131026.match.VlanMatchBuilder; -import org.opendaylight.yang.gen.v1.urn.opendaylight.model.match.types.rev131026.match.layer._4.match.TcpMatchBuilder; -import org.opendaylight.yang.gen.v1.urn.opendaylight.model.match.types.rev131026.vlan.match.fields.VlanIdBuilder; -import org.opendaylight.yangtools.yang.binding.DataObject; -import org.opendaylight.yangtools.yang.binding.InstanceIdentifier; -import org.opendaylight.yangtools.yang.common.RpcResult; -import org.opendaylight.yangtools.yang.data.api.CompositeNode; - -import com.google.common.util.concurrent.Futures; -import com.google.common.util.concurrent.ListenableFuture; -import com.google.common.util.concurrent.ListeningExecutorService; -import com.google.common.util.concurrent.MoreExecutors; - -@SuppressWarnings("deprecation") -public class DOMCodecBug01Test extends AbstractDataServiceTest { - - private static final long FLOW_ID = 1234; - private static final String NODE_ID = "node:1"; - - private static final NodeKey NODE_KEY = new NodeKey(new NodeId(NODE_ID)); - - private static final InstanceIdentifier NODE_INSTANCE_ID_BA = InstanceIdentifier.builder(Nodes.class) // - .child(Node.class, NODE_KEY).toInstance(); - - private static final NodeRef NODE_REF = new NodeRef(NODE_INSTANCE_ID_BA); - - private static final FlowKey FLOW_KEY = new FlowKey(FLOW_ID, NODE_REF); - - private static final InstanceIdentifier FLOW_INSTANCE_ID_BA = // - InstanceIdentifier.builder(Flows.class) // - .child(Flow.class, FLOW_KEY) // - .toInstance(); - - - - /** - * - * Testcase for https://bugs.opendaylight.org/show_bug.cgi?id= - * - * Cannot compile CoDec for - * org.opendaylight.yang.gen.v1.urn.opendaylight.flow - * .config.rev130819.flows.Flow - * - * When invoking following code in the consumer, user got an - * IllegalStateException during creation of mapping between Java DTOs and - * data-dom. - * - * Exception was compilation error which was caused by incorect generation - * of code. - * - * 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); - ListeningExecutorService listenablePool = MoreExecutors.listeningDecorator(basePool); - - createFlow(); - - Object lock = new Object(); - CreateFlowTask task1 = new CreateFlowTask(lock); - CreateFlowTask task2 = new CreateFlowTask(lock); - CreateFlowTask task3 = new CreateFlowTask(lock); - - ListenableFuture task1Future = listenablePool.submit(task1); - ListenableFuture task2Future = listenablePool.submit(task2); - ListenableFuture task3Future = listenablePool.submit(task3); - - - @SuppressWarnings("unchecked") - ListenableFuture> compositeFuture = Futures.allAsList(task1Future,task2Future,task3Future); - - Thread.sleep(500); - //lock.notifyAll(); - compositeFuture.get(); - - verifyDataAreStoredProperly(); - - DataModificationTransaction modification2 = baDataService.beginTransaction(); - modification2.removeConfigurationData(FLOW_INSTANCE_ID_BA); - - DataObject originalData = modification2.getOriginalConfigurationData().get(FLOW_INSTANCE_ID_BA); - assertNotNull(originalData); - RpcResult ret2 = modification2.commit().get(); - - assertNotNull(ret2); - assertEquals(TransactionStatus.COMMITED, ret2.getResult()); - - // Data are not in the store. - assertNull(baDataService.readConfigurationData(FLOW_INSTANCE_ID_BA)); - - } - - private void createFlow() throws Exception { - - DataModificationTransaction modification = baDataService.beginTransaction(); - - FlowBuilder flow = new FlowBuilder(); - MatchBuilder match = new MatchBuilder(); - VlanMatchBuilder vlanBuilder = new VlanMatchBuilder(); - VlanIdBuilder vlanIdBuilder = new VlanIdBuilder(); - VlanId vlanId = new VlanId(10); - vlanBuilder.setVlanId(vlanIdBuilder.setVlanId(vlanId).build()); - match.setVlanMatch(vlanBuilder.build()); - - flow.setKey(FLOW_KEY); - flow.setMatch(match.build()); - flow.setNode(NODE_REF); - InstructionsBuilder instructions = new InstructionsBuilder(); - InstructionBuilder instruction = new InstructionBuilder(); - - instruction.setOrder(10); - ApplyActionsBuilder applyActions = new ApplyActionsBuilder(); - List actionList = new ArrayList<>(); - PopMplsActionBuilder popMplsAction = new PopMplsActionBuilder(); - popMplsAction.setEthernetType(34); - actionList.add(new ActionBuilder().setAction(new PopMplsActionCaseBuilder().setPopMplsAction(popMplsAction.build()).build()).setOrder(10).build()); - - applyActions.setAction(actionList ); - - instruction.setInstruction(new ApplyActionsCaseBuilder().setApplyActions(applyActions.build()).build()); - - - List instructionList = Collections.singletonList(instruction.build()); - instructions.setInstruction(instructionList ); - - flow.setInstructions(instructions.build()); - modification.putConfigurationData(FLOW_INSTANCE_ID_BA, flow.build()); - RpcResult ret = modification.commit().get(); - assertNotNull(ret); - assertEquals(TransactionStatus.COMMITED, ret.getResult()); - } - - private void createFlow2() throws Exception { - DataModificationTransaction modification = baDataService.beginTransaction(); - long id = 123; - FlowKey key = new FlowKey(id, new NodeRef(NODE_INSTANCE_ID_BA)); - InstanceIdentifier path1; - FlowBuilder flow = new FlowBuilder(); - flow.setKey(key); - MatchBuilder match = new MatchBuilder(); - match.setLayer4Match(new TcpMatchBuilder().build()); - flow.setMatch(match.build()); - - path1 = InstanceIdentifier.builder(Flows.class).child(Flow.class, key).toInstance(); - // DataObject cls = (DataObject) modification.readConfigurationData(path1); - modification.putConfigurationData(path1, flow.build()); - modification.commit(); - - } - - private class CreateFlowTask implements Callable { - - public CreateFlowTask(final Object startSync) { - } - - @Override - public Void call() { - try { - //startSyncObj ect.wait(); - //Thread.sleep(500); - createFlow(); - createFlow2(); - } catch (Exception e) { - throw new RuntimeException(e); - } - return null; - } - } - - private void verifyDataAreStoredProperly() { - CompositeNode biFlows = biDataService.readConfigurationData(org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier.of(Flows.QNAME)); - assertNotNull(biFlows); - CompositeNode biFlow = biFlows.getFirstCompositeByName(Flow.QNAME); - assertNotNull(biFlow); - } - - -} diff --git a/opendaylight/md-sal/sal-binding-it/pom.xml b/opendaylight/md-sal/sal-binding-it/pom.xml index b8bb891e79..1912462cf0 100644 --- a/opendaylight/md-sal/sal-binding-it/pom.xml +++ b/opendaylight/md-sal/sal-binding-it/pom.xml @@ -8,12 +8,6 @@ sal-binding-it - - ../sal-binding-broker/target/jacoco-it.exec - - ../sal-binding-broker/target/jacoco.exec - - ch.qos.logback @@ -39,6 +33,10 @@ org.mockito mockito-all + + org.opendaylight.yangtools + object-cache-guava + org.opendaylight.controller config-manager @@ -124,11 +122,6 @@ org.slf4j log4j-over-slf4j - - org.opendaylight.controller.model - model-flow-management - provided - org.opendaylight.controller.model model-flow-service @@ -165,65 +158,9 @@ - - org.jacoco - jacoco-maven-plugin - ${jacoco.version} - - ../sal-binding-broker/target/jacoco-it.exec - - org.opendaylight.controller.* - - - - - pre-test - - prepare-agent - - - - post-test - - true - - - - - - org.apache.maven.plugins - maven-surefire-plugin - - false - - - - org.jacoco - jacoco-maven-plugin - - - org.opendaylight.controller.* - - - - - pre-test - - prepare-agent - - - - post-test - - report - - test - - - org.ops4j.pax.exam maven-paxexam-plugin diff --git a/opendaylight/md-sal/sal-binding-it/src/main/java/org/opendaylight/controller/test/sal/binding/it/TestHelper.java b/opendaylight/md-sal/sal-binding-it/src/main/java/org/opendaylight/controller/test/sal/binding/it/TestHelper.java index c389618f2e..83a69969b7 100644 --- a/opendaylight/md-sal/sal-binding-it/src/main/java/org/opendaylight/controller/test/sal/binding/it/TestHelper.java +++ b/opendaylight/md-sal/sal-binding-it/src/main/java/org/opendaylight/controller/test/sal/binding/it/TestHelper.java @@ -30,6 +30,8 @@ public class TestHelper { mavenBundle(YANGTOOLS, "util").versionAsInProject(), // // mavenBundle(YANGTOOLS, "yang-binding").versionAsInProject(), // // mavenBundle(YANGTOOLS, "yang-common").versionAsInProject(), // // + mavenBundle(YANGTOOLS, "object-cache-api").versionAsInProject(), // // + mavenBundle(YANGTOOLS, "object-cache-guava").versionAsInProject(), // // mavenBundle(CONTROLLER, "sal-common").versionAsInProject(), // // mavenBundle(CONTROLLER, "sal-common-api").versionAsInProject(), // // mavenBundle(CONTROLLER, "sal-common-impl").versionAsInProject(), // // diff --git a/opendaylight/md-sal/sal-protocolbuffer-encoding/README-FIRST b/opendaylight/md-sal/sal-clustering-commons/README-FIRST similarity index 77% rename from opendaylight/md-sal/sal-protocolbuffer-encoding/README-FIRST rename to opendaylight/md-sal/sal-clustering-commons/README-FIRST index d0be2cbcbb..4791979c17 100644 --- a/opendaylight/md-sal/sal-protocolbuffer-encoding/README-FIRST +++ b/opendaylight/md-sal/sal-clustering-commons/README-FIRST @@ -24,5 +24,9 @@ machine 6. !!!WARNING!!! - never edit the generated sources files of protocol buffer -7. !!!NOTE!!! if you are planning to add new .proto file option java_package should begin with +7. !!!IMPORTANT!!! if you are planning to add new .proto file option java_package should begin with org.opendaylight.controller.protobuff.messages to properly exclude from sonar. + +8. !!!IMPORTANT!!! for any new .proto file added you need to create corresponding version-compatibility-serialized-data + serialized test file under test/resources and a test case for one message in your .proto file. + Please follow the instruction in readme.txt in that folder diff --git a/opendaylight/md-sal/sal-protocolbuffer-encoding/pom.xml b/opendaylight/md-sal/sal-clustering-commons/pom.xml similarity index 98% rename from opendaylight/md-sal/sal-protocolbuffer-encoding/pom.xml rename to opendaylight/md-sal/sal-clustering-commons/pom.xml index 28e629a92c..6db4d3a094 100644 --- a/opendaylight/md-sal/sal-protocolbuffer-encoding/pom.xml +++ b/opendaylight/md-sal/sal-clustering-commons/pom.xml @@ -8,7 +8,7 @@ 1.1-SNAPSHOT - sal-protocolbuffer-encoding + sal-clustering-commons bundle diff --git a/opendaylight/md-sal/sal-protocolbuffer-encoding/run.sh b/opendaylight/md-sal/sal-clustering-commons/run.sh similarity index 93% rename from opendaylight/md-sal/sal-protocolbuffer-encoding/run.sh rename to opendaylight/md-sal/sal-clustering-commons/run.sh index f0907db664..d3d0324fa0 100755 --- a/opendaylight/md-sal/sal-protocolbuffer-encoding/run.sh +++ b/opendaylight/md-sal/sal-clustering-commons/run.sh @@ -30,7 +30,7 @@ # org.opendaylight.controller.protobuff.messages to properly exclude from sonar. ######################################################################################################## -protoc --proto_path=src/main/resources --java_out=src/main/java src/main/resources/*.proto +protoc --proto_path=src/main/resources --proto_path=../sal-akka-raft/src/main/resources --java_out=src/main/java src/main/resources/*.proto echo "Done generating Java source files." diff --git a/opendaylight/md-sal/sal-protocolbuffer-encoding/src/main/java/org/opendaylight/controller/cluster/datastore/node/NodeToNormalizedNodeBuilder.java b/opendaylight/md-sal/sal-clustering-commons/src/main/java/org/opendaylight/controller/cluster/datastore/node/NodeToNormalizedNodeBuilder.java similarity index 98% rename from opendaylight/md-sal/sal-protocolbuffer-encoding/src/main/java/org/opendaylight/controller/cluster/datastore/node/NodeToNormalizedNodeBuilder.java rename to opendaylight/md-sal/sal-clustering-commons/src/main/java/org/opendaylight/controller/cluster/datastore/node/NodeToNormalizedNodeBuilder.java index ce120809d7..03d632b61f 100644 --- a/opendaylight/md-sal/sal-protocolbuffer-encoding/src/main/java/org/opendaylight/controller/cluster/datastore/node/NodeToNormalizedNodeBuilder.java +++ b/opendaylight/md-sal/sal-clustering-commons/src/main/java/org/opendaylight/controller/cluster/datastore/node/NodeToNormalizedNodeBuilder.java @@ -1,3 +1,13 @@ +/* + * + * 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.cluster.datastore.node; import com.google.common.base.Preconditions; diff --git a/opendaylight/md-sal/sal-protocolbuffer-encoding/src/main/java/org/opendaylight/controller/cluster/datastore/node/NodeValueCodec.java b/opendaylight/md-sal/sal-clustering-commons/src/main/java/org/opendaylight/controller/cluster/datastore/node/NodeValueCodec.java similarity index 86% rename from opendaylight/md-sal/sal-protocolbuffer-encoding/src/main/java/org/opendaylight/controller/cluster/datastore/node/NodeValueCodec.java rename to opendaylight/md-sal/sal-clustering-commons/src/main/java/org/opendaylight/controller/cluster/datastore/node/NodeValueCodec.java index 7b6f5c46d2..b6dbefbbac 100644 --- a/opendaylight/md-sal/sal-protocolbuffer-encoding/src/main/java/org/opendaylight/controller/cluster/datastore/node/NodeValueCodec.java +++ b/opendaylight/md-sal/sal-clustering-commons/src/main/java/org/opendaylight/controller/cluster/datastore/node/NodeValueCodec.java @@ -1,9 +1,11 @@ /* - * 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 + * 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.cluster.datastore.node; @@ -16,7 +18,7 @@ import org.opendaylight.yangtools.yang.data.impl.codec.TypeDefinitionAwareCodec; import org.opendaylight.yangtools.yang.model.api.DataSchemaNode; import org.opendaylight.yangtools.yang.model.api.TypeDefinition; import org.opendaylight.yangtools.yang.model.util.IdentityrefType; -import org.opendaylight.yangtools.yang.model.util.InstanceIdentifier; +import org.opendaylight.yangtools.yang.model.util.InstanceIdentifierType; import org.opendaylight.yangtools.yang.model.util.Leafref; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -55,7 +57,7 @@ public class NodeValueCodec { return value; } else if(baseType instanceof IdentityrefType) { return QNameFactory.create(value); - } else if(baseType instanceof InstanceIdentifier) { + } else if(baseType instanceof InstanceIdentifierType) { return InstanceIdentifierUtils.fromSerializable(node.getInstanceIdentifierValue()); } else { logger.error("Could not figure out how to transform value " + value + " for schemaType " + type); diff --git a/opendaylight/md-sal/sal-protocolbuffer-encoding/src/main/java/org/opendaylight/controller/cluster/datastore/node/NormalizedNodeToNodeCodec.java b/opendaylight/md-sal/sal-clustering-commons/src/main/java/org/opendaylight/controller/cluster/datastore/node/NormalizedNodeToNodeCodec.java similarity index 87% rename from opendaylight/md-sal/sal-protocolbuffer-encoding/src/main/java/org/opendaylight/controller/cluster/datastore/node/NormalizedNodeToNodeCodec.java rename to opendaylight/md-sal/sal-clustering-commons/src/main/java/org/opendaylight/controller/cluster/datastore/node/NormalizedNodeToNodeCodec.java index fc4b3954c5..17bdb36e56 100644 --- a/opendaylight/md-sal/sal-protocolbuffer-encoding/src/main/java/org/opendaylight/controller/cluster/datastore/node/NormalizedNodeToNodeCodec.java +++ b/opendaylight/md-sal/sal-clustering-commons/src/main/java/org/opendaylight/controller/cluster/datastore/node/NormalizedNodeToNodeCodec.java @@ -1,3 +1,13 @@ +/* + * + * 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.cluster.datastore.node; import org.opendaylight.controller.protobuff.messages.common.NormalizedNodeMessages; diff --git a/opendaylight/md-sal/sal-protocolbuffer-encoding/src/main/java/org/opendaylight/controller/cluster/datastore/node/NormalizedNodeToProtocolBufferNode.java b/opendaylight/md-sal/sal-clustering-commons/src/main/java/org/opendaylight/controller/cluster/datastore/node/NormalizedNodeToProtocolBufferNode.java similarity index 97% rename from opendaylight/md-sal/sal-protocolbuffer-encoding/src/main/java/org/opendaylight/controller/cluster/datastore/node/NormalizedNodeToProtocolBufferNode.java rename to opendaylight/md-sal/sal-clustering-commons/src/main/java/org/opendaylight/controller/cluster/datastore/node/NormalizedNodeToProtocolBufferNode.java index fb15312665..68d3c590e0 100644 --- a/opendaylight/md-sal/sal-protocolbuffer-encoding/src/main/java/org/opendaylight/controller/cluster/datastore/node/NormalizedNodeToProtocolBufferNode.java +++ b/opendaylight/md-sal/sal-clustering-commons/src/main/java/org/opendaylight/controller/cluster/datastore/node/NormalizedNodeToProtocolBufferNode.java @@ -1,3 +1,13 @@ +/* + * + * 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.cluster.datastore.node; import com.google.common.base.Preconditions; diff --git a/opendaylight/md-sal/sal-protocolbuffer-encoding/src/main/java/org/opendaylight/controller/cluster/datastore/node/utils/AugmentationIdentifierGenerator.java b/opendaylight/md-sal/sal-clustering-commons/src/main/java/org/opendaylight/controller/cluster/datastore/node/utils/AugmentationIdentifierGenerator.java similarity index 81% rename from opendaylight/md-sal/sal-protocolbuffer-encoding/src/main/java/org/opendaylight/controller/cluster/datastore/node/utils/AugmentationIdentifierGenerator.java rename to opendaylight/md-sal/sal-clustering-commons/src/main/java/org/opendaylight/controller/cluster/datastore/node/utils/AugmentationIdentifierGenerator.java index a34307f6b4..e2c4c35893 100644 --- a/opendaylight/md-sal/sal-protocolbuffer-encoding/src/main/java/org/opendaylight/controller/cluster/datastore/node/utils/AugmentationIdentifierGenerator.java +++ b/opendaylight/md-sal/sal-clustering-commons/src/main/java/org/opendaylight/controller/cluster/datastore/node/utils/AugmentationIdentifierGenerator.java @@ -1,3 +1,13 @@ +/* + * + * 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.cluster.datastore.node.utils; import org.opendaylight.yangtools.yang.common.QName; diff --git a/opendaylight/md-sal/sal-protocolbuffer-encoding/src/main/java/org/opendaylight/controller/cluster/datastore/node/utils/NodeIdentifierFactory.java b/opendaylight/md-sal/sal-clustering-commons/src/main/java/org/opendaylight/controller/cluster/datastore/node/utils/NodeIdentifierFactory.java similarity index 87% rename from opendaylight/md-sal/sal-protocolbuffer-encoding/src/main/java/org/opendaylight/controller/cluster/datastore/node/utils/NodeIdentifierFactory.java rename to opendaylight/md-sal/sal-clustering-commons/src/main/java/org/opendaylight/controller/cluster/datastore/node/utils/NodeIdentifierFactory.java index 175e242a11..ea3986f4a0 100644 --- a/opendaylight/md-sal/sal-protocolbuffer-encoding/src/main/java/org/opendaylight/controller/cluster/datastore/node/utils/NodeIdentifierFactory.java +++ b/opendaylight/md-sal/sal-clustering-commons/src/main/java/org/opendaylight/controller/cluster/datastore/node/utils/NodeIdentifierFactory.java @@ -1,3 +1,13 @@ +/* + * + * 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.cluster.datastore.node.utils; import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier; diff --git a/opendaylight/md-sal/sal-protocolbuffer-encoding/src/main/java/org/opendaylight/controller/cluster/datastore/node/utils/NodeIdentifierGenerator.java b/opendaylight/md-sal/sal-clustering-commons/src/main/java/org/opendaylight/controller/cluster/datastore/node/utils/NodeIdentifierGenerator.java similarity index 63% rename from opendaylight/md-sal/sal-protocolbuffer-encoding/src/main/java/org/opendaylight/controller/cluster/datastore/node/utils/NodeIdentifierGenerator.java rename to opendaylight/md-sal/sal-clustering-commons/src/main/java/org/opendaylight/controller/cluster/datastore/node/utils/NodeIdentifierGenerator.java index 9edec1e230..1b9c70867d 100644 --- a/opendaylight/md-sal/sal-protocolbuffer-encoding/src/main/java/org/opendaylight/controller/cluster/datastore/node/utils/NodeIdentifierGenerator.java +++ b/opendaylight/md-sal/sal-clustering-commons/src/main/java/org/opendaylight/controller/cluster/datastore/node/utils/NodeIdentifierGenerator.java @@ -1,3 +1,13 @@ +/* + * + * 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.cluster.datastore.node.utils; import org.opendaylight.yangtools.yang.common.QName; diff --git a/opendaylight/md-sal/sal-protocolbuffer-encoding/src/main/java/org/opendaylight/controller/cluster/datastore/node/utils/NodeIdentifierWithPredicatesGenerator.java b/opendaylight/md-sal/sal-clustering-commons/src/main/java/org/opendaylight/controller/cluster/datastore/node/utils/NodeIdentifierWithPredicatesGenerator.java similarity index 89% rename from opendaylight/md-sal/sal-protocolbuffer-encoding/src/main/java/org/opendaylight/controller/cluster/datastore/node/utils/NodeIdentifierWithPredicatesGenerator.java rename to opendaylight/md-sal/sal-clustering-commons/src/main/java/org/opendaylight/controller/cluster/datastore/node/utils/NodeIdentifierWithPredicatesGenerator.java index 4bfcf391dd..6d3a26ad77 100644 --- a/opendaylight/md-sal/sal-protocolbuffer-encoding/src/main/java/org/opendaylight/controller/cluster/datastore/node/utils/NodeIdentifierWithPredicatesGenerator.java +++ b/opendaylight/md-sal/sal-clustering-commons/src/main/java/org/opendaylight/controller/cluster/datastore/node/utils/NodeIdentifierWithPredicatesGenerator.java @@ -1,3 +1,13 @@ +/* + * + * 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.cluster.datastore.node.utils; import org.opendaylight.yangtools.yang.common.QName; diff --git a/opendaylight/md-sal/sal-protocolbuffer-encoding/src/main/java/org/opendaylight/controller/cluster/datastore/node/utils/NodeIdentifierWithValueGenerator.java b/opendaylight/md-sal/sal-clustering-commons/src/main/java/org/opendaylight/controller/cluster/datastore/node/utils/NodeIdentifierWithValueGenerator.java similarity index 84% rename from opendaylight/md-sal/sal-protocolbuffer-encoding/src/main/java/org/opendaylight/controller/cluster/datastore/node/utils/NodeIdentifierWithValueGenerator.java rename to opendaylight/md-sal/sal-clustering-commons/src/main/java/org/opendaylight/controller/cluster/datastore/node/utils/NodeIdentifierWithValueGenerator.java index b2ec5644d4..2d434fffcf 100644 --- a/opendaylight/md-sal/sal-protocolbuffer-encoding/src/main/java/org/opendaylight/controller/cluster/datastore/node/utils/NodeIdentifierWithValueGenerator.java +++ b/opendaylight/md-sal/sal-clustering-commons/src/main/java/org/opendaylight/controller/cluster/datastore/node/utils/NodeIdentifierWithValueGenerator.java @@ -1,3 +1,13 @@ +/* + * + * 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.cluster.datastore.node.utils; import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier; diff --git a/opendaylight/md-sal/sal-protocolbuffer-encoding/src/main/java/org/opendaylight/controller/cluster/datastore/node/utils/NormalizedNodeGetter.java b/opendaylight/md-sal/sal-clustering-commons/src/main/java/org/opendaylight/controller/cluster/datastore/node/utils/NormalizedNodeGetter.java similarity index 71% rename from opendaylight/md-sal/sal-protocolbuffer-encoding/src/main/java/org/opendaylight/controller/cluster/datastore/node/utils/NormalizedNodeGetter.java rename to opendaylight/md-sal/sal-clustering-commons/src/main/java/org/opendaylight/controller/cluster/datastore/node/utils/NormalizedNodeGetter.java index e82a23d37f..31e6521a28 100644 --- a/opendaylight/md-sal/sal-protocolbuffer-encoding/src/main/java/org/opendaylight/controller/cluster/datastore/node/utils/NormalizedNodeGetter.java +++ b/opendaylight/md-sal/sal-clustering-commons/src/main/java/org/opendaylight/controller/cluster/datastore/node/utils/NormalizedNodeGetter.java @@ -1,3 +1,13 @@ +/* + * + * 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.cluster.datastore.node.utils; import com.google.common.base.Preconditions; diff --git a/opendaylight/md-sal/sal-protocolbuffer-encoding/src/main/java/org/opendaylight/controller/cluster/datastore/node/utils/NormalizedNodeNavigator.java b/opendaylight/md-sal/sal-clustering-commons/src/main/java/org/opendaylight/controller/cluster/datastore/node/utils/NormalizedNodeNavigator.java similarity index 91% rename from opendaylight/md-sal/sal-protocolbuffer-encoding/src/main/java/org/opendaylight/controller/cluster/datastore/node/utils/NormalizedNodeNavigator.java rename to opendaylight/md-sal/sal-clustering-commons/src/main/java/org/opendaylight/controller/cluster/datastore/node/utils/NormalizedNodeNavigator.java index 4ccc7076ff..0083b00403 100644 --- a/opendaylight/md-sal/sal-protocolbuffer-encoding/src/main/java/org/opendaylight/controller/cluster/datastore/node/utils/NormalizedNodeNavigator.java +++ b/opendaylight/md-sal/sal-clustering-commons/src/main/java/org/opendaylight/controller/cluster/datastore/node/utils/NormalizedNodeNavigator.java @@ -1,3 +1,13 @@ +/* + * + * 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.cluster.datastore.node.utils; import com.google.common.base.Preconditions; diff --git a/opendaylight/md-sal/sal-protocolbuffer-encoding/src/main/java/org/opendaylight/controller/cluster/datastore/node/utils/NormalizedNodePrinter.java b/opendaylight/md-sal/sal-clustering-commons/src/main/java/org/opendaylight/controller/cluster/datastore/node/utils/NormalizedNodePrinter.java similarity index 79% rename from opendaylight/md-sal/sal-protocolbuffer-encoding/src/main/java/org/opendaylight/controller/cluster/datastore/node/utils/NormalizedNodePrinter.java rename to opendaylight/md-sal/sal-clustering-commons/src/main/java/org/opendaylight/controller/cluster/datastore/node/utils/NormalizedNodePrinter.java index 7735a12a8b..d370eb2deb 100644 --- a/opendaylight/md-sal/sal-protocolbuffer-encoding/src/main/java/org/opendaylight/controller/cluster/datastore/node/utils/NormalizedNodePrinter.java +++ b/opendaylight/md-sal/sal-clustering-commons/src/main/java/org/opendaylight/controller/cluster/datastore/node/utils/NormalizedNodePrinter.java @@ -1,3 +1,13 @@ +/* + * + * 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.cluster.datastore.node.utils; import org.opendaylight.yangtools.yang.data.api.schema.LeafNode; diff --git a/opendaylight/md-sal/sal-clustering-commons/src/main/java/org/opendaylight/controller/cluster/datastore/node/utils/NormalizedNodeVisitor.java b/opendaylight/md-sal/sal-clustering-commons/src/main/java/org/opendaylight/controller/cluster/datastore/node/utils/NormalizedNodeVisitor.java new file mode 100644 index 0000000000..9e85ccb9ab --- /dev/null +++ b/opendaylight/md-sal/sal-clustering-commons/src/main/java/org/opendaylight/controller/cluster/datastore/node/utils/NormalizedNodeVisitor.java @@ -0,0 +1,17 @@ +/* + * + * 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.cluster.datastore.node.utils; + +import org.opendaylight.yangtools.yang.data.api.schema.NormalizedNode; + +public interface NormalizedNodeVisitor { + public void visitNode(int level, String parentPath, NormalizedNode normalizedNode); +} diff --git a/opendaylight/md-sal/sal-protocolbuffer-encoding/src/main/java/org/opendaylight/controller/cluster/datastore/node/utils/PathUtils.java b/opendaylight/md-sal/sal-clustering-commons/src/main/java/org/opendaylight/controller/cluster/datastore/node/utils/PathUtils.java similarity index 65% rename from opendaylight/md-sal/sal-protocolbuffer-encoding/src/main/java/org/opendaylight/controller/cluster/datastore/node/utils/PathUtils.java rename to opendaylight/md-sal/sal-clustering-commons/src/main/java/org/opendaylight/controller/cluster/datastore/node/utils/PathUtils.java index ba81836ea8..cf5174319d 100644 --- a/opendaylight/md-sal/sal-protocolbuffer-encoding/src/main/java/org/opendaylight/controller/cluster/datastore/node/utils/PathUtils.java +++ b/opendaylight/md-sal/sal-clustering-commons/src/main/java/org/opendaylight/controller/cluster/datastore/node/utils/PathUtils.java @@ -1,3 +1,13 @@ +/* + * + * 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.cluster.datastore.node.utils; public class PathUtils { diff --git a/opendaylight/md-sal/sal-protocolbuffer-encoding/src/main/java/org/opendaylight/controller/cluster/datastore/node/utils/QNameFactory.java b/opendaylight/md-sal/sal-clustering-commons/src/main/java/org/opendaylight/controller/cluster/datastore/node/utils/QNameFactory.java similarity index 67% rename from opendaylight/md-sal/sal-protocolbuffer-encoding/src/main/java/org/opendaylight/controller/cluster/datastore/node/utils/QNameFactory.java rename to opendaylight/md-sal/sal-clustering-commons/src/main/java/org/opendaylight/controller/cluster/datastore/node/utils/QNameFactory.java index 8dba0563bd..002b9ff82e 100644 --- a/opendaylight/md-sal/sal-protocolbuffer-encoding/src/main/java/org/opendaylight/controller/cluster/datastore/node/utils/QNameFactory.java +++ b/opendaylight/md-sal/sal-clustering-commons/src/main/java/org/opendaylight/controller/cluster/datastore/node/utils/QNameFactory.java @@ -1,3 +1,13 @@ +/* + * + * 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.cluster.datastore.node.utils; import org.opendaylight.yangtools.yang.common.QName; diff --git a/opendaylight/md-sal/sal-protocolbuffer-encoding/src/main/java/org/opendaylight/controller/cluster/datastore/util/EncoderDecoderUtil.java b/opendaylight/md-sal/sal-clustering-commons/src/main/java/org/opendaylight/controller/cluster/datastore/util/EncoderDecoderUtil.java similarity index 97% rename from opendaylight/md-sal/sal-protocolbuffer-encoding/src/main/java/org/opendaylight/controller/cluster/datastore/util/EncoderDecoderUtil.java rename to opendaylight/md-sal/sal-clustering-commons/src/main/java/org/opendaylight/controller/cluster/datastore/util/EncoderDecoderUtil.java index d9a067b573..90f5cf3396 100644 --- a/opendaylight/md-sal/sal-protocolbuffer-encoding/src/main/java/org/opendaylight/controller/cluster/datastore/util/EncoderDecoderUtil.java +++ b/opendaylight/md-sal/sal-clustering-commons/src/main/java/org/opendaylight/controller/cluster/datastore/util/EncoderDecoderUtil.java @@ -1,3 +1,13 @@ +/* + * + * 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.cluster.datastore.util; import com.google.common.base.Preconditions; @@ -44,13 +54,6 @@ import java.util.Collections; import java.util.Iterator; import java.util.List; -/* - * 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 - */ /* * * EncoderDecoderUtil helps in wrapping the NormalizedNode into a SimpleNormalizedNode diff --git a/opendaylight/md-sal/sal-protocolbuffer-encoding/src/main/java/org/opendaylight/controller/cluster/datastore/util/InstanceIdentifierUtils.java b/opendaylight/md-sal/sal-clustering-commons/src/main/java/org/opendaylight/controller/cluster/datastore/util/InstanceIdentifierUtils.java similarity index 97% rename from opendaylight/md-sal/sal-protocolbuffer-encoding/src/main/java/org/opendaylight/controller/cluster/datastore/util/InstanceIdentifierUtils.java rename to opendaylight/md-sal/sal-clustering-commons/src/main/java/org/opendaylight/controller/cluster/datastore/util/InstanceIdentifierUtils.java index 5b459e7e7c..55cb341086 100644 --- a/opendaylight/md-sal/sal-protocolbuffer-encoding/src/main/java/org/opendaylight/controller/cluster/datastore/util/InstanceIdentifierUtils.java +++ b/opendaylight/md-sal/sal-clustering-commons/src/main/java/org/opendaylight/controller/cluster/datastore/util/InstanceIdentifierUtils.java @@ -1,3 +1,13 @@ +/* + * + * 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.cluster.datastore.util; import org.opendaylight.controller.cluster.datastore.node.utils.NodeIdentifierFactory; diff --git a/opendaylight/md-sal/sal-protocolbuffer-encoding/src/main/java/org/opendaylight/controller/mdsal/CompositeModificationPayload.java b/opendaylight/md-sal/sal-clustering-commons/src/main/java/org/opendaylight/controller/mdsal/CompositeModificationPayload.java similarity index 100% rename from opendaylight/md-sal/sal-protocolbuffer-encoding/src/main/java/org/opendaylight/controller/mdsal/CompositeModificationPayload.java rename to opendaylight/md-sal/sal-clustering-commons/src/main/java/org/opendaylight/controller/mdsal/CompositeModificationPayload.java diff --git a/opendaylight/md-sal/sal-protocolbuffer-encoding/src/main/java/org/opendaylight/controller/protobuff/messages/cohort3pc/ThreePhaseCommitCohortMessages.java b/opendaylight/md-sal/sal-clustering-commons/src/main/java/org/opendaylight/controller/protobuff/messages/cohort3pc/ThreePhaseCommitCohortMessages.java similarity index 99% rename from opendaylight/md-sal/sal-protocolbuffer-encoding/src/main/java/org/opendaylight/controller/protobuff/messages/cohort3pc/ThreePhaseCommitCohortMessages.java rename to opendaylight/md-sal/sal-clustering-commons/src/main/java/org/opendaylight/controller/protobuff/messages/cohort3pc/ThreePhaseCommitCohortMessages.java index ac0701a6d8..22a93c0e10 100644 --- a/opendaylight/md-sal/sal-protocolbuffer-encoding/src/main/java/org/opendaylight/controller/protobuff/messages/cohort3pc/ThreePhaseCommitCohortMessages.java +++ b/opendaylight/md-sal/sal-clustering-commons/src/main/java/org/opendaylight/controller/protobuff/messages/cohort3pc/ThreePhaseCommitCohortMessages.java @@ -652,7 +652,7 @@ public final class ThreePhaseCommitCohortMessages { public final boolean isInitialized() { if (!hasCanCommit()) { - + return false; } return true; diff --git a/opendaylight/md-sal/sal-protocolbuffer-encoding/src/main/java/org/opendaylight/controller/protobuff/messages/common/NormalizedNodeMessages.java b/opendaylight/md-sal/sal-clustering-commons/src/main/java/org/opendaylight/controller/protobuff/messages/common/NormalizedNodeMessages.java similarity index 98% rename from opendaylight/md-sal/sal-protocolbuffer-encoding/src/main/java/org/opendaylight/controller/protobuff/messages/common/NormalizedNodeMessages.java rename to opendaylight/md-sal/sal-clustering-commons/src/main/java/org/opendaylight/controller/protobuff/messages/common/NormalizedNodeMessages.java index 81e5b462cc..35c2940be3 100644 --- a/opendaylight/md-sal/sal-protocolbuffer-encoding/src/main/java/org/opendaylight/controller/protobuff/messages/common/NormalizedNodeMessages.java +++ b/opendaylight/md-sal/sal-clustering-commons/src/main/java/org/opendaylight/controller/protobuff/messages/common/NormalizedNodeMessages.java @@ -179,7 +179,7 @@ public final class NormalizedNodeMessages { if (ref instanceof java.lang.String) { return (java.lang.String) ref; } else { - com.google.protobuf.ByteString bs = + com.google.protobuf.ByteString bs = (com.google.protobuf.ByteString) ref; java.lang.String s = bs.toStringUtf8(); if (bs.isValidUtf8()) { @@ -195,7 +195,7 @@ public final class NormalizedNodeMessages { getNameBytes() { java.lang.Object ref = name_; if (ref instanceof java.lang.String) { - com.google.protobuf.ByteString b = + com.google.protobuf.ByteString b = com.google.protobuf.ByteString.copyFromUtf8( (java.lang.String) ref); name_ = b; @@ -222,7 +222,7 @@ public final class NormalizedNodeMessages { if (ref instanceof java.lang.String) { return (java.lang.String) ref; } else { - com.google.protobuf.ByteString bs = + com.google.protobuf.ByteString bs = (com.google.protobuf.ByteString) ref; java.lang.String s = bs.toStringUtf8(); if (bs.isValidUtf8()) { @@ -238,7 +238,7 @@ public final class NormalizedNodeMessages { getValueBytes() { java.lang.Object ref = value_; if (ref instanceof java.lang.String) { - com.google.protobuf.ByteString b = + com.google.protobuf.ByteString b = com.google.protobuf.ByteString.copyFromUtf8( (java.lang.String) ref); value_ = b; @@ -265,7 +265,7 @@ public final class NormalizedNodeMessages { if (ref instanceof java.lang.String) { return (java.lang.String) ref; } else { - com.google.protobuf.ByteString bs = + com.google.protobuf.ByteString bs = (com.google.protobuf.ByteString) ref; java.lang.String s = bs.toStringUtf8(); if (bs.isValidUtf8()) { @@ -281,7 +281,7 @@ public final class NormalizedNodeMessages { getTypeBytes() { java.lang.Object ref = type_; if (ref instanceof java.lang.String) { - com.google.protobuf.ByteString b = + com.google.protobuf.ByteString b = com.google.protobuf.ByteString.copyFromUtf8( (java.lang.String) ref); type_ = b; @@ -541,7 +541,7 @@ public final class NormalizedNodeMessages { public final boolean isInitialized() { if (!hasName()) { - + return false; } return true; @@ -595,7 +595,7 @@ public final class NormalizedNodeMessages { getNameBytes() { java.lang.Object ref = name_; if (ref instanceof String) { - com.google.protobuf.ByteString b = + com.google.protobuf.ByteString b = com.google.protobuf.ByteString.copyFromUtf8( (java.lang.String) ref); name_ = b; @@ -669,7 +669,7 @@ public final class NormalizedNodeMessages { getValueBytes() { java.lang.Object ref = value_; if (ref instanceof String) { - com.google.protobuf.ByteString b = + com.google.protobuf.ByteString b = com.google.protobuf.ByteString.copyFromUtf8( (java.lang.String) ref); value_ = b; @@ -743,7 +743,7 @@ public final class NormalizedNodeMessages { getTypeBytes() { java.lang.Object ref = type_; if (ref instanceof String) { - com.google.protobuf.ByteString b = + com.google.protobuf.ByteString b = com.google.protobuf.ByteString.copyFromUtf8( (java.lang.String) ref); type_ = b; @@ -930,7 +930,7 @@ public final class NormalizedNodeMessages { if (ref instanceof java.lang.String) { return (java.lang.String) ref; } else { - com.google.protobuf.ByteString bs = + com.google.protobuf.ByteString bs = (com.google.protobuf.ByteString) ref; java.lang.String s = bs.toStringUtf8(); if (bs.isValidUtf8()) { @@ -946,7 +946,7 @@ public final class NormalizedNodeMessages { getValueBytes() { java.lang.Object ref = value_; if (ref instanceof java.lang.String) { - com.google.protobuf.ByteString b = + com.google.protobuf.ByteString b = com.google.protobuf.ByteString.copyFromUtf8( (java.lang.String) ref); value_ = b; @@ -1168,7 +1168,7 @@ public final class NormalizedNodeMessages { public final boolean isInitialized() { if (!hasValue()) { - + return false; } return true; @@ -1222,7 +1222,7 @@ public final class NormalizedNodeMessages { getValueBytes() { java.lang.Object ref = value_; if (ref instanceof String) { - com.google.protobuf.ByteString b = + com.google.protobuf.ByteString b = com.google.protobuf.ByteString.copyFromUtf8( (java.lang.String) ref); value_ = b; @@ -1341,7 +1341,7 @@ public final class NormalizedNodeMessages { /** * repeated .org.opendaylight.controller.mdsal.Attribute attributes = 4; */ - java.util.List + java.util.List getAttributesList(); /** * repeated .org.opendaylight.controller.mdsal.Attribute attributes = 4; @@ -1354,7 +1354,7 @@ public final class NormalizedNodeMessages { /** * repeated .org.opendaylight.controller.mdsal.Attribute attributes = 4; */ - java.util.List + java.util.List getAttributesOrBuilderList(); /** * repeated .org.opendaylight.controller.mdsal.Attribute attributes = 4; @@ -1504,7 +1504,7 @@ public final class NormalizedNodeMessages { if (ref instanceof java.lang.String) { return (java.lang.String) ref; } else { - com.google.protobuf.ByteString bs = + com.google.protobuf.ByteString bs = (com.google.protobuf.ByteString) ref; java.lang.String s = bs.toStringUtf8(); if (bs.isValidUtf8()) { @@ -1520,7 +1520,7 @@ public final class NormalizedNodeMessages { getValueBytes() { java.lang.Object ref = value_; if (ref instanceof java.lang.String) { - com.google.protobuf.ByteString b = + com.google.protobuf.ByteString b = com.google.protobuf.ByteString.copyFromUtf8( (java.lang.String) ref); value_ = b; @@ -1555,7 +1555,7 @@ public final class NormalizedNodeMessages { if (ref instanceof java.lang.String) { return (java.lang.String) ref; } else { - com.google.protobuf.ByteString bs = + com.google.protobuf.ByteString bs = (com.google.protobuf.ByteString) ref; java.lang.String s = bs.toStringUtf8(); if (bs.isValidUtf8()) { @@ -1575,7 +1575,7 @@ public final class NormalizedNodeMessages { getTypeBytes() { java.lang.Object ref = type_; if (ref instanceof java.lang.String) { - com.google.protobuf.ByteString b = + com.google.protobuf.ByteString b = com.google.protobuf.ByteString.copyFromUtf8( (java.lang.String) ref); type_ = b; @@ -1619,7 +1619,7 @@ public final class NormalizedNodeMessages { /** * repeated .org.opendaylight.controller.mdsal.Attribute attributes = 4; */ - public java.util.List + public java.util.List getAttributesOrBuilderList() { return attributes_; } @@ -1948,7 +1948,7 @@ public final class NormalizedNodeMessages { attributesBuilder_ = null; attributes_ = other.attributes_; bitField0_ = (bitField0_ & ~0x00000008); - attributesBuilder_ = + attributesBuilder_ = com.google.protobuf.GeneratedMessage.alwaysUseFieldBuilders ? getAttributesFieldBuilder() : null; } else { @@ -1962,18 +1962,18 @@ public final class NormalizedNodeMessages { public final boolean isInitialized() { if (!hasValue()) { - + return false; } if (hasNodeType()) { if (!getNodeType().isInitialized()) { - + return false; } } for (int i = 0; i < getAttributesCount(); i++) { if (!getAttributes(i).isInitialized()) { - + return false; } } @@ -2028,7 +2028,7 @@ public final class NormalizedNodeMessages { getValueBytes() { java.lang.Object ref = value_; if (ref instanceof String) { - com.google.protobuf.ByteString b = + com.google.protobuf.ByteString b = com.google.protobuf.ByteString.copyFromUtf8( (java.lang.String) ref); value_ = b; @@ -2114,7 +2114,7 @@ public final class NormalizedNodeMessages { getTypeBytes() { java.lang.Object ref = type_; if (ref instanceof String) { - com.google.protobuf.ByteString b = + com.google.protobuf.ByteString b = com.google.protobuf.ByteString.copyFromUtf8( (java.lang.String) ref); type_ = b; @@ -2275,7 +2275,7 @@ public final class NormalizedNodeMessages { * optional .org.opendaylight.controller.mdsal.QName nodeType = 3; */ private com.google.protobuf.SingleFieldBuilder< - org.opendaylight.controller.protobuff.messages.common.NormalizedNodeMessages.QName, org.opendaylight.controller.protobuff.messages.common.NormalizedNodeMessages.QName.Builder, org.opendaylight.controller.protobuff.messages.common.NormalizedNodeMessages.QNameOrBuilder> + org.opendaylight.controller.protobuff.messages.common.NormalizedNodeMessages.QName, org.opendaylight.controller.protobuff.messages.common.NormalizedNodeMessages.QName.Builder, org.opendaylight.controller.protobuff.messages.common.NormalizedNodeMessages.QNameOrBuilder> getNodeTypeFieldBuilder() { if (nodeTypeBuilder_ == null) { nodeTypeBuilder_ = new com.google.protobuf.SingleFieldBuilder< @@ -2483,7 +2483,7 @@ public final class NormalizedNodeMessages { /** * repeated .org.opendaylight.controller.mdsal.Attribute attributes = 4; */ - public java.util.List + public java.util.List getAttributesOrBuilderList() { if (attributesBuilder_ != null) { return attributesBuilder_.getMessageOrBuilderList(); @@ -2509,12 +2509,12 @@ public final class NormalizedNodeMessages { /** * repeated .org.opendaylight.controller.mdsal.Attribute attributes = 4; */ - public java.util.List + public java.util.List getAttributesBuilderList() { return getAttributesFieldBuilder().getBuilderList(); } private com.google.protobuf.RepeatedFieldBuilder< - org.opendaylight.controller.protobuff.messages.common.NormalizedNodeMessages.Attribute, org.opendaylight.controller.protobuff.messages.common.NormalizedNodeMessages.Attribute.Builder, org.opendaylight.controller.protobuff.messages.common.NormalizedNodeMessages.AttributeOrBuilder> + org.opendaylight.controller.protobuff.messages.common.NormalizedNodeMessages.Attribute, org.opendaylight.controller.protobuff.messages.common.NormalizedNodeMessages.Attribute.Builder, org.opendaylight.controller.protobuff.messages.common.NormalizedNodeMessages.AttributeOrBuilder> getAttributesFieldBuilder() { if (attributesBuilder_ == null) { attributesBuilder_ = new com.google.protobuf.RepeatedFieldBuilder< @@ -2546,7 +2546,7 @@ public final class NormalizedNodeMessages { /** * repeated .org.opendaylight.controller.mdsal.PathArgument arguments = 1; */ - java.util.List + java.util.List getArgumentsList(); /** * repeated .org.opendaylight.controller.mdsal.PathArgument arguments = 1; @@ -2559,7 +2559,7 @@ public final class NormalizedNodeMessages { /** * repeated .org.opendaylight.controller.mdsal.PathArgument arguments = 1; */ - java.util.List + java.util.List getArgumentsOrBuilderList(); /** * repeated .org.opendaylight.controller.mdsal.PathArgument arguments = 1; @@ -2680,7 +2680,7 @@ public final class NormalizedNodeMessages { /** * repeated .org.opendaylight.controller.mdsal.PathArgument arguments = 1; */ - public java.util.List + public java.util.List getArgumentsOrBuilderList() { return arguments_; } @@ -2933,7 +2933,7 @@ public final class NormalizedNodeMessages { argumentsBuilder_ = null; arguments_ = other.arguments_; bitField0_ = (bitField0_ & ~0x00000001); - argumentsBuilder_ = + argumentsBuilder_ = com.google.protobuf.GeneratedMessage.alwaysUseFieldBuilders ? getArgumentsFieldBuilder() : null; } else { @@ -2948,7 +2948,7 @@ public final class NormalizedNodeMessages { public final boolean isInitialized() { for (int i = 0; i < getArgumentsCount(); i++) { if (!getArguments(i).isInitialized()) { - + return false; } } @@ -3169,7 +3169,7 @@ public final class NormalizedNodeMessages { /** * repeated .org.opendaylight.controller.mdsal.PathArgument arguments = 1; */ - public java.util.List + public java.util.List getArgumentsOrBuilderList() { if (argumentsBuilder_ != null) { return argumentsBuilder_.getMessageOrBuilderList(); @@ -3195,12 +3195,12 @@ public final class NormalizedNodeMessages { /** * repeated .org.opendaylight.controller.mdsal.PathArgument arguments = 1; */ - public java.util.List + public java.util.List getArgumentsBuilderList() { return getArgumentsFieldBuilder().getBuilderList(); } private com.google.protobuf.RepeatedFieldBuilder< - org.opendaylight.controller.protobuff.messages.common.NormalizedNodeMessages.PathArgument, org.opendaylight.controller.protobuff.messages.common.NormalizedNodeMessages.PathArgument.Builder, org.opendaylight.controller.protobuff.messages.common.NormalizedNodeMessages.PathArgumentOrBuilder> + org.opendaylight.controller.protobuff.messages.common.NormalizedNodeMessages.PathArgument, org.opendaylight.controller.protobuff.messages.common.NormalizedNodeMessages.PathArgument.Builder, org.opendaylight.controller.protobuff.messages.common.NormalizedNodeMessages.PathArgumentOrBuilder> getArgumentsFieldBuilder() { if (argumentsBuilder_ == null) { argumentsBuilder_ = new com.google.protobuf.RepeatedFieldBuilder< @@ -3262,7 +3262,7 @@ public final class NormalizedNodeMessages { /** * repeated .org.opendaylight.controller.mdsal.Attribute attributes = 3; */ - java.util.List + java.util.List getAttributesList(); /** * repeated .org.opendaylight.controller.mdsal.Attribute attributes = 3; @@ -3275,7 +3275,7 @@ public final class NormalizedNodeMessages { /** * repeated .org.opendaylight.controller.mdsal.Attribute attributes = 3; */ - java.util.List + java.util.List getAttributesOrBuilderList(); /** * repeated .org.opendaylight.controller.mdsal.Attribute attributes = 3; @@ -3287,7 +3287,7 @@ public final class NormalizedNodeMessages { /** * repeated .org.opendaylight.controller.mdsal.Node child = 4; */ - java.util.List + java.util.List getChildList(); /** * repeated .org.opendaylight.controller.mdsal.Node child = 4; @@ -3300,7 +3300,7 @@ public final class NormalizedNodeMessages { /** * repeated .org.opendaylight.controller.mdsal.Node child = 4; */ - java.util.List + java.util.List getChildOrBuilderList(); /** * repeated .org.opendaylight.controller.mdsal.Node child = 4; @@ -3546,7 +3546,7 @@ public final class NormalizedNodeMessages { if (ref instanceof java.lang.String) { return (java.lang.String) ref; } else { - com.google.protobuf.ByteString bs = + com.google.protobuf.ByteString bs = (com.google.protobuf.ByteString) ref; java.lang.String s = bs.toStringUtf8(); if (bs.isValidUtf8()) { @@ -3562,7 +3562,7 @@ public final class NormalizedNodeMessages { getPathBytes() { java.lang.Object ref = path_; if (ref instanceof java.lang.String) { - com.google.protobuf.ByteString b = + com.google.protobuf.ByteString b = com.google.protobuf.ByteString.copyFromUtf8( (java.lang.String) ref); path_ = b; @@ -3589,7 +3589,7 @@ public final class NormalizedNodeMessages { if (ref instanceof java.lang.String) { return (java.lang.String) ref; } else { - com.google.protobuf.ByteString bs = + com.google.protobuf.ByteString bs = (com.google.protobuf.ByteString) ref; java.lang.String s = bs.toStringUtf8(); if (bs.isValidUtf8()) { @@ -3605,7 +3605,7 @@ public final class NormalizedNodeMessages { getTypeBytes() { java.lang.Object ref = type_; if (ref instanceof java.lang.String) { - com.google.protobuf.ByteString b = + com.google.protobuf.ByteString b = com.google.protobuf.ByteString.copyFromUtf8( (java.lang.String) ref); type_ = b; @@ -3627,7 +3627,7 @@ public final class NormalizedNodeMessages { /** * repeated .org.opendaylight.controller.mdsal.Attribute attributes = 3; */ - public java.util.List + public java.util.List getAttributesOrBuilderList() { return attributes_; } @@ -3663,7 +3663,7 @@ public final class NormalizedNodeMessages { /** * repeated .org.opendaylight.controller.mdsal.Node child = 4; */ - public java.util.List + public java.util.List getChildOrBuilderList() { return child_; } @@ -3704,7 +3704,7 @@ public final class NormalizedNodeMessages { if (ref instanceof java.lang.String) { return (java.lang.String) ref; } else { - com.google.protobuf.ByteString bs = + com.google.protobuf.ByteString bs = (com.google.protobuf.ByteString) ref; java.lang.String s = bs.toStringUtf8(); if (bs.isValidUtf8()) { @@ -3720,7 +3720,7 @@ public final class NormalizedNodeMessages { getValueBytes() { java.lang.Object ref = value_; if (ref instanceof java.lang.String) { - com.google.protobuf.ByteString b = + com.google.protobuf.ByteString b = com.google.protobuf.ByteString.copyFromUtf8( (java.lang.String) ref); value_ = b; @@ -3747,7 +3747,7 @@ public final class NormalizedNodeMessages { if (ref instanceof java.lang.String) { return (java.lang.String) ref; } else { - com.google.protobuf.ByteString bs = + com.google.protobuf.ByteString bs = (com.google.protobuf.ByteString) ref; java.lang.String s = bs.toStringUtf8(); if (bs.isValidUtf8()) { @@ -3763,7 +3763,7 @@ public final class NormalizedNodeMessages { getValueTypeBytes() { java.lang.Object ref = valueType_; if (ref instanceof java.lang.String) { - com.google.protobuf.ByteString b = + com.google.protobuf.ByteString b = com.google.protobuf.ByteString.copyFromUtf8( (java.lang.String) ref); valueType_ = b; @@ -4202,7 +4202,7 @@ public final class NormalizedNodeMessages { attributesBuilder_ = null; attributes_ = other.attributes_; bitField0_ = (bitField0_ & ~0x00000004); - attributesBuilder_ = + attributesBuilder_ = com.google.protobuf.GeneratedMessage.alwaysUseFieldBuilders ? getAttributesFieldBuilder() : null; } else { @@ -4228,7 +4228,7 @@ public final class NormalizedNodeMessages { childBuilder_ = null; child_ = other.child_; bitField0_ = (bitField0_ & ~0x00000008); - childBuilder_ = + childBuilder_ = com.google.protobuf.GeneratedMessage.alwaysUseFieldBuilders ? getChildFieldBuilder() : null; } else { @@ -4266,19 +4266,19 @@ public final class NormalizedNodeMessages { public final boolean isInitialized() { for (int i = 0; i < getAttributesCount(); i++) { if (!getAttributes(i).isInitialized()) { - + return false; } } for (int i = 0; i < getChildCount(); i++) { if (!getChild(i).isInitialized()) { - + return false; } } if (hasInstanceIdentifierValue()) { if (!getInstanceIdentifierValue().isInitialized()) { - + return false; } } @@ -4333,7 +4333,7 @@ public final class NormalizedNodeMessages { getPathBytes() { java.lang.Object ref = path_; if (ref instanceof String) { - com.google.protobuf.ByteString b = + com.google.protobuf.ByteString b = com.google.protobuf.ByteString.copyFromUtf8( (java.lang.String) ref); path_ = b; @@ -4407,7 +4407,7 @@ public final class NormalizedNodeMessages { getTypeBytes() { java.lang.Object ref = type_; if (ref instanceof String) { - com.google.protobuf.ByteString b = + com.google.protobuf.ByteString b = com.google.protobuf.ByteString.copyFromUtf8( (java.lang.String) ref); type_ = b; @@ -4647,7 +4647,7 @@ public final class NormalizedNodeMessages { /** * repeated .org.opendaylight.controller.mdsal.Attribute attributes = 3; */ - public java.util.List + public java.util.List getAttributesOrBuilderList() { if (attributesBuilder_ != null) { return attributesBuilder_.getMessageOrBuilderList(); @@ -4673,12 +4673,12 @@ public final class NormalizedNodeMessages { /** * repeated .org.opendaylight.controller.mdsal.Attribute attributes = 3; */ - public java.util.List + public java.util.List getAttributesBuilderList() { return getAttributesFieldBuilder().getBuilderList(); } private com.google.protobuf.RepeatedFieldBuilder< - org.opendaylight.controller.protobuff.messages.common.NormalizedNodeMessages.Attribute, org.opendaylight.controller.protobuff.messages.common.NormalizedNodeMessages.Attribute.Builder, org.opendaylight.controller.protobuff.messages.common.NormalizedNodeMessages.AttributeOrBuilder> + org.opendaylight.controller.protobuff.messages.common.NormalizedNodeMessages.Attribute, org.opendaylight.controller.protobuff.messages.common.NormalizedNodeMessages.Attribute.Builder, org.opendaylight.controller.protobuff.messages.common.NormalizedNodeMessages.AttributeOrBuilder> getAttributesFieldBuilder() { if (attributesBuilder_ == null) { attributesBuilder_ = new com.google.protobuf.RepeatedFieldBuilder< @@ -4887,7 +4887,7 @@ public final class NormalizedNodeMessages { /** * repeated .org.opendaylight.controller.mdsal.Node child = 4; */ - public java.util.List + public java.util.List getChildOrBuilderList() { if (childBuilder_ != null) { return childBuilder_.getMessageOrBuilderList(); @@ -4913,12 +4913,12 @@ public final class NormalizedNodeMessages { /** * repeated .org.opendaylight.controller.mdsal.Node child = 4; */ - public java.util.List + public java.util.List getChildBuilderList() { return getChildFieldBuilder().getBuilderList(); } private com.google.protobuf.RepeatedFieldBuilder< - org.opendaylight.controller.protobuff.messages.common.NormalizedNodeMessages.Node, org.opendaylight.controller.protobuff.messages.common.NormalizedNodeMessages.Node.Builder, org.opendaylight.controller.protobuff.messages.common.NormalizedNodeMessages.NodeOrBuilder> + org.opendaylight.controller.protobuff.messages.common.NormalizedNodeMessages.Node, org.opendaylight.controller.protobuff.messages.common.NormalizedNodeMessages.Node.Builder, org.opendaylight.controller.protobuff.messages.common.NormalizedNodeMessages.NodeOrBuilder> getChildFieldBuilder() { if (childBuilder_ == null) { childBuilder_ = new com.google.protobuf.RepeatedFieldBuilder< @@ -4961,7 +4961,7 @@ public final class NormalizedNodeMessages { getValueBytes() { java.lang.Object ref = value_; if (ref instanceof String) { - com.google.protobuf.ByteString b = + com.google.protobuf.ByteString b = com.google.protobuf.ByteString.copyFromUtf8( (java.lang.String) ref); value_ = b; @@ -5035,7 +5035,7 @@ public final class NormalizedNodeMessages { getValueTypeBytes() { java.lang.Object ref = valueType_; if (ref instanceof String) { - com.google.protobuf.ByteString b = + com.google.protobuf.ByteString b = com.google.protobuf.ByteString.copyFromUtf8( (java.lang.String) ref); valueType_ = b; @@ -5277,7 +5277,7 @@ public final class NormalizedNodeMessages { * optional .org.opendaylight.controller.mdsal.InstanceIdentifier instanceIdentifierValue = 8; */ private com.google.protobuf.SingleFieldBuilder< - org.opendaylight.controller.protobuff.messages.common.NormalizedNodeMessages.InstanceIdentifier, org.opendaylight.controller.protobuff.messages.common.NormalizedNodeMessages.InstanceIdentifier.Builder, org.opendaylight.controller.protobuff.messages.common.NormalizedNodeMessages.InstanceIdentifierOrBuilder> + org.opendaylight.controller.protobuff.messages.common.NormalizedNodeMessages.InstanceIdentifier, org.opendaylight.controller.protobuff.messages.common.NormalizedNodeMessages.InstanceIdentifier.Builder, org.opendaylight.controller.protobuff.messages.common.NormalizedNodeMessages.InstanceIdentifierOrBuilder> getInstanceIdentifierValueFieldBuilder() { if (instanceIdentifierValueBuilder_ == null) { instanceIdentifierValueBuilder_ = new com.google.protobuf.SingleFieldBuilder< @@ -5459,7 +5459,7 @@ public final class NormalizedNodeMessages { if (ref instanceof java.lang.String) { return (java.lang.String) ref; } else { - com.google.protobuf.ByteString bs = + com.google.protobuf.ByteString bs = (com.google.protobuf.ByteString) ref; java.lang.String s = bs.toStringUtf8(); if (bs.isValidUtf8()) { @@ -5475,7 +5475,7 @@ public final class NormalizedNodeMessages { getParentPathBytes() { java.lang.Object ref = parentPath_; if (ref instanceof java.lang.String) { - com.google.protobuf.ByteString b = + com.google.protobuf.ByteString b = com.google.protobuf.ByteString.copyFromUtf8( (java.lang.String) ref); parentPath_ = b; @@ -5751,12 +5751,12 @@ public final class NormalizedNodeMessages { public final boolean isInitialized() { if (!hasParentPath()) { - + return false; } if (hasNormalizedNode()) { if (!getNormalizedNode().isInitialized()) { - + return false; } } @@ -5811,7 +5811,7 @@ public final class NormalizedNodeMessages { getParentPathBytes() { java.lang.Object ref = parentPath_; if (ref instanceof String) { - com.google.protobuf.ByteString b = + com.google.protobuf.ByteString b = com.google.protobuf.ByteString.copyFromUtf8( (java.lang.String) ref); parentPath_ = b; @@ -5960,7 +5960,7 @@ public final class NormalizedNodeMessages { * optional .org.opendaylight.controller.mdsal.Node normalizedNode = 2; */ private com.google.protobuf.SingleFieldBuilder< - org.opendaylight.controller.protobuff.messages.common.NormalizedNodeMessages.Node, org.opendaylight.controller.protobuff.messages.common.NormalizedNodeMessages.Node.Builder, org.opendaylight.controller.protobuff.messages.common.NormalizedNodeMessages.NodeOrBuilder> + org.opendaylight.controller.protobuff.messages.common.NormalizedNodeMessages.Node, org.opendaylight.controller.protobuff.messages.common.NormalizedNodeMessages.Node.Builder, org.opendaylight.controller.protobuff.messages.common.NormalizedNodeMessages.NodeOrBuilder> getNormalizedNodeFieldBuilder() { if (normalizedNodeBuilder_ == null) { normalizedNodeBuilder_ = new com.google.protobuf.SingleFieldBuilder< @@ -6431,16 +6431,16 @@ public final class NormalizedNodeMessages { public final boolean isInitialized() { if (!hasInstanceIdentifierPath()) { - + return false; } if (!getInstanceIdentifierPath().isInitialized()) { - + return false; } if (hasNormalizedNode()) { if (!getNormalizedNode().isInitialized()) { - + return false; } } @@ -6570,7 +6570,7 @@ public final class NormalizedNodeMessages { * required .org.opendaylight.controller.mdsal.InstanceIdentifier instanceIdentifierPath = 1; */ private com.google.protobuf.SingleFieldBuilder< - org.opendaylight.controller.protobuff.messages.common.NormalizedNodeMessages.InstanceIdentifier, org.opendaylight.controller.protobuff.messages.common.NormalizedNodeMessages.InstanceIdentifier.Builder, org.opendaylight.controller.protobuff.messages.common.NormalizedNodeMessages.InstanceIdentifierOrBuilder> + org.opendaylight.controller.protobuff.messages.common.NormalizedNodeMessages.InstanceIdentifier, org.opendaylight.controller.protobuff.messages.common.NormalizedNodeMessages.InstanceIdentifier.Builder, org.opendaylight.controller.protobuff.messages.common.NormalizedNodeMessages.InstanceIdentifierOrBuilder> getInstanceIdentifierPathFieldBuilder() { if (instanceIdentifierPathBuilder_ == null) { instanceIdentifierPathBuilder_ = new com.google.protobuf.SingleFieldBuilder< @@ -6687,7 +6687,7 @@ public final class NormalizedNodeMessages { * optional .org.opendaylight.controller.mdsal.Node normalizedNode = 2; */ private com.google.protobuf.SingleFieldBuilder< - org.opendaylight.controller.protobuff.messages.common.NormalizedNodeMessages.Node, org.opendaylight.controller.protobuff.messages.common.NormalizedNodeMessages.Node.Builder, org.opendaylight.controller.protobuff.messages.common.NormalizedNodeMessages.NodeOrBuilder> + org.opendaylight.controller.protobuff.messages.common.NormalizedNodeMessages.Node, org.opendaylight.controller.protobuff.messages.common.NormalizedNodeMessages.Node.Builder, org.opendaylight.controller.protobuff.messages.common.NormalizedNodeMessages.NodeOrBuilder> getNormalizedNodeFieldBuilder() { if (normalizedNodeBuilder_ == null) { normalizedNodeBuilder_ = new com.google.protobuf.SingleFieldBuilder< @@ -6718,7 +6718,7 @@ public final class NormalizedNodeMessages { /** * repeated .org.opendaylight.controller.mdsal.NodeMapEntry mapEntries = 1; */ - java.util.List + java.util.List getMapEntriesList(); /** * repeated .org.opendaylight.controller.mdsal.NodeMapEntry mapEntries = 1; @@ -6731,7 +6731,7 @@ public final class NormalizedNodeMessages { /** * repeated .org.opendaylight.controller.mdsal.NodeMapEntry mapEntries = 1; */ - java.util.List + java.util.List getMapEntriesOrBuilderList(); /** * repeated .org.opendaylight.controller.mdsal.NodeMapEntry mapEntries = 1; @@ -6852,7 +6852,7 @@ public final class NormalizedNodeMessages { /** * repeated .org.opendaylight.controller.mdsal.NodeMapEntry mapEntries = 1; */ - public java.util.List + public java.util.List getMapEntriesOrBuilderList() { return mapEntries_; } @@ -7105,7 +7105,7 @@ public final class NormalizedNodeMessages { mapEntriesBuilder_ = null; mapEntries_ = other.mapEntries_; bitField0_ = (bitField0_ & ~0x00000001); - mapEntriesBuilder_ = + mapEntriesBuilder_ = com.google.protobuf.GeneratedMessage.alwaysUseFieldBuilders ? getMapEntriesFieldBuilder() : null; } else { @@ -7120,7 +7120,7 @@ public final class NormalizedNodeMessages { public final boolean isInitialized() { for (int i = 0; i < getMapEntriesCount(); i++) { if (!getMapEntries(i).isInitialized()) { - + return false; } } @@ -7341,7 +7341,7 @@ public final class NormalizedNodeMessages { /** * repeated .org.opendaylight.controller.mdsal.NodeMapEntry mapEntries = 1; */ - public java.util.List + public java.util.List getMapEntriesOrBuilderList() { if (mapEntriesBuilder_ != null) { return mapEntriesBuilder_.getMessageOrBuilderList(); @@ -7367,12 +7367,12 @@ public final class NormalizedNodeMessages { /** * repeated .org.opendaylight.controller.mdsal.NodeMapEntry mapEntries = 1; */ - public java.util.List + public java.util.List getMapEntriesBuilderList() { return getMapEntriesFieldBuilder().getBuilderList(); } private com.google.protobuf.RepeatedFieldBuilder< - org.opendaylight.controller.protobuff.messages.common.NormalizedNodeMessages.NodeMapEntry, org.opendaylight.controller.protobuff.messages.common.NormalizedNodeMessages.NodeMapEntry.Builder, org.opendaylight.controller.protobuff.messages.common.NormalizedNodeMessages.NodeMapEntryOrBuilder> + org.opendaylight.controller.protobuff.messages.common.NormalizedNodeMessages.NodeMapEntry, org.opendaylight.controller.protobuff.messages.common.NormalizedNodeMessages.NodeMapEntry.Builder, org.opendaylight.controller.protobuff.messages.common.NormalizedNodeMessages.NodeMapEntryOrBuilder> getMapEntriesFieldBuilder() { if (mapEntriesBuilder_ == null) { mapEntriesBuilder_ = new com.google.protobuf.RepeatedFieldBuilder< diff --git a/opendaylight/md-sal/sal-protocolbuffer-encoding/src/main/java/org/opendaylight/controller/protobuff/messages/common/SimpleNormalizedNodeMessage.java b/opendaylight/md-sal/sal-clustering-commons/src/main/java/org/opendaylight/controller/protobuff/messages/common/SimpleNormalizedNodeMessage.java similarity index 98% rename from opendaylight/md-sal/sal-protocolbuffer-encoding/src/main/java/org/opendaylight/controller/protobuff/messages/common/SimpleNormalizedNodeMessage.java rename to opendaylight/md-sal/sal-clustering-commons/src/main/java/org/opendaylight/controller/protobuff/messages/common/SimpleNormalizedNodeMessage.java index 29e54571d3..67ab472d0c 100644 --- a/opendaylight/md-sal/sal-protocolbuffer-encoding/src/main/java/org/opendaylight/controller/protobuff/messages/common/SimpleNormalizedNodeMessage.java +++ b/opendaylight/md-sal/sal-clustering-commons/src/main/java/org/opendaylight/controller/protobuff/messages/common/SimpleNormalizedNodeMessage.java @@ -159,7 +159,7 @@ public final class SimpleNormalizedNodeMessage { if (ref instanceof java.lang.String) { return (java.lang.String) ref; } else { - com.google.protobuf.ByteString bs = + com.google.protobuf.ByteString bs = (com.google.protobuf.ByteString) ref; java.lang.String s = bs.toStringUtf8(); if (bs.isValidUtf8()) { @@ -175,7 +175,7 @@ public final class SimpleNormalizedNodeMessage { getNodeIdentifierBytes() { java.lang.Object ref = nodeIdentifier_; if (ref instanceof java.lang.String) { - com.google.protobuf.ByteString b = + com.google.protobuf.ByteString b = com.google.protobuf.ByteString.copyFromUtf8( (java.lang.String) ref); nodeIdentifier_ = b; @@ -202,7 +202,7 @@ public final class SimpleNormalizedNodeMessage { if (ref instanceof java.lang.String) { return (java.lang.String) ref; } else { - com.google.protobuf.ByteString bs = + com.google.protobuf.ByteString bs = (com.google.protobuf.ByteString) ref; java.lang.String s = bs.toStringUtf8(); if (bs.isValidUtf8()) { @@ -218,7 +218,7 @@ public final class SimpleNormalizedNodeMessage { getXmlStringBytes() { java.lang.Object ref = xmlString_; if (ref instanceof java.lang.String) { - com.google.protobuf.ByteString b = + com.google.protobuf.ByteString b = com.google.protobuf.ByteString.copyFromUtf8( (java.lang.String) ref); xmlString_ = b; @@ -463,11 +463,11 @@ public final class SimpleNormalizedNodeMessage { public final boolean isInitialized() { if (!hasNodeIdentifier()) { - + return false; } if (!hasXmlString()) { - + return false; } return true; @@ -521,7 +521,7 @@ public final class SimpleNormalizedNodeMessage { getNodeIdentifierBytes() { java.lang.Object ref = nodeIdentifier_; if (ref instanceof String) { - com.google.protobuf.ByteString b = + com.google.protobuf.ByteString b = com.google.protobuf.ByteString.copyFromUtf8( (java.lang.String) ref); nodeIdentifier_ = b; @@ -595,7 +595,7 @@ public final class SimpleNormalizedNodeMessage { getXmlStringBytes() { java.lang.Object ref = xmlString_; if (ref instanceof String) { - com.google.protobuf.ByteString b = + com.google.protobuf.ByteString b = com.google.protobuf.ByteString.copyFromUtf8( (java.lang.String) ref); xmlString_ = b; diff --git a/opendaylight/md-sal/sal-protocolbuffer-encoding/src/main/java/org/opendaylight/controller/protobuff/messages/datachange/notification/DataChangeListenerMessages.java b/opendaylight/md-sal/sal-clustering-commons/src/main/java/org/opendaylight/controller/protobuff/messages/datachange/notification/DataChangeListenerMessages.java similarity index 99% rename from opendaylight/md-sal/sal-protocolbuffer-encoding/src/main/java/org/opendaylight/controller/protobuff/messages/datachange/notification/DataChangeListenerMessages.java rename to opendaylight/md-sal/sal-clustering-commons/src/main/java/org/opendaylight/controller/protobuff/messages/datachange/notification/DataChangeListenerMessages.java index 2018834768..384b389f92 100644 --- a/opendaylight/md-sal/sal-protocolbuffer-encoding/src/main/java/org/opendaylight/controller/protobuff/messages/datachange/notification/DataChangeListenerMessages.java +++ b/opendaylight/md-sal/sal-clustering-commons/src/main/java/org/opendaylight/controller/protobuff/messages/datachange/notification/DataChangeListenerMessages.java @@ -85,7 +85,7 @@ public final class DataChangeListenerMessages { /** * repeated .org.opendaylight.controller.mdsal.InstanceIdentifier removedPaths = 6; */ - java.util.List + java.util.List getRemovedPathsList(); /** * repeated .org.opendaylight.controller.mdsal.InstanceIdentifier removedPaths = 6; @@ -98,7 +98,7 @@ public final class DataChangeListenerMessages { /** * repeated .org.opendaylight.controller.mdsal.InstanceIdentifier removedPaths = 6; */ - java.util.List + java.util.List getRemovedPathsOrBuilderList(); /** * repeated .org.opendaylight.controller.mdsal.InstanceIdentifier removedPaths = 6; @@ -395,7 +395,7 @@ public final class DataChangeListenerMessages { /** * repeated .org.opendaylight.controller.mdsal.InstanceIdentifier removedPaths = 6; */ - public java.util.List + public java.util.List getRemovedPathsOrBuilderList() { return removedPaths_; } @@ -810,7 +810,7 @@ public final class DataChangeListenerMessages { removedPathsBuilder_ = null; removedPaths_ = other.removedPaths_; bitField0_ = (bitField0_ & ~0x00000020); - removedPathsBuilder_ = + removedPathsBuilder_ = com.google.protobuf.GeneratedMessage.alwaysUseFieldBuilders ? getRemovedPathsFieldBuilder() : null; } else { @@ -825,37 +825,37 @@ public final class DataChangeListenerMessages { public final boolean isInitialized() { if (hasOriginalSubTree()) { if (!getOriginalSubTree().isInitialized()) { - + return false; } } if (hasUpdatedSubTree()) { if (!getUpdatedSubTree().isInitialized()) { - + return false; } } if (hasOriginalData()) { if (!getOriginalData().isInitialized()) { - + return false; } } if (hasUpdatedData()) { if (!getUpdatedData().isInitialized()) { - + return false; } } if (hasCreatedData()) { if (!getCreatedData().isInitialized()) { - + return false; } } for (int i = 0; i < getRemovedPathsCount(); i++) { if (!getRemovedPaths(i).isInitialized()) { - + return false; } } @@ -985,7 +985,7 @@ public final class DataChangeListenerMessages { * optional .org.opendaylight.controller.mdsal.Node originalSubTree = 1; */ private com.google.protobuf.SingleFieldBuilder< - org.opendaylight.controller.protobuff.messages.common.NormalizedNodeMessages.Node, org.opendaylight.controller.protobuff.messages.common.NormalizedNodeMessages.Node.Builder, org.opendaylight.controller.protobuff.messages.common.NormalizedNodeMessages.NodeOrBuilder> + org.opendaylight.controller.protobuff.messages.common.NormalizedNodeMessages.Node, org.opendaylight.controller.protobuff.messages.common.NormalizedNodeMessages.Node.Builder, org.opendaylight.controller.protobuff.messages.common.NormalizedNodeMessages.NodeOrBuilder> getOriginalSubTreeFieldBuilder() { if (originalSubTreeBuilder_ == null) { originalSubTreeBuilder_ = new com.google.protobuf.SingleFieldBuilder< @@ -1102,7 +1102,7 @@ public final class DataChangeListenerMessages { * optional .org.opendaylight.controller.mdsal.Node updatedSubTree = 2; */ private com.google.protobuf.SingleFieldBuilder< - org.opendaylight.controller.protobuff.messages.common.NormalizedNodeMessages.Node, org.opendaylight.controller.protobuff.messages.common.NormalizedNodeMessages.Node.Builder, org.opendaylight.controller.protobuff.messages.common.NormalizedNodeMessages.NodeOrBuilder> + org.opendaylight.controller.protobuff.messages.common.NormalizedNodeMessages.Node, org.opendaylight.controller.protobuff.messages.common.NormalizedNodeMessages.Node.Builder, org.opendaylight.controller.protobuff.messages.common.NormalizedNodeMessages.NodeOrBuilder> getUpdatedSubTreeFieldBuilder() { if (updatedSubTreeBuilder_ == null) { updatedSubTreeBuilder_ = new com.google.protobuf.SingleFieldBuilder< @@ -1219,7 +1219,7 @@ public final class DataChangeListenerMessages { * optional .org.opendaylight.controller.mdsal.NodeMap originalData = 3; */ private com.google.protobuf.SingleFieldBuilder< - org.opendaylight.controller.protobuff.messages.common.NormalizedNodeMessages.NodeMap, org.opendaylight.controller.protobuff.messages.common.NormalizedNodeMessages.NodeMap.Builder, org.opendaylight.controller.protobuff.messages.common.NormalizedNodeMessages.NodeMapOrBuilder> + org.opendaylight.controller.protobuff.messages.common.NormalizedNodeMessages.NodeMap, org.opendaylight.controller.protobuff.messages.common.NormalizedNodeMessages.NodeMap.Builder, org.opendaylight.controller.protobuff.messages.common.NormalizedNodeMessages.NodeMapOrBuilder> getOriginalDataFieldBuilder() { if (originalDataBuilder_ == null) { originalDataBuilder_ = new com.google.protobuf.SingleFieldBuilder< @@ -1336,7 +1336,7 @@ public final class DataChangeListenerMessages { * optional .org.opendaylight.controller.mdsal.NodeMap updatedData = 4; */ private com.google.protobuf.SingleFieldBuilder< - org.opendaylight.controller.protobuff.messages.common.NormalizedNodeMessages.NodeMap, org.opendaylight.controller.protobuff.messages.common.NormalizedNodeMessages.NodeMap.Builder, org.opendaylight.controller.protobuff.messages.common.NormalizedNodeMessages.NodeMapOrBuilder> + org.opendaylight.controller.protobuff.messages.common.NormalizedNodeMessages.NodeMap, org.opendaylight.controller.protobuff.messages.common.NormalizedNodeMessages.NodeMap.Builder, org.opendaylight.controller.protobuff.messages.common.NormalizedNodeMessages.NodeMapOrBuilder> getUpdatedDataFieldBuilder() { if (updatedDataBuilder_ == null) { updatedDataBuilder_ = new com.google.protobuf.SingleFieldBuilder< @@ -1453,7 +1453,7 @@ public final class DataChangeListenerMessages { * optional .org.opendaylight.controller.mdsal.NodeMap createdData = 5; */ private com.google.protobuf.SingleFieldBuilder< - org.opendaylight.controller.protobuff.messages.common.NormalizedNodeMessages.NodeMap, org.opendaylight.controller.protobuff.messages.common.NormalizedNodeMessages.NodeMap.Builder, org.opendaylight.controller.protobuff.messages.common.NormalizedNodeMessages.NodeMapOrBuilder> + org.opendaylight.controller.protobuff.messages.common.NormalizedNodeMessages.NodeMap, org.opendaylight.controller.protobuff.messages.common.NormalizedNodeMessages.NodeMap.Builder, org.opendaylight.controller.protobuff.messages.common.NormalizedNodeMessages.NodeMapOrBuilder> getCreatedDataFieldBuilder() { if (createdDataBuilder_ == null) { createdDataBuilder_ = new com.google.protobuf.SingleFieldBuilder< @@ -1661,7 +1661,7 @@ public final class DataChangeListenerMessages { /** * repeated .org.opendaylight.controller.mdsal.InstanceIdentifier removedPaths = 6; */ - public java.util.List + public java.util.List getRemovedPathsOrBuilderList() { if (removedPathsBuilder_ != null) { return removedPathsBuilder_.getMessageOrBuilderList(); @@ -1687,12 +1687,12 @@ public final class DataChangeListenerMessages { /** * repeated .org.opendaylight.controller.mdsal.InstanceIdentifier removedPaths = 6; */ - public java.util.List + public java.util.List getRemovedPathsBuilderList() { return getRemovedPathsFieldBuilder().getBuilderList(); } private com.google.protobuf.RepeatedFieldBuilder< - org.opendaylight.controller.protobuff.messages.common.NormalizedNodeMessages.InstanceIdentifier, org.opendaylight.controller.protobuff.messages.common.NormalizedNodeMessages.InstanceIdentifier.Builder, org.opendaylight.controller.protobuff.messages.common.NormalizedNodeMessages.InstanceIdentifierOrBuilder> + org.opendaylight.controller.protobuff.messages.common.NormalizedNodeMessages.InstanceIdentifier, org.opendaylight.controller.protobuff.messages.common.NormalizedNodeMessages.InstanceIdentifier.Builder, org.opendaylight.controller.protobuff.messages.common.NormalizedNodeMessages.InstanceIdentifierOrBuilder> getRemovedPathsFieldBuilder() { if (removedPathsBuilder_ == null) { removedPathsBuilder_ = new com.google.protobuf.RepeatedFieldBuilder< diff --git a/opendaylight/md-sal/sal-protocolbuffer-encoding/src/main/java/org/opendaylight/controller/protobuff/messages/persistent/PersistentMessages.java b/opendaylight/md-sal/sal-clustering-commons/src/main/java/org/opendaylight/controller/protobuff/messages/persistent/PersistentMessages.java similarity index 99% rename from opendaylight/md-sal/sal-protocolbuffer-encoding/src/main/java/org/opendaylight/controller/protobuff/messages/persistent/PersistentMessages.java rename to opendaylight/md-sal/sal-clustering-commons/src/main/java/org/opendaylight/controller/protobuff/messages/persistent/PersistentMessages.java index eaa90012db..d354348da8 100644 --- a/opendaylight/md-sal/sal-protocolbuffer-encoding/src/main/java/org/opendaylight/controller/protobuff/messages/persistent/PersistentMessages.java +++ b/opendaylight/md-sal/sal-clustering-commons/src/main/java/org/opendaylight/controller/protobuff/messages/persistent/PersistentMessages.java @@ -193,7 +193,7 @@ public final class PersistentMessages { if (ref instanceof java.lang.String) { return (java.lang.String) ref; } else { - com.google.protobuf.ByteString bs = + com.google.protobuf.ByteString bs = (com.google.protobuf.ByteString) ref; java.lang.String s = bs.toStringUtf8(); if (bs.isValidUtf8()) { @@ -209,7 +209,7 @@ public final class PersistentMessages { getTypeBytes() { java.lang.Object ref = type_; if (ref instanceof java.lang.String) { - com.google.protobuf.ByteString b = + com.google.protobuf.ByteString b = com.google.protobuf.ByteString.copyFromUtf8( (java.lang.String) ref); type_ = b; @@ -541,20 +541,20 @@ public final class PersistentMessages { public final boolean isInitialized() { if (!hasType()) { - + return false; } if (!hasPath()) { - + return false; } if (!getPath().isInitialized()) { - + return false; } if (hasData()) { if (!getData().isInitialized()) { - + return false; } } @@ -609,7 +609,7 @@ public final class PersistentMessages { getTypeBytes() { java.lang.Object ref = type_; if (ref instanceof String) { - com.google.protobuf.ByteString b = + com.google.protobuf.ByteString b = com.google.protobuf.ByteString.copyFromUtf8( (java.lang.String) ref); type_ = b; @@ -758,7 +758,7 @@ public final class PersistentMessages { * required .org.opendaylight.controller.mdsal.InstanceIdentifier path = 2; */ private com.google.protobuf.SingleFieldBuilder< - org.opendaylight.controller.protobuff.messages.common.NormalizedNodeMessages.InstanceIdentifier, org.opendaylight.controller.protobuff.messages.common.NormalizedNodeMessages.InstanceIdentifier.Builder, org.opendaylight.controller.protobuff.messages.common.NormalizedNodeMessages.InstanceIdentifierOrBuilder> + org.opendaylight.controller.protobuff.messages.common.NormalizedNodeMessages.InstanceIdentifier, org.opendaylight.controller.protobuff.messages.common.NormalizedNodeMessages.InstanceIdentifier.Builder, org.opendaylight.controller.protobuff.messages.common.NormalizedNodeMessages.InstanceIdentifierOrBuilder> getPathFieldBuilder() { if (pathBuilder_ == null) { pathBuilder_ = new com.google.protobuf.SingleFieldBuilder< @@ -875,7 +875,7 @@ public final class PersistentMessages { * optional .org.opendaylight.controller.mdsal.Node data = 3; */ private com.google.protobuf.SingleFieldBuilder< - org.opendaylight.controller.protobuff.messages.common.NormalizedNodeMessages.Node, org.opendaylight.controller.protobuff.messages.common.NormalizedNodeMessages.Node.Builder, org.opendaylight.controller.protobuff.messages.common.NormalizedNodeMessages.NodeOrBuilder> + org.opendaylight.controller.protobuff.messages.common.NormalizedNodeMessages.Node, org.opendaylight.controller.protobuff.messages.common.NormalizedNodeMessages.Node.Builder, org.opendaylight.controller.protobuff.messages.common.NormalizedNodeMessages.NodeOrBuilder> getDataFieldBuilder() { if (dataBuilder_ == null) { dataBuilder_ = new com.google.protobuf.SingleFieldBuilder< @@ -906,7 +906,7 @@ public final class PersistentMessages { /** * repeated .org.opendaylight.controller.mdsal.Modification modification = 1; */ - java.util.List + java.util.List getModificationList(); /** * repeated .org.opendaylight.controller.mdsal.Modification modification = 1; @@ -919,7 +919,7 @@ public final class PersistentMessages { /** * repeated .org.opendaylight.controller.mdsal.Modification modification = 1; */ - java.util.List + java.util.List getModificationOrBuilderList(); /** * repeated .org.opendaylight.controller.mdsal.Modification modification = 1; @@ -1040,7 +1040,7 @@ public final class PersistentMessages { /** * repeated .org.opendaylight.controller.mdsal.Modification modification = 1; */ - public java.util.List + public java.util.List getModificationOrBuilderList() { return modification_; } @@ -1293,7 +1293,7 @@ public final class PersistentMessages { modificationBuilder_ = null; modification_ = other.modification_; bitField0_ = (bitField0_ & ~0x00000001); - modificationBuilder_ = + modificationBuilder_ = com.google.protobuf.GeneratedMessage.alwaysUseFieldBuilders ? getModificationFieldBuilder() : null; } else { @@ -1308,7 +1308,7 @@ public final class PersistentMessages { public final boolean isInitialized() { for (int i = 0; i < getModificationCount(); i++) { if (!getModification(i).isInitialized()) { - + return false; } } @@ -1529,7 +1529,7 @@ public final class PersistentMessages { /** * repeated .org.opendaylight.controller.mdsal.Modification modification = 1; */ - public java.util.List + public java.util.List getModificationOrBuilderList() { if (modificationBuilder_ != null) { return modificationBuilder_.getMessageOrBuilderList(); @@ -1555,12 +1555,12 @@ public final class PersistentMessages { /** * repeated .org.opendaylight.controller.mdsal.Modification modification = 1; */ - public java.util.List + public java.util.List getModificationBuilderList() { return getModificationFieldBuilder().getBuilderList(); } private com.google.protobuf.RepeatedFieldBuilder< - org.opendaylight.controller.protobuff.messages.persistent.PersistentMessages.Modification, org.opendaylight.controller.protobuff.messages.persistent.PersistentMessages.Modification.Builder, org.opendaylight.controller.protobuff.messages.persistent.PersistentMessages.ModificationOrBuilder> + org.opendaylight.controller.protobuff.messages.persistent.PersistentMessages.Modification, org.opendaylight.controller.protobuff.messages.persistent.PersistentMessages.Modification.Builder, org.opendaylight.controller.protobuff.messages.persistent.PersistentMessages.ModificationOrBuilder> getModificationFieldBuilder() { if (modificationBuilder_ == null) { modificationBuilder_ = new com.google.protobuf.RepeatedFieldBuilder< diff --git a/opendaylight/md-sal/sal-protocolbuffer-encoding/src/main/java/org/opendaylight/controller/protobuff/messages/registration/ListenerRegistrationMessages.java b/opendaylight/md-sal/sal-clustering-commons/src/main/java/org/opendaylight/controller/protobuff/messages/registration/ListenerRegistrationMessages.java similarity index 99% rename from opendaylight/md-sal/sal-protocolbuffer-encoding/src/main/java/org/opendaylight/controller/protobuff/messages/registration/ListenerRegistrationMessages.java rename to opendaylight/md-sal/sal-clustering-commons/src/main/java/org/opendaylight/controller/protobuff/messages/registration/ListenerRegistrationMessages.java index e06dd0d429..77cbd4da46 100644 --- a/opendaylight/md-sal/sal-protocolbuffer-encoding/src/main/java/org/opendaylight/controller/protobuff/messages/registration/ListenerRegistrationMessages.java +++ b/opendaylight/md-sal/sal-clustering-commons/src/main/java/org/opendaylight/controller/protobuff/messages/registration/ListenerRegistrationMessages.java @@ -837,7 +837,7 @@ public final class ListenerRegistrationMessages { if (ref instanceof java.lang.String) { return (java.lang.String) ref; } else { - com.google.protobuf.ByteString bs = + com.google.protobuf.ByteString bs = (com.google.protobuf.ByteString) ref; java.lang.String s = bs.toStringUtf8(); if (bs.isValidUtf8()) { @@ -853,7 +853,7 @@ public final class ListenerRegistrationMessages { getDataChangeListenerActorPathBytes() { java.lang.Object ref = dataChangeListenerActorPath_; if (ref instanceof java.lang.String) { - com.google.protobuf.ByteString b = + com.google.protobuf.ByteString b = com.google.protobuf.ByteString.copyFromUtf8( (java.lang.String) ref); dataChangeListenerActorPath_ = b; @@ -1146,19 +1146,19 @@ public final class ListenerRegistrationMessages { public final boolean isInitialized() { if (!hasInstanceIdentifierPath()) { - + return false; } if (!hasDataChangeListenerActorPath()) { - + return false; } if (!hasDataChangeScope()) { - + return false; } if (!getInstanceIdentifierPath().isInitialized()) { - + return false; } return true; @@ -1287,7 +1287,7 @@ public final class ListenerRegistrationMessages { * required .org.opendaylight.controller.mdsal.InstanceIdentifier instanceIdentifierPath = 1; */ private com.google.protobuf.SingleFieldBuilder< - org.opendaylight.controller.protobuff.messages.common.NormalizedNodeMessages.InstanceIdentifier, org.opendaylight.controller.protobuff.messages.common.NormalizedNodeMessages.InstanceIdentifier.Builder, org.opendaylight.controller.protobuff.messages.common.NormalizedNodeMessages.InstanceIdentifierOrBuilder> + org.opendaylight.controller.protobuff.messages.common.NormalizedNodeMessages.InstanceIdentifier, org.opendaylight.controller.protobuff.messages.common.NormalizedNodeMessages.InstanceIdentifier.Builder, org.opendaylight.controller.protobuff.messages.common.NormalizedNodeMessages.InstanceIdentifierOrBuilder> getInstanceIdentifierPathFieldBuilder() { if (instanceIdentifierPathBuilder_ == null) { instanceIdentifierPathBuilder_ = new com.google.protobuf.SingleFieldBuilder< @@ -1329,7 +1329,7 @@ public final class ListenerRegistrationMessages { getDataChangeListenerActorPathBytes() { java.lang.Object ref = dataChangeListenerActorPath_; if (ref instanceof String) { - com.google.protobuf.ByteString b = + com.google.protobuf.ByteString b = com.google.protobuf.ByteString.copyFromUtf8( (java.lang.String) ref); dataChangeListenerActorPath_ = b; @@ -1556,7 +1556,7 @@ public final class ListenerRegistrationMessages { if (ref instanceof java.lang.String) { return (java.lang.String) ref; } else { - com.google.protobuf.ByteString bs = + com.google.protobuf.ByteString bs = (com.google.protobuf.ByteString) ref; java.lang.String s = bs.toStringUtf8(); if (bs.isValidUtf8()) { @@ -1572,7 +1572,7 @@ public final class ListenerRegistrationMessages { getListenerRegistrationPathBytes() { java.lang.Object ref = listenerRegistrationPath_; if (ref instanceof java.lang.String) { - com.google.protobuf.ByteString b = + com.google.protobuf.ByteString b = com.google.protobuf.ByteString.copyFromUtf8( (java.lang.String) ref); listenerRegistrationPath_ = b; @@ -1801,7 +1801,7 @@ public final class ListenerRegistrationMessages { public final boolean isInitialized() { if (!hasListenerRegistrationPath()) { - + return false; } return true; @@ -1855,7 +1855,7 @@ public final class ListenerRegistrationMessages { getListenerRegistrationPathBytes() { java.lang.Object ref = listenerRegistrationPath_; if (ref instanceof String) { - com.google.protobuf.ByteString b = + com.google.protobuf.ByteString b = com.google.protobuf.ByteString.copyFromUtf8( (java.lang.String) ref); listenerRegistrationPath_ = b; diff --git a/opendaylight/md-sal/sal-protocolbuffer-encoding/src/main/java/org/opendaylight/controller/protobuff/messages/shard/ShardManagerMessages.java b/opendaylight/md-sal/sal-clustering-commons/src/main/java/org/opendaylight/controller/protobuff/messages/shard/ShardManagerMessages.java similarity index 99% rename from opendaylight/md-sal/sal-protocolbuffer-encoding/src/main/java/org/opendaylight/controller/protobuff/messages/shard/ShardManagerMessages.java rename to opendaylight/md-sal/sal-clustering-commons/src/main/java/org/opendaylight/controller/protobuff/messages/shard/ShardManagerMessages.java index 7c2a47e1b0..2324dfc2a2 100644 --- a/opendaylight/md-sal/sal-protocolbuffer-encoding/src/main/java/org/opendaylight/controller/protobuff/messages/shard/ShardManagerMessages.java +++ b/opendaylight/md-sal/sal-clustering-commons/src/main/java/org/opendaylight/controller/protobuff/messages/shard/ShardManagerMessages.java @@ -139,7 +139,7 @@ public final class ShardManagerMessages { if (ref instanceof java.lang.String) { return (java.lang.String) ref; } else { - com.google.protobuf.ByteString bs = + com.google.protobuf.ByteString bs = (com.google.protobuf.ByteString) ref; java.lang.String s = bs.toStringUtf8(); if (bs.isValidUtf8()) { @@ -155,7 +155,7 @@ public final class ShardManagerMessages { getShardNameBytes() { java.lang.Object ref = shardName_; if (ref instanceof java.lang.String) { - com.google.protobuf.ByteString b = + com.google.protobuf.ByteString b = com.google.protobuf.ByteString.copyFromUtf8( (java.lang.String) ref); shardName_ = b; @@ -377,7 +377,7 @@ public final class ShardManagerMessages { public final boolean isInitialized() { if (!hasShardName()) { - + return false; } return true; @@ -431,7 +431,7 @@ public final class ShardManagerMessages { getShardNameBytes() { java.lang.Object ref = shardName_; if (ref instanceof String) { - com.google.protobuf.ByteString b = + com.google.protobuf.ByteString b = com.google.protobuf.ByteString.copyFromUtf8( (java.lang.String) ref); shardName_ = b; @@ -618,7 +618,7 @@ public final class ShardManagerMessages { if (ref instanceof java.lang.String) { return (java.lang.String) ref; } else { - com.google.protobuf.ByteString bs = + com.google.protobuf.ByteString bs = (com.google.protobuf.ByteString) ref; java.lang.String s = bs.toStringUtf8(); if (bs.isValidUtf8()) { @@ -634,7 +634,7 @@ public final class ShardManagerMessages { getPrimaryPathBytes() { java.lang.Object ref = primaryPath_; if (ref instanceof java.lang.String) { - com.google.protobuf.ByteString b = + com.google.protobuf.ByteString b = com.google.protobuf.ByteString.copyFromUtf8( (java.lang.String) ref); primaryPath_ = b; @@ -856,7 +856,7 @@ public final class ShardManagerMessages { public final boolean isInitialized() { if (!hasPrimaryPath()) { - + return false; } return true; @@ -910,7 +910,7 @@ public final class ShardManagerMessages { getPrimaryPathBytes() { java.lang.Object ref = primaryPath_; if (ref instanceof String) { - com.google.protobuf.ByteString b = + com.google.protobuf.ByteString b = com.google.protobuf.ByteString.copyFromUtf8( (java.lang.String) ref); primaryPath_ = b; @@ -1097,7 +1097,7 @@ public final class ShardManagerMessages { if (ref instanceof java.lang.String) { return (java.lang.String) ref; } else { - com.google.protobuf.ByteString bs = + com.google.protobuf.ByteString bs = (com.google.protobuf.ByteString) ref; java.lang.String s = bs.toStringUtf8(); if (bs.isValidUtf8()) { @@ -1113,7 +1113,7 @@ public final class ShardManagerMessages { getShardNameBytes() { java.lang.Object ref = shardName_; if (ref instanceof java.lang.String) { - com.google.protobuf.ByteString b = + com.google.protobuf.ByteString b = com.google.protobuf.ByteString.copyFromUtf8( (java.lang.String) ref); shardName_ = b; @@ -1335,7 +1335,7 @@ public final class ShardManagerMessages { public final boolean isInitialized() { if (!hasShardName()) { - + return false; } return true; @@ -1389,7 +1389,7 @@ public final class ShardManagerMessages { getShardNameBytes() { java.lang.Object ref = shardName_; if (ref instanceof String) { - com.google.protobuf.ByteString b = + com.google.protobuf.ByteString b = com.google.protobuf.ByteString.copyFromUtf8( (java.lang.String) ref); shardName_ = b; diff --git a/opendaylight/md-sal/sal-protocolbuffer-encoding/src/main/java/org/opendaylight/controller/protobuff/messages/transaction/ShardTransactionChainMessages.java b/opendaylight/md-sal/sal-clustering-commons/src/main/java/org/opendaylight/controller/protobuff/messages/transaction/ShardTransactionChainMessages.java similarity index 99% rename from opendaylight/md-sal/sal-protocolbuffer-encoding/src/main/java/org/opendaylight/controller/protobuff/messages/transaction/ShardTransactionChainMessages.java rename to opendaylight/md-sal/sal-clustering-commons/src/main/java/org/opendaylight/controller/protobuff/messages/transaction/ShardTransactionChainMessages.java index 3f354ba40e..63dd5e7081 100644 --- a/opendaylight/md-sal/sal-protocolbuffer-encoding/src/main/java/org/opendaylight/controller/protobuff/messages/transaction/ShardTransactionChainMessages.java +++ b/opendaylight/md-sal/sal-clustering-commons/src/main/java/org/opendaylight/controller/protobuff/messages/transaction/ShardTransactionChainMessages.java @@ -1066,7 +1066,7 @@ public final class ShardTransactionChainMessages { if (ref instanceof java.lang.String) { return (java.lang.String) ref; } else { - com.google.protobuf.ByteString bs = + com.google.protobuf.ByteString bs = (com.google.protobuf.ByteString) ref; java.lang.String s = bs.toStringUtf8(); if (bs.isValidUtf8()) { @@ -1082,7 +1082,7 @@ public final class ShardTransactionChainMessages { getTransactionChainPathBytes() { java.lang.Object ref = transactionChainPath_; if (ref instanceof java.lang.String) { - com.google.protobuf.ByteString b = + com.google.protobuf.ByteString b = com.google.protobuf.ByteString.copyFromUtf8( (java.lang.String) ref); transactionChainPath_ = b; @@ -1304,7 +1304,7 @@ public final class ShardTransactionChainMessages { public final boolean isInitialized() { if (!hasTransactionChainPath()) { - + return false; } return true; @@ -1358,7 +1358,7 @@ public final class ShardTransactionChainMessages { getTransactionChainPathBytes() { java.lang.Object ref = transactionChainPath_; if (ref instanceof String) { - com.google.protobuf.ByteString b = + com.google.protobuf.ByteString b = com.google.protobuf.ByteString.copyFromUtf8( (java.lang.String) ref); transactionChainPath_ = b; diff --git a/opendaylight/md-sal/sal-protocolbuffer-encoding/src/main/java/org/opendaylight/controller/protobuff/messages/transaction/ShardTransactionMessages.java b/opendaylight/md-sal/sal-clustering-commons/src/main/java/org/opendaylight/controller/protobuff/messages/transaction/ShardTransactionMessages.java similarity index 98% rename from opendaylight/md-sal/sal-protocolbuffer-encoding/src/main/java/org/opendaylight/controller/protobuff/messages/transaction/ShardTransactionMessages.java rename to opendaylight/md-sal/sal-clustering-commons/src/main/java/org/opendaylight/controller/protobuff/messages/transaction/ShardTransactionMessages.java index ee2c70423e..33ac9f6ca1 100644 --- a/opendaylight/md-sal/sal-protocolbuffer-encoding/src/main/java/org/opendaylight/controller/protobuff/messages/transaction/ShardTransactionMessages.java +++ b/opendaylight/md-sal/sal-clustering-commons/src/main/java/org/opendaylight/controller/protobuff/messages/transaction/ShardTransactionMessages.java @@ -643,6 +643,16 @@ public final class ShardTransactionMessages { */ com.google.protobuf.ByteString getTransactionIdBytes(); + + // required int32 transactionType = 2; + /** + * required int32 transactionType = 2; + */ + boolean hasTransactionType(); + /** + * required int32 transactionType = 2; + */ + int getTransactionType(); } /** * Protobuf type {@code org.opendaylight.controller.mdsal.CreateTransaction} @@ -700,6 +710,11 @@ public final class ShardTransactionMessages { transactionId_ = input.readBytes(); break; } + case 16: { + bitField0_ |= 0x00000002; + transactionType_ = input.readInt32(); + break; + } } } } catch (com.google.protobuf.InvalidProtocolBufferException e) { @@ -757,7 +772,7 @@ public final class ShardTransactionMessages { if (ref instanceof java.lang.String) { return (java.lang.String) ref; } else { - com.google.protobuf.ByteString bs = + com.google.protobuf.ByteString bs = (com.google.protobuf.ByteString) ref; java.lang.String s = bs.toStringUtf8(); if (bs.isValidUtf8()) { @@ -773,7 +788,7 @@ public final class ShardTransactionMessages { getTransactionIdBytes() { java.lang.Object ref = transactionId_; if (ref instanceof java.lang.String) { - com.google.protobuf.ByteString b = + com.google.protobuf.ByteString b = com.google.protobuf.ByteString.copyFromUtf8( (java.lang.String) ref); transactionId_ = b; @@ -783,8 +798,25 @@ public final class ShardTransactionMessages { } } + // required int32 transactionType = 2; + public static final int TRANSACTIONTYPE_FIELD_NUMBER = 2; + private int transactionType_; + /** + * required int32 transactionType = 2; + */ + public boolean hasTransactionType() { + return ((bitField0_ & 0x00000002) == 0x00000002); + } + /** + * required int32 transactionType = 2; + */ + public int getTransactionType() { + return transactionType_; + } + private void initFields() { transactionId_ = ""; + transactionType_ = 0; } private byte memoizedIsInitialized = -1; public final boolean isInitialized() { @@ -795,6 +827,10 @@ public final class ShardTransactionMessages { memoizedIsInitialized = 0; return false; } + if (!hasTransactionType()) { + memoizedIsInitialized = 0; + return false; + } memoizedIsInitialized = 1; return true; } @@ -805,6 +841,9 @@ public final class ShardTransactionMessages { if (((bitField0_ & 0x00000001) == 0x00000001)) { output.writeBytes(1, getTransactionIdBytes()); } + if (((bitField0_ & 0x00000002) == 0x00000002)) { + output.writeInt32(2, transactionType_); + } getUnknownFields().writeTo(output); } @@ -818,6 +857,10 @@ public final class ShardTransactionMessages { size += com.google.protobuf.CodedOutputStream .computeBytesSize(1, getTransactionIdBytes()); } + if (((bitField0_ & 0x00000002) == 0x00000002)) { + size += com.google.protobuf.CodedOutputStream + .computeInt32Size(2, transactionType_); + } size += getUnknownFields().getSerializedSize(); memoizedSerializedSize = size; return size; @@ -936,6 +979,8 @@ public final class ShardTransactionMessages { super.clear(); transactionId_ = ""; bitField0_ = (bitField0_ & ~0x00000001); + transactionType_ = 0; + bitField0_ = (bitField0_ & ~0x00000002); return this; } @@ -968,6 +1013,10 @@ public final class ShardTransactionMessages { to_bitField0_ |= 0x00000001; } result.transactionId_ = transactionId_; + if (((from_bitField0_ & 0x00000002) == 0x00000002)) { + to_bitField0_ |= 0x00000002; + } + result.transactionType_ = transactionType_; result.bitField0_ = to_bitField0_; onBuilt(); return result; @@ -989,13 +1038,20 @@ public final class ShardTransactionMessages { transactionId_ = other.transactionId_; onChanged(); } + if (other.hasTransactionType()) { + setTransactionType(other.getTransactionType()); + } this.mergeUnknownFields(other.getUnknownFields()); return this; } public final boolean isInitialized() { if (!hasTransactionId()) { - + + return false; + } + if (!hasTransactionType()) { + return false; } return true; @@ -1049,7 +1105,7 @@ public final class ShardTransactionMessages { getTransactionIdBytes() { java.lang.Object ref = transactionId_; if (ref instanceof String) { - com.google.protobuf.ByteString b = + com.google.protobuf.ByteString b = com.google.protobuf.ByteString.copyFromUtf8( (java.lang.String) ref); transactionId_ = b; @@ -1094,6 +1150,39 @@ public final class ShardTransactionMessages { return this; } + // required int32 transactionType = 2; + private int transactionType_ ; + /** + * required int32 transactionType = 2; + */ + public boolean hasTransactionType() { + return ((bitField0_ & 0x00000002) == 0x00000002); + } + /** + * required int32 transactionType = 2; + */ + public int getTransactionType() { + return transactionType_; + } + /** + * required int32 transactionType = 2; + */ + public Builder setTransactionType(int value) { + bitField0_ |= 0x00000002; + transactionType_ = value; + onChanged(); + return this; + } + /** + * required int32 transactionType = 2; + */ + public Builder clearTransactionType() { + bitField0_ = (bitField0_ & ~0x00000002); + transactionType_ = 0; + onChanged(); + return this; + } + // @@protoc_insertion_point(builder_scope:org.opendaylight.controller.mdsal.CreateTransaction) } @@ -1256,7 +1345,7 @@ public final class ShardTransactionMessages { if (ref instanceof java.lang.String) { return (java.lang.String) ref; } else { - com.google.protobuf.ByteString bs = + com.google.protobuf.ByteString bs = (com.google.protobuf.ByteString) ref; java.lang.String s = bs.toStringUtf8(); if (bs.isValidUtf8()) { @@ -1272,7 +1361,7 @@ public final class ShardTransactionMessages { getTransactionActorPathBytes() { java.lang.Object ref = transactionActorPath_; if (ref instanceof java.lang.String) { - com.google.protobuf.ByteString b = + com.google.protobuf.ByteString b = com.google.protobuf.ByteString.copyFromUtf8( (java.lang.String) ref); transactionActorPath_ = b; @@ -1299,7 +1388,7 @@ public final class ShardTransactionMessages { if (ref instanceof java.lang.String) { return (java.lang.String) ref; } else { - com.google.protobuf.ByteString bs = + com.google.protobuf.ByteString bs = (com.google.protobuf.ByteString) ref; java.lang.String s = bs.toStringUtf8(); if (bs.isValidUtf8()) { @@ -1315,7 +1404,7 @@ public final class ShardTransactionMessages { getTransactionIdBytes() { java.lang.Object ref = transactionId_; if (ref instanceof java.lang.String) { - com.google.protobuf.ByteString b = + com.google.protobuf.ByteString b = com.google.protobuf.ByteString.copyFromUtf8( (java.lang.String) ref); transactionId_ = b; @@ -1560,11 +1649,11 @@ public final class ShardTransactionMessages { public final boolean isInitialized() { if (!hasTransactionActorPath()) { - + return false; } if (!hasTransactionId()) { - + return false; } return true; @@ -1618,7 +1707,7 @@ public final class ShardTransactionMessages { getTransactionActorPathBytes() { java.lang.Object ref = transactionActorPath_; if (ref instanceof String) { - com.google.protobuf.ByteString b = + com.google.protobuf.ByteString b = com.google.protobuf.ByteString.copyFromUtf8( (java.lang.String) ref); transactionActorPath_ = b; @@ -1692,7 +1781,7 @@ public final class ShardTransactionMessages { getTransactionIdBytes() { java.lang.Object ref = transactionId_; if (ref instanceof String) { - com.google.protobuf.ByteString b = + com.google.protobuf.ByteString b = com.google.protobuf.ByteString.copyFromUtf8( (java.lang.String) ref); transactionId_ = b; @@ -2188,7 +2277,7 @@ public final class ShardTransactionMessages { if (ref instanceof java.lang.String) { return (java.lang.String) ref; } else { - com.google.protobuf.ByteString bs = + com.google.protobuf.ByteString bs = (com.google.protobuf.ByteString) ref; java.lang.String s = bs.toStringUtf8(); if (bs.isValidUtf8()) { @@ -2204,7 +2293,7 @@ public final class ShardTransactionMessages { getActorPathBytes() { java.lang.Object ref = actorPath_; if (ref instanceof java.lang.String) { - com.google.protobuf.ByteString b = + com.google.protobuf.ByteString b = com.google.protobuf.ByteString.copyFromUtf8( (java.lang.String) ref); actorPath_ = b; @@ -2426,7 +2515,7 @@ public final class ShardTransactionMessages { public final boolean isInitialized() { if (!hasActorPath()) { - + return false; } return true; @@ -2480,7 +2569,7 @@ public final class ShardTransactionMessages { getActorPathBytes() { java.lang.Object ref = actorPath_; if (ref instanceof String) { - com.google.protobuf.ByteString b = + com.google.protobuf.ByteString b = com.google.protobuf.ByteString.copyFromUtf8( (java.lang.String) ref); actorPath_ = b; @@ -2902,11 +2991,11 @@ public final class ShardTransactionMessages { public final boolean isInitialized() { if (!hasInstanceIdentifierPathArguments()) { - + return false; } if (!getInstanceIdentifierPathArguments().isInitialized()) { - + return false; } return true; @@ -3035,7 +3124,7 @@ public final class ShardTransactionMessages { * required .org.opendaylight.controller.mdsal.InstanceIdentifier instanceIdentifierPathArguments = 1; */ private com.google.protobuf.SingleFieldBuilder< - org.opendaylight.controller.protobuff.messages.common.NormalizedNodeMessages.InstanceIdentifier, org.opendaylight.controller.protobuff.messages.common.NormalizedNodeMessages.InstanceIdentifier.Builder, org.opendaylight.controller.protobuff.messages.common.NormalizedNodeMessages.InstanceIdentifierOrBuilder> + org.opendaylight.controller.protobuff.messages.common.NormalizedNodeMessages.InstanceIdentifier, org.opendaylight.controller.protobuff.messages.common.NormalizedNodeMessages.InstanceIdentifier.Builder, org.opendaylight.controller.protobuff.messages.common.NormalizedNodeMessages.InstanceIdentifierOrBuilder> getInstanceIdentifierPathArgumentsFieldBuilder() { if (instanceIdentifierPathArgumentsBuilder_ == null) { instanceIdentifierPathArgumentsBuilder_ = new com.google.protobuf.SingleFieldBuilder< @@ -3734,11 +3823,11 @@ public final class ShardTransactionMessages { public final boolean isInitialized() { if (!hasInstanceIdentifierPathArguments()) { - + return false; } if (!getInstanceIdentifierPathArguments().isInitialized()) { - + return false; } return true; @@ -3867,7 +3956,7 @@ public final class ShardTransactionMessages { * required .org.opendaylight.controller.mdsal.InstanceIdentifier instanceIdentifierPathArguments = 1; */ private com.google.protobuf.SingleFieldBuilder< - org.opendaylight.controller.protobuff.messages.common.NormalizedNodeMessages.InstanceIdentifier, org.opendaylight.controller.protobuff.messages.common.NormalizedNodeMessages.InstanceIdentifier.Builder, org.opendaylight.controller.protobuff.messages.common.NormalizedNodeMessages.InstanceIdentifierOrBuilder> + org.opendaylight.controller.protobuff.messages.common.NormalizedNodeMessages.InstanceIdentifier, org.opendaylight.controller.protobuff.messages.common.NormalizedNodeMessages.InstanceIdentifier.Builder, org.opendaylight.controller.protobuff.messages.common.NormalizedNodeMessages.InstanceIdentifierOrBuilder> getInstanceIdentifierPathArgumentsFieldBuilder() { if (instanceIdentifierPathArgumentsBuilder_ == null) { instanceIdentifierPathArgumentsBuilder_ = new com.google.protobuf.SingleFieldBuilder< @@ -4256,7 +4345,7 @@ public final class ShardTransactionMessages { public final boolean isInitialized() { if (hasNormalizedNode()) { if (!getNormalizedNode().isInitialized()) { - + return false; } } @@ -4386,7 +4475,7 @@ public final class ShardTransactionMessages { * optional .org.opendaylight.controller.mdsal.Node normalizedNode = 1; */ private com.google.protobuf.SingleFieldBuilder< - org.opendaylight.controller.protobuff.messages.common.NormalizedNodeMessages.Node, org.opendaylight.controller.protobuff.messages.common.NormalizedNodeMessages.Node.Builder, org.opendaylight.controller.protobuff.messages.common.NormalizedNodeMessages.NodeOrBuilder> + org.opendaylight.controller.protobuff.messages.common.NormalizedNodeMessages.Node, org.opendaylight.controller.protobuff.messages.common.NormalizedNodeMessages.Node.Builder, org.opendaylight.controller.protobuff.messages.common.NormalizedNodeMessages.NodeOrBuilder> getNormalizedNodeFieldBuilder() { if (normalizedNodeBuilder_ == null) { normalizedNodeBuilder_ = new com.google.protobuf.SingleFieldBuilder< @@ -4859,19 +4948,19 @@ public final class ShardTransactionMessages { public final boolean isInitialized() { if (!hasInstanceIdentifierPathArguments()) { - + return false; } if (!hasNormalizedNode()) { - + return false; } if (!getInstanceIdentifierPathArguments().isInitialized()) { - + return false; } if (!getNormalizedNode().isInitialized()) { - + return false; } return true; @@ -5000,7 +5089,7 @@ public final class ShardTransactionMessages { * required .org.opendaylight.controller.mdsal.InstanceIdentifier instanceIdentifierPathArguments = 1; */ private com.google.protobuf.SingleFieldBuilder< - org.opendaylight.controller.protobuff.messages.common.NormalizedNodeMessages.InstanceIdentifier, org.opendaylight.controller.protobuff.messages.common.NormalizedNodeMessages.InstanceIdentifier.Builder, org.opendaylight.controller.protobuff.messages.common.NormalizedNodeMessages.InstanceIdentifierOrBuilder> + org.opendaylight.controller.protobuff.messages.common.NormalizedNodeMessages.InstanceIdentifier, org.opendaylight.controller.protobuff.messages.common.NormalizedNodeMessages.InstanceIdentifier.Builder, org.opendaylight.controller.protobuff.messages.common.NormalizedNodeMessages.InstanceIdentifierOrBuilder> getInstanceIdentifierPathArgumentsFieldBuilder() { if (instanceIdentifierPathArgumentsBuilder_ == null) { instanceIdentifierPathArgumentsBuilder_ = new com.google.protobuf.SingleFieldBuilder< @@ -5117,7 +5206,7 @@ public final class ShardTransactionMessages { * required .org.opendaylight.controller.mdsal.Node normalizedNode = 2; */ private com.google.protobuf.SingleFieldBuilder< - org.opendaylight.controller.protobuff.messages.common.NormalizedNodeMessages.Node, org.opendaylight.controller.protobuff.messages.common.NormalizedNodeMessages.Node.Builder, org.opendaylight.controller.protobuff.messages.common.NormalizedNodeMessages.NodeOrBuilder> + org.opendaylight.controller.protobuff.messages.common.NormalizedNodeMessages.Node, org.opendaylight.controller.protobuff.messages.common.NormalizedNodeMessages.Node.Builder, org.opendaylight.controller.protobuff.messages.common.NormalizedNodeMessages.NodeOrBuilder> getNormalizedNodeFieldBuilder() { if (normalizedNodeBuilder_ == null) { normalizedNodeBuilder_ = new com.google.protobuf.SingleFieldBuilder< @@ -5899,19 +5988,19 @@ public final class ShardTransactionMessages { public final boolean isInitialized() { if (!hasInstanceIdentifierPathArguments()) { - + return false; } if (!hasNormalizedNode()) { - + return false; } if (!getInstanceIdentifierPathArguments().isInitialized()) { - + return false; } if (!getNormalizedNode().isInitialized()) { - + return false; } return true; @@ -6040,7 +6129,7 @@ public final class ShardTransactionMessages { * required .org.opendaylight.controller.mdsal.InstanceIdentifier instanceIdentifierPathArguments = 1; */ private com.google.protobuf.SingleFieldBuilder< - org.opendaylight.controller.protobuff.messages.common.NormalizedNodeMessages.InstanceIdentifier, org.opendaylight.controller.protobuff.messages.common.NormalizedNodeMessages.InstanceIdentifier.Builder, org.opendaylight.controller.protobuff.messages.common.NormalizedNodeMessages.InstanceIdentifierOrBuilder> + org.opendaylight.controller.protobuff.messages.common.NormalizedNodeMessages.InstanceIdentifier, org.opendaylight.controller.protobuff.messages.common.NormalizedNodeMessages.InstanceIdentifier.Builder, org.opendaylight.controller.protobuff.messages.common.NormalizedNodeMessages.InstanceIdentifierOrBuilder> getInstanceIdentifierPathArgumentsFieldBuilder() { if (instanceIdentifierPathArgumentsBuilder_ == null) { instanceIdentifierPathArgumentsBuilder_ = new com.google.protobuf.SingleFieldBuilder< @@ -6157,7 +6246,7 @@ public final class ShardTransactionMessages { * required .org.opendaylight.controller.mdsal.Node normalizedNode = 2; */ private com.google.protobuf.SingleFieldBuilder< - org.opendaylight.controller.protobuff.messages.common.NormalizedNodeMessages.Node, org.opendaylight.controller.protobuff.messages.common.NormalizedNodeMessages.Node.Builder, org.opendaylight.controller.protobuff.messages.common.NormalizedNodeMessages.NodeOrBuilder> + org.opendaylight.controller.protobuff.messages.common.NormalizedNodeMessages.Node, org.opendaylight.controller.protobuff.messages.common.NormalizedNodeMessages.Node.Builder, org.opendaylight.controller.protobuff.messages.common.NormalizedNodeMessages.NodeOrBuilder> getNormalizedNodeFieldBuilder() { if (normalizedNodeBuilder_ == null) { normalizedNodeBuilder_ = new com.google.protobuf.SingleFieldBuilder< @@ -6571,32 +6660,33 @@ public final class ShardTransactionMessages { java.lang.String[] descriptorData = { "\n\026ShardTransaction.proto\022!org.opendaylig" + "ht.controller.mdsal\032\014Common.proto\"\022\n\020Clo" + - "seTransaction\"\027\n\025CloseTransactionReply\"*" + + "seTransaction\"\027\n\025CloseTransactionReply\"C" + "\n\021CreateTransaction\022\025\n\rtransactionId\030\001 \002" + - "(\t\"M\n\026CreateTransactionReply\022\034\n\024transact" + - "ionActorPath\030\001 \002(\t\022\025\n\rtransactionId\030\002 \002(" + - "\t\"\022\n\020ReadyTransaction\"*\n\025ReadyTransactio" + - "nReply\022\021\n\tactorPath\030\001 \002(\t\"l\n\nDeleteData\022" + - "^\n\037instanceIdentifierPathArguments\030\001 \002(\013" + - "25.org.opendaylight.controller.mdsal.Ins", - "tanceIdentifier\"\021\n\017DeleteDataReply\"j\n\010Re" + - "adData\022^\n\037instanceIdentifierPathArgument" + - "s\030\001 \002(\01325.org.opendaylight.controller.md" + - "sal.InstanceIdentifier\"P\n\rReadDataReply\022" + - "?\n\016normalizedNode\030\001 \001(\0132\'.org.opendaylig" + - "ht.controller.mdsal.Node\"\254\001\n\tWriteData\022^" + - "\n\037instanceIdentifierPathArguments\030\001 \002(\0132" + - "5.org.opendaylight.controller.mdsal.Inst" + - "anceIdentifier\022?\n\016normalizedNode\030\002 \002(\0132\'" + - ".org.opendaylight.controller.mdsal.Node\"", - "\020\n\016WriteDataReply\"\254\001\n\tMergeData\022^\n\037insta" + + "(\t\022\027\n\017transactionType\030\002 \002(\005\"M\n\026CreateTra" + + "nsactionReply\022\034\n\024transactionActorPath\030\001 " + + "\002(\t\022\025\n\rtransactionId\030\002 \002(\t\"\022\n\020ReadyTrans" + + "action\"*\n\025ReadyTransactionReply\022\021\n\tactor" + + "Path\030\001 \002(\t\"l\n\nDeleteData\022^\n\037instanceIden" + + "tifierPathArguments\030\001 \002(\01325.org.opendayl", + "ight.controller.mdsal.InstanceIdentifier" + + "\"\021\n\017DeleteDataReply\"j\n\010ReadData\022^\n\037insta" + "nceIdentifierPathArguments\030\001 \002(\01325.org.o" + "pendaylight.controller.mdsal.InstanceIde" + - "ntifier\022?\n\016normalizedNode\030\002 \002(\0132\'.org.op" + - "endaylight.controller.mdsal.Node\"\020\n\016Merg" + - "eDataReplyBV\n:org.opendaylight.controlle" + - "r.protobuff.messages.transactionB\030ShardT" + - "ransactionMessages" + "ntifier\"P\n\rReadDataReply\022?\n\016normalizedNo" + + "de\030\001 \001(\0132\'.org.opendaylight.controller.m" + + "dsal.Node\"\254\001\n\tWriteData\022^\n\037instanceIdent" + + "ifierPathArguments\030\001 \002(\01325.org.opendayli" + + "ght.controller.mdsal.InstanceIdentifier\022" + + "?\n\016normalizedNode\030\002 \002(\0132\'.org.opendaylig", + "ht.controller.mdsal.Node\"\020\n\016WriteDataRep" + + "ly\"\254\001\n\tMergeData\022^\n\037instanceIdentifierPa" + + "thArguments\030\001 \002(\01325.org.opendaylight.con" + + "troller.mdsal.InstanceIdentifier\022?\n\016norm" + + "alizedNode\030\002 \002(\0132\'.org.opendaylight.cont" + + "roller.mdsal.Node\"\020\n\016MergeDataReplyBV\n:o" + + "rg.opendaylight.controller.protobuff.mes" + + "sages.transactionB\030ShardTransactionMessa" + + "ges" }; com.google.protobuf.Descriptors.FileDescriptor.InternalDescriptorAssigner assigner = new com.google.protobuf.Descriptors.FileDescriptor.InternalDescriptorAssigner() { @@ -6620,7 +6710,7 @@ public final class ShardTransactionMessages { internal_static_org_opendaylight_controller_mdsal_CreateTransaction_fieldAccessorTable = new com.google.protobuf.GeneratedMessage.FieldAccessorTable( internal_static_org_opendaylight_controller_mdsal_CreateTransaction_descriptor, - new java.lang.String[] { "TransactionId", }); + new java.lang.String[] { "TransactionId", "TransactionType", }); internal_static_org_opendaylight_controller_mdsal_CreateTransactionReply_descriptor = getDescriptor().getMessageTypes().get(3); internal_static_org_opendaylight_controller_mdsal_CreateTransactionReply_fieldAccessorTable = new diff --git a/opendaylight/md-sal/sal-protocolbuffer-encoding/src/main/resources/Cohort.proto b/opendaylight/md-sal/sal-clustering-commons/src/main/resources/Cohort.proto similarity index 100% rename from opendaylight/md-sal/sal-protocolbuffer-encoding/src/main/resources/Cohort.proto rename to opendaylight/md-sal/sal-clustering-commons/src/main/resources/Cohort.proto diff --git a/opendaylight/md-sal/sal-protocolbuffer-encoding/src/main/resources/Common.proto b/opendaylight/md-sal/sal-clustering-commons/src/main/resources/Common.proto similarity index 100% rename from opendaylight/md-sal/sal-protocolbuffer-encoding/src/main/resources/Common.proto rename to opendaylight/md-sal/sal-clustering-commons/src/main/resources/Common.proto diff --git a/opendaylight/md-sal/sal-protocolbuffer-encoding/src/main/resources/CompositeModificationPayload.proto b/opendaylight/md-sal/sal-clustering-commons/src/main/resources/CompositeModificationPayload.proto similarity index 100% rename from opendaylight/md-sal/sal-protocolbuffer-encoding/src/main/resources/CompositeModificationPayload.proto rename to opendaylight/md-sal/sal-clustering-commons/src/main/resources/CompositeModificationPayload.proto diff --git a/opendaylight/md-sal/sal-protocolbuffer-encoding/src/main/resources/DataChangeListener.proto b/opendaylight/md-sal/sal-clustering-commons/src/main/resources/DataChangeListener.proto similarity index 100% rename from opendaylight/md-sal/sal-protocolbuffer-encoding/src/main/resources/DataChangeListener.proto rename to opendaylight/md-sal/sal-clustering-commons/src/main/resources/DataChangeListener.proto diff --git a/opendaylight/md-sal/sal-protocolbuffer-encoding/src/main/resources/ListenerRegistration.proto b/opendaylight/md-sal/sal-clustering-commons/src/main/resources/ListenerRegistration.proto similarity index 100% rename from opendaylight/md-sal/sal-protocolbuffer-encoding/src/main/resources/ListenerRegistration.proto rename to opendaylight/md-sal/sal-clustering-commons/src/main/resources/ListenerRegistration.proto diff --git a/opendaylight/md-sal/sal-protocolbuffer-encoding/src/main/resources/Persistent.proto b/opendaylight/md-sal/sal-clustering-commons/src/main/resources/Persistent.proto similarity index 100% rename from opendaylight/md-sal/sal-protocolbuffer-encoding/src/main/resources/Persistent.proto rename to opendaylight/md-sal/sal-clustering-commons/src/main/resources/Persistent.proto diff --git a/opendaylight/md-sal/sal-protocolbuffer-encoding/src/main/resources/ShardManager.proto b/opendaylight/md-sal/sal-clustering-commons/src/main/resources/ShardManager.proto similarity index 100% rename from opendaylight/md-sal/sal-protocolbuffer-encoding/src/main/resources/ShardManager.proto rename to opendaylight/md-sal/sal-clustering-commons/src/main/resources/ShardManager.proto diff --git a/opendaylight/md-sal/sal-protocolbuffer-encoding/src/main/resources/ShardTransaction.proto b/opendaylight/md-sal/sal-clustering-commons/src/main/resources/ShardTransaction.proto similarity index 96% rename from opendaylight/md-sal/sal-protocolbuffer-encoding/src/main/resources/ShardTransaction.proto rename to opendaylight/md-sal/sal-clustering-commons/src/main/resources/ShardTransaction.proto index 9684b7d72f..4177bd7a05 100644 --- a/opendaylight/md-sal/sal-protocolbuffer-encoding/src/main/resources/ShardTransaction.proto +++ b/opendaylight/md-sal/sal-clustering-commons/src/main/resources/ShardTransaction.proto @@ -14,6 +14,7 @@ message CloseTransactionReply{ message CreateTransaction{ required string transactionId = 1; + required int32 transactionType =2; } message CreateTransactionReply{ diff --git a/opendaylight/md-sal/sal-protocolbuffer-encoding/src/main/resources/ShardTransactionChain.proto b/opendaylight/md-sal/sal-clustering-commons/src/main/resources/ShardTransactionChain.proto similarity index 100% rename from opendaylight/md-sal/sal-protocolbuffer-encoding/src/main/resources/ShardTransactionChain.proto rename to opendaylight/md-sal/sal-clustering-commons/src/main/resources/ShardTransactionChain.proto diff --git a/opendaylight/md-sal/sal-protocolbuffer-encoding/src/main/resources/SimpleNormalizedNode.proto b/opendaylight/md-sal/sal-clustering-commons/src/main/resources/SimpleNormalizedNode.proto similarity index 100% rename from opendaylight/md-sal/sal-protocolbuffer-encoding/src/main/resources/SimpleNormalizedNode.proto rename to opendaylight/md-sal/sal-clustering-commons/src/main/resources/SimpleNormalizedNode.proto diff --git a/opendaylight/md-sal/sal-clustering-commons/src/test/java/org/opendaylight/controller/cluster/datastore/node/NormalizedNodeToNodeCodecTest.java b/opendaylight/md-sal/sal-clustering-commons/src/test/java/org/opendaylight/controller/cluster/datastore/node/NormalizedNodeToNodeCodecTest.java new file mode 100644 index 0000000000..1b85d46fc6 --- /dev/null +++ b/opendaylight/md-sal/sal-clustering-commons/src/test/java/org/opendaylight/controller/cluster/datastore/node/NormalizedNodeToNodeCodecTest.java @@ -0,0 +1,180 @@ +/* + * + * 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.cluster.datastore.node; + +import junit.framework.Assert; +import org.junit.Before; +import org.junit.Test; +import org.opendaylight.controller.cluster.datastore.node.utils.NodeIdentifierFactory; +import org.opendaylight.controller.cluster.datastore.node.utils.NormalizedNodeGetter; +import org.opendaylight.controller.cluster.datastore.node.utils.NormalizedNodeNavigator; +import org.opendaylight.controller.cluster.datastore.util.TestModel; +import org.opendaylight.controller.protobuff.messages.common.NormalizedNodeMessages.Container; +import org.opendaylight.controller.protobuff.messages.common.NormalizedNodeMessages.Node; +import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier; +import org.opendaylight.yangtools.yang.data.api.schema.MapEntryNode; +import org.opendaylight.yangtools.yang.data.api.schema.NormalizedNode; +import org.opendaylight.yangtools.yang.model.api.SchemaContext; + +import java.util.ArrayList; +import java.util.List; + +import static junit.framework.Assert.assertEquals; +import static junit.framework.Assert.assertNotNull; + +public class NormalizedNodeToNodeCodecTest { + + + + private SchemaContext schemaContext; + + @Before + public void setUp() { + schemaContext = TestModel.createTestContext(); + assertNotNull("Schema context must not be null.", schemaContext); + } + + private YangInstanceIdentifier instanceIdentifierFromString(String s) { + + String[] ids = s.split("/"); + + List pathArguments = new ArrayList<>(); + for (String nodeId : ids) { + if (!"".equals(nodeId)) { + pathArguments.add(NodeIdentifierFactory.getArgument(nodeId)); + } + } + final YangInstanceIdentifier instanceIdentifier = + YangInstanceIdentifier.create(pathArguments); + return instanceIdentifier; + } + + + @Test + public void testNormalizeNodeAttributesToProtoBuffNode() { + final NormalizedNode documentOne = TestModel.createTestContainer(); + String id = + "/(urn:opendaylight:params:xml:ns:yang:controller:md:sal:dom:store:test?revision=2014-03-13)test" + + "/(urn:opendaylight:params:xml:ns:yang:controller:md:sal:dom:store:test?revision=2014-03-13)outer-list" + + "/(urn:opendaylight:params:xml:ns:yang:controller:md:sal:dom:store:test?revision=2014-03-13)outer-list[{(urn:opendaylight:params:xml:ns:yang:controller:md:sal:dom:store:test?revision=2014-03-13)id=2}]" + + "/(urn:opendaylight:params:xml:ns:yang:controller:md:sal:dom:store:test?revision=2014-03-13)id"; + + NormalizedNodeGetter normalizedNodeGetter = new NormalizedNodeGetter(id); + new NormalizedNodeNavigator(normalizedNodeGetter).navigate( + YangInstanceIdentifier.builder().build().toString(), documentOne); + + // Validate the value of id can be retrieved from the normalized node + NormalizedNode output = normalizedNodeGetter.getOutput(); + assertNotNull(output); + + + NormalizedNodeToNodeCodec codec = + new NormalizedNodeToNodeCodec(schemaContext); + Container container = + codec.encode(instanceIdentifierFromString(id), output); + + assertNotNull(container); + assertEquals(id, container.getParentPath() + "/" + + container.getNormalizedNode().getPath()); + + // Decode the normalized node from the ProtocolBuffer form + // first get the node representation of normalized node + final Node node = container.getNormalizedNode(); + + NormalizedNode normalizedNode = + codec.decode(instanceIdentifierFromString(id), node); + + assertEquals(normalizedNode.getValue().toString(), output.getValue() + .toString()); + } + + @Test + public void testThatANormalizedNodeToProtoBuffNodeEncodeDecode() + throws Exception { + final NormalizedNode documentOne = TestModel.createTestContainer(); + + final NormalizedNodeToNodeCodec normalizedNodeToNodeCodec = + new NormalizedNodeToNodeCodec(schemaContext); + + Container container = + normalizedNodeToNodeCodec.encode(YangInstanceIdentifier.builder() + .build(), documentOne); + + + final NormalizedNode decode = + normalizedNodeToNodeCodec + .decode( + instanceIdentifierFromString("/(urn:opendaylight:params:xml:ns:yang:controller:md:sal:dom:store:test?revision=2014-03-13)test"), + container.getNormalizedNode()); + assertNotNull(decode != null); + + // let us ensure that the return decode normalized node encode returns same container + Container containerResult = + normalizedNodeToNodeCodec.encode(YangInstanceIdentifier.builder() + .build(), decode); + + assertEquals(container.getParentPath(), containerResult.getParentPath()); + assertEquals(container.getNormalizedNode().getChildCount(), container + .getNormalizedNode().getChildCount()); + + Assert.assertEquals(containerResult.getNormalizedNode().getChildCount(), + container.getNormalizedNode().getChildCount()); + + // check first level children are proper + List childrenResult = + containerResult.getNormalizedNode().getChildList(); + List childrenOriginal = container.getNormalizedNode().getChildList(); + + System.out.println("-------------------------------------------------"); + + System.out.println(childrenOriginal.toString()); + + System.out.println("-------------------------------------------------"); + + System.out.println(childrenResult.toString()); + + boolean bFound; + for (Node resultChild : childrenResult) { + bFound = false; + for (Node originalChild : childrenOriginal) { + if (originalChild.getPath().equals(resultChild.getPath()) + && resultChild.getType().equals(resultChild.getType())) { + bFound = true; + break; + } + } + Assert.assertTrue(bFound); + } + + } + + @Test + public void addAugmentations() { + String stringId = + "/(urn:opendaylight:params:xml:ns:yang:controller:md:sal:dom:store:test?revision=2014-03-13)test" + + "/(urn:opendaylight:params:xml:ns:yang:controller:md:sal:dom:store:test?revision=2014-03-13)augmented-list" + + "/(urn:opendaylight:params:xml:ns:yang:controller:md:sal:dom:store:test?revision=2014-03-13)augmented-list[{(urn:opendaylight:params:xml:ns:yang:controller:md:sal:dom:store:test?revision=2014-03-13)id=1}]"; + + YangInstanceIdentifier identifier = instanceIdentifierFromString(stringId); + + MapEntryNode uno = TestModel.createAugmentedListEntry(1, "Uno"); + + NormalizedNodeToNodeCodec codec = + new NormalizedNodeToNodeCodec(schemaContext); + + Container encode = codec.encode(identifier, uno); + + System.out.println(encode.getNormalizedNode()); + + codec.decode(identifier, encode.getNormalizedNode()); + } + +} diff --git a/opendaylight/md-sal/sal-clustering-commons/src/test/java/org/opendaylight/controller/cluster/datastore/node/utils/NodeIdentifierFactoryTest.java b/opendaylight/md-sal/sal-clustering-commons/src/test/java/org/opendaylight/controller/cluster/datastore/node/utils/NodeIdentifierFactoryTest.java new file mode 100644 index 0000000000..4da7d8c483 --- /dev/null +++ b/opendaylight/md-sal/sal-clustering-commons/src/test/java/org/opendaylight/controller/cluster/datastore/node/utils/NodeIdentifierFactoryTest.java @@ -0,0 +1,31 @@ +/* + * + * 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.cluster.datastore.node.utils; + +import junit.framework.Assert; +import org.junit.Test; +import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier; + +public class NodeIdentifierFactoryTest { + + @Test + public void validateAugmentationIdentifier() { + YangInstanceIdentifier.PathArgument argument = + NodeIdentifierFactory + .getArgument("AugmentationIdentifier{childNames=[(urn:opendaylight:flow:table:statistics?revision=2013-12-15)flow-table-statistics]}"); + + Assert + .assertTrue(argument instanceof YangInstanceIdentifier.AugmentationIdentifier); + + + } + +} diff --git a/opendaylight/md-sal/sal-clustering-commons/src/test/java/org/opendaylight/controller/cluster/datastore/util/InstanceIdentifierUtilsTest.java b/opendaylight/md-sal/sal-clustering-commons/src/test/java/org/opendaylight/controller/cluster/datastore/util/InstanceIdentifierUtilsTest.java new file mode 100644 index 0000000000..136748e341 --- /dev/null +++ b/opendaylight/md-sal/sal-clustering-commons/src/test/java/org/opendaylight/controller/cluster/datastore/util/InstanceIdentifierUtilsTest.java @@ -0,0 +1,161 @@ +/* + * + * 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.cluster.datastore.util; + +import org.junit.Assert; +import org.junit.Test; +import org.opendaylight.controller.protobuff.messages.common.NormalizedNodeMessages; +import org.opendaylight.yangtools.yang.common.QName; +import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.HashSet; +import java.util.List; + +public class InstanceIdentifierUtilsTest { + + private static QName TEST_QNAME = + QName + .create("(urn:opendaylight:params:xml:ns:yang:controller:md:sal:dom:store:test?revision=2014-03-13)test"); + private static QName NODE_WITH_VALUE_QNAME = + QName + .create("(urn:opendaylight:params:xml:ns:yang:controller:md:sal:dom:store:test?revision=2014-03-13)value"); + private static QName NODE_WITH_PREDICATES_QNAME = + QName + .create("(urn:opendaylight:params:xml:ns:yang:controller:md:sal:dom:store:test?revision=2014-03-13)pred"); + private static QName NAME_QNAME = + QName + .create("(urn:opendaylight:params:xml:ns:yang:controller:md:sal:dom:store:test?revision=2014-03-13)name"); + + @Test + public void testSerializationOfNodeIdentifier() { + YangInstanceIdentifier.PathArgument p1 = + new YangInstanceIdentifier.NodeIdentifier(TEST_QNAME); + + List arguments = new ArrayList<>(); + + arguments.add(p1); + + YangInstanceIdentifier expected = YangInstanceIdentifier.create(arguments); + + NormalizedNodeMessages.InstanceIdentifier instanceIdentifier = + InstanceIdentifierUtils.toSerializable(expected); + + YangInstanceIdentifier actual = + InstanceIdentifierUtils.fromSerializable(instanceIdentifier); + + + Assert.assertEquals(expected.getLastPathArgument(), + actual.getLastPathArgument()); + + + } + + @Test + public void testSerializationOfNodeWithValue() { + + withValue((short) 1); + withValue((long) 2); + withValue(3); + withValue(true); + + } + + private void withValue(Object value) { + YangInstanceIdentifier.PathArgument p1 = + new YangInstanceIdentifier.NodeIdentifier(TEST_QNAME); + + YangInstanceIdentifier.PathArgument p2 = + new YangInstanceIdentifier.NodeWithValue(NODE_WITH_VALUE_QNAME, value); + + + List arguments = new ArrayList<>(); + + arguments.add(p1); + arguments.add(p2); + + YangInstanceIdentifier expected = YangInstanceIdentifier.create(arguments); + + NormalizedNodeMessages.InstanceIdentifier instanceIdentifier = + InstanceIdentifierUtils.toSerializable(expected); + + YangInstanceIdentifier actual = + InstanceIdentifierUtils.fromSerializable(instanceIdentifier); + + + Assert.assertEquals(expected.getLastPathArgument(), + actual.getLastPathArgument()); + } + + + @Test + public void testSerializationOfNodeIdentifierWithPredicates() { + + withPredicates((short) 1); + withPredicates((long) 2); + withPredicates(3); + withPredicates(true); + + } + + private void withPredicates(Object value) { + YangInstanceIdentifier.PathArgument p1 = + new YangInstanceIdentifier.NodeIdentifier(TEST_QNAME); + + YangInstanceIdentifier.PathArgument p2 = + new YangInstanceIdentifier.NodeIdentifierWithPredicates( + NODE_WITH_PREDICATES_QNAME, NAME_QNAME, value); + + + List arguments = new ArrayList<>(); + + arguments.add(p1); + arguments.add(p2); + + YangInstanceIdentifier expected = YangInstanceIdentifier.create(arguments); + + NormalizedNodeMessages.InstanceIdentifier instanceIdentifier = + InstanceIdentifierUtils.toSerializable(expected); + + YangInstanceIdentifier actual = + InstanceIdentifierUtils.fromSerializable(instanceIdentifier); + + + Assert.assertEquals(expected.getLastPathArgument(), + actual.getLastPathArgument()); + } + + @Test + public void testAugmentationIdentifier() { + YangInstanceIdentifier.PathArgument p1 = + new YangInstanceIdentifier.AugmentationIdentifier(new HashSet( + Arrays.asList(TEST_QNAME))); + + List arguments = new ArrayList<>(); + + arguments.add(p1); + + YangInstanceIdentifier expected = YangInstanceIdentifier.create(arguments); + + NormalizedNodeMessages.InstanceIdentifier instanceIdentifier = + InstanceIdentifierUtils.toSerializable(expected); + + YangInstanceIdentifier actual = + InstanceIdentifierUtils.fromSerializable(instanceIdentifier); + + + Assert.assertEquals(expected.getLastPathArgument(), + actual.getLastPathArgument()); + + } + +} diff --git a/opendaylight/md-sal/sal-clustering-commons/src/test/java/org/opendaylight/controller/cluster/datastore/util/NormalizedNodeXmlConverterTest.java b/opendaylight/md-sal/sal-clustering-commons/src/test/java/org/opendaylight/controller/cluster/datastore/util/NormalizedNodeXmlConverterTest.java new file mode 100644 index 0000000000..853b3e264b --- /dev/null +++ b/opendaylight/md-sal/sal-clustering-commons/src/test/java/org/opendaylight/controller/cluster/datastore/util/NormalizedNodeXmlConverterTest.java @@ -0,0 +1,483 @@ +/* + * + * 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.cluster.datastore.util; + +import com.google.common.base.Preconditions; +import com.google.common.collect.Lists; +import com.google.common.collect.Maps; +import com.google.common.collect.Sets; +import org.custommonkey.xmlunit.Diff; +import org.custommonkey.xmlunit.XMLUnit; +import org.junit.Test; +import org.opendaylight.controller.protobuff.messages.common.SimpleNormalizedNodeMessage; +import org.opendaylight.yangtools.yang.common.QName; +import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier; +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; +import org.opendaylight.yangtools.yang.data.api.schema.MapEntryNode; +import org.opendaylight.yangtools.yang.data.api.schema.MapNode; +import org.opendaylight.yangtools.yang.data.impl.codec.xml.XmlDocumentUtils; +import org.opendaylight.yangtools.yang.data.impl.schema.Builders; +import org.opendaylight.yangtools.yang.data.impl.schema.builder.api.CollectionNodeBuilder; +import org.opendaylight.yangtools.yang.data.impl.schema.builder.api.DataContainerNodeBuilder; +import org.opendaylight.yangtools.yang.data.impl.schema.builder.api.ListNodeBuilder; +import org.opendaylight.yangtools.yang.data.impl.schema.builder.api.NormalizedNodeBuilder; +import org.opendaylight.yangtools.yang.data.impl.schema.transform.dom.DomUtils; +import org.opendaylight.yangtools.yang.data.impl.schema.transform.dom.parser.DomToNormalizedNodeParserFactory; +import org.opendaylight.yangtools.yang.data.impl.schema.transform.dom.serializer.DomFromNormalizedNodeSerializerFactory; +import org.opendaylight.yangtools.yang.model.api.ChoiceNode; +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.Module; +import org.opendaylight.yangtools.yang.model.api.SchemaContext; +import org.opendaylight.yangtools.yang.parser.impl.YangParserImpl; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.w3c.dom.Document; +import org.w3c.dom.Element; +import org.xml.sax.SAXException; + +import javax.xml.parsers.DocumentBuilder; +import javax.xml.parsers.DocumentBuilderFactory; +import javax.xml.parsers.ParserConfigurationException; +import javax.xml.transform.OutputKeys; +import javax.xml.transform.Transformer; +import javax.xml.transform.TransformerException; +import javax.xml.transform.TransformerFactory; +import javax.xml.transform.TransformerFactoryConfigurationError; +import javax.xml.transform.dom.DOMSource; +import javax.xml.transform.stream.StreamResult; +import java.io.ByteArrayInputStream; +import java.io.IOException; +import java.io.InputStream; +import java.io.StringWriter; +import java.net.URI; +import java.text.ParseException; +import java.text.SimpleDateFormat; +import java.util.ArrayList; +import java.util.Collection; +import java.util.Collections; +import java.util.Date; +import java.util.List; +import java.util.Map; +import java.util.Set; + + +/** + * Two of the testcases in the yangtools/yang-data-impl are leveraged (with modification) to create + * the serialization of NormalizedNode using the ProtocolBuffer + * + * @syedbahm + * + */ + + +public class NormalizedNodeXmlConverterTest { + private static final Logger logger = LoggerFactory + .getLogger(NormalizedNodeXmlConverterTest.class); + public static final String NAMESPACE = + "urn:opendaylight:params:xml:ns:yang:controller:test"; + private static Date revision; + private ContainerNode expectedNode; + private ContainerSchemaNode containerNode; + private String xmlPath; + + static { + try { + revision = new SimpleDateFormat("yyyy-MM-dd").parse("2014-03-13"); + } catch (ParseException e) { + throw new RuntimeException(e); + } + } + + public static DataSchemaNode getSchemaNode(final SchemaContext context, + final String moduleName, final String childNodeName) { + for (Module module : context.getModules()) { + if (module.getName().equals(moduleName)) { + DataSchemaNode found = + findChildNode(module.getChildNodes(), childNodeName); + Preconditions.checkState(found != null, "Unable to find %s", + childNodeName); + return found; + } + } + throw new IllegalStateException("Unable to find child node " + + childNodeName); + } + + static DataSchemaNode findChildNode( + final Collection children, final String name) { + List containers = Lists.newArrayList(); + + for (DataSchemaNode dataSchemaNode : children) { + if (dataSchemaNode.getQName().getLocalName().equals(name)) { + return dataSchemaNode; + } + if (dataSchemaNode instanceof DataNodeContainer) { + containers.add((DataNodeContainer) dataSchemaNode); + } else if (dataSchemaNode instanceof ChoiceNode) { + containers.addAll(((ChoiceNode) dataSchemaNode).getCases()); + } + } + + for (DataNodeContainer container : containers) { + DataSchemaNode retVal = findChildNode(container.getChildNodes(), name); + if (retVal != null) { + return retVal; + } + } + + return null; + } + + public static YangInstanceIdentifier.NodeIdentifier getNodeIdentifier( + final String localName) { + return new YangInstanceIdentifier.NodeIdentifier(QName.create( + URI.create(NAMESPACE), revision, localName)); + } + + public static YangInstanceIdentifier.AugmentationIdentifier getAugmentIdentifier( + final String... childNames) { + Set qn = Sets.newHashSet(); + + for (String childName : childNames) { + qn.add(getNodeIdentifier(childName).getNodeType()); + } + + return new YangInstanceIdentifier.AugmentationIdentifier(qn); + } + + + public static ContainerNode augmentChoiceExpectedNode() { + + DataContainerNodeBuilder b = + Builders.containerBuilder(); + b.withNodeIdentifier(getNodeIdentifier("container")); + + b.withChild(Builders + .choiceBuilder() + .withNodeIdentifier(getNodeIdentifier("ch2")) + .withChild( + Builders.leafBuilder() + .withNodeIdentifier(getNodeIdentifier("c2Leaf")).withValue("2") + .build()) + .withChild( + Builders + .choiceBuilder() + .withNodeIdentifier(getNodeIdentifier("c2DeepChoice")) + .withChild( + Builders + .leafBuilder() + .withNodeIdentifier( + getNodeIdentifier("c2DeepChoiceCase1Leaf2")) + .withValue("2").build()).build()).build()); + + b.withChild(Builders + .choiceBuilder() + .withNodeIdentifier(getNodeIdentifier("ch3")) + .withChild( + Builders.leafBuilder() + .withNodeIdentifier(getNodeIdentifier("c3Leaf")).withValue("3") + .build()).build()); + + b.withChild(Builders + .augmentationBuilder() + .withNodeIdentifier(getAugmentIdentifier("augLeaf")) + .withChild( + Builders.leafBuilder() + .withNodeIdentifier(getNodeIdentifier("augLeaf")) + .withValue("augment").build()).build()); + + b.withChild(Builders + .augmentationBuilder() + .withNodeIdentifier(getAugmentIdentifier("ch")) + .withChild( + Builders + .choiceBuilder() + .withNodeIdentifier(getNodeIdentifier("ch")) + .withChild( + Builders.leafBuilder() + .withNodeIdentifier(getNodeIdentifier("c1Leaf")) + .withValue("1").build()) + .withChild( + Builders + .augmentationBuilder() + .withNodeIdentifier( + getAugmentIdentifier("c1Leaf_AnotherAugment", + "deepChoice")) + .withChild( + Builders + .leafBuilder() + .withNodeIdentifier( + getNodeIdentifier("c1Leaf_AnotherAugment")) + .withValue("1").build()) + .withChild( + Builders + .choiceBuilder() + .withNodeIdentifier( + getNodeIdentifier("deepChoice")) + .withChild( + Builders + .leafBuilder() + .withNodeIdentifier( + getNodeIdentifier("deepLeafc1")) + .withValue("1").build()).build()) + .build()).build()).build()); + + return b.build(); + } + + + + public void init(final String yangPath, final String xmlPath, + final ContainerNode expectedNode) throws Exception { + SchemaContext schema = parseTestSchema(yangPath); + this.xmlPath = xmlPath; + this.containerNode = + (ContainerSchemaNode) getSchemaNode(schema, "test", "container"); + this.expectedNode = expectedNode; + } + + SchemaContext parseTestSchema(final String yangPath) throws Exception { + + YangParserImpl yangParserImpl = new YangParserImpl(); + InputStream stream = + NormalizedNodeXmlConverterTest.class.getResourceAsStream(yangPath); + ArrayList al = new ArrayList(); + al.add(stream); + Set modules = yangParserImpl.parseYangModelsFromStreams(al); + return yangParserImpl.resolveSchemaContext(modules); + + } + + + @Test + public void testConversionWithAugmentChoice() throws Exception { + init("/augment_choice.yang", "/augment_choice.xml", + augmentChoiceExpectedNode()); + Document doc = loadDocument(xmlPath); + + ContainerNode built = + DomToNormalizedNodeParserFactory + .getInstance(DomUtils.defaultValueCodecProvider()) + .getContainerNodeParser() + .parse(Collections.singletonList(doc.getDocumentElement()), + containerNode); + + if (expectedNode != null) { + junit.framework.Assert.assertEquals(expectedNode, built); + } + + logger.info("{}", built); + + Iterable els = + DomFromNormalizedNodeSerializerFactory + .getInstance(XmlDocumentUtils.getDocument(), + DomUtils.defaultValueCodecProvider()) + .getContainerNodeSerializer().serialize(containerNode, built); + + Element el = els.iterator().next(); + + XMLUnit.setIgnoreWhitespace(true); + XMLUnit.setIgnoreComments(true); + + System.out.println(toString(doc.getDocumentElement())); + System.out.println(toString(el)); + + new Diff(XMLUnit.buildControlDocument(toString(doc.getDocumentElement())), + XMLUnit.buildTestDocument(toString(el))).similar(); + } + + private static ContainerNode listLeafListWithAttributes() { + DataContainerNodeBuilder b = + Builders.containerBuilder(); + b.withNodeIdentifier(getNodeIdentifier("container")); + + CollectionNodeBuilder listBuilder = + Builders.mapBuilder().withNodeIdentifier(getNodeIdentifier("list")); + + Map predicates = Maps.newHashMap(); + predicates.put(getNodeIdentifier("uint32InList").getNodeType(), 3L); + + DataContainerNodeBuilder list1Builder = + Builders.mapEntryBuilder().withNodeIdentifier( + new YangInstanceIdentifier.NodeIdentifierWithPredicates( + getNodeIdentifier("list").getNodeType(), predicates)); + NormalizedNodeBuilder> uint32InListBuilder = + Builders.leafBuilder().withNodeIdentifier( + getNodeIdentifier("uint32InList")); + + list1Builder.withChild(uint32InListBuilder.withValue(3L).build()); + + listBuilder.withChild(list1Builder.build()); + b.withChild(listBuilder.build()); + + NormalizedNodeBuilder> booleanBuilder = + Builders.leafBuilder().withNodeIdentifier(getNodeIdentifier("boolean")); + booleanBuilder.withValue(false); + b.withChild(booleanBuilder.build()); + + ListNodeBuilder> leafListBuilder = + Builders.leafSetBuilder().withNodeIdentifier( + getNodeIdentifier("leafList")); + + NormalizedNodeBuilder> leafList1Builder = + Builders.leafSetEntryBuilder().withNodeIdentifier( + new YangInstanceIdentifier.NodeWithValue(getNodeIdentifier( + "leafList").getNodeType(), "a")); + + leafList1Builder.withValue("a"); + + leafListBuilder.withChild(leafList1Builder.build()); + b.withChild(leafListBuilder.build()); + + return b.build(); + } + + + @Test + public void testConversionWithAttributes() throws Exception { + init("/test.yang", "/simple_xml_with_attributes.xml", + listLeafListWithAttributes()); + Document doc = loadDocument(xmlPath); + + ContainerNode built = + DomToNormalizedNodeParserFactory + .getInstance(DomUtils.defaultValueCodecProvider()) + .getContainerNodeParser() + .parse(Collections.singletonList(doc.getDocumentElement()), + containerNode); + + if (expectedNode != null) { + junit.framework.Assert.assertEquals(expectedNode, built); + } + + logger.info("{}", built); + + Iterable els = + DomFromNormalizedNodeSerializerFactory + .getInstance(XmlDocumentUtils.getDocument(), + DomUtils.defaultValueCodecProvider()) + .getContainerNodeSerializer().serialize(containerNode, built); + + Element el = els.iterator().next(); + + XMLUnit.setIgnoreWhitespace(true); + XMLUnit.setIgnoreComments(true); + + System.out.println(toString(doc.getDocumentElement())); + System.out.println(toString(el)); + + new Diff(XMLUnit.buildControlDocument(toString(doc.getDocumentElement())), + XMLUnit.buildTestDocument(toString(el))).similar(); + } + + + private Document loadDocument(final String xmlPath) throws Exception { + InputStream resourceAsStream = + NormalizedNodeXmlConverterTest.class.getResourceAsStream(xmlPath); + + Document currentConfigElement = readXmlToDocument(resourceAsStream); + Preconditions.checkNotNull(currentConfigElement); + return currentConfigElement; + } + + private static final DocumentBuilderFactory BUILDERFACTORY; + + static { + DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance(); + factory.setNamespaceAware(true); + factory.setCoalescing(true); + factory.setIgnoringElementContentWhitespace(true); + factory.setIgnoringComments(true); + BUILDERFACTORY = factory; + } + + private Document readXmlToDocument(final InputStream xmlContent) + throws IOException, SAXException { + DocumentBuilder dBuilder; + try { + dBuilder = BUILDERFACTORY.newDocumentBuilder(); + } catch (ParserConfigurationException e) { + throw new RuntimeException("Failed to parse XML document", e); + } + Document doc = dBuilder.parse(xmlContent); + + doc.getDocumentElement().normalize(); + return doc; + } + + public static String toString(final Element xml) { + try { + Transformer transformer = + TransformerFactory.newInstance().newTransformer(); + transformer.setOutputProperty(OutputKeys.INDENT, "yes"); + + StreamResult result = new StreamResult(new StringWriter()); + DOMSource source = new DOMSource(xml); + transformer.transform(source, result); + + return result.getWriter().toString(); + } catch (IllegalArgumentException | TransformerFactoryConfigurationError + | TransformerException e) { + throw new RuntimeException("Unable to serialize xml element " + xml, e); + } + } + + @Test + public void testConversionToNormalizedXml() throws Exception { + SimpleNormalizedNodeMessage.NormalizedNodeXml nnXml = + EncoderDecoderUtil.encode(parseTestSchema("/augment_choice.yang"), + augmentChoiceExpectedNode()); + Document expectedDoc = loadDocument("/augment_choice.xml"); + Document convertedDoc = + EncoderDecoderUtil.factory.newDocumentBuilder().parse( + new ByteArrayInputStream(nnXml.getXmlString().getBytes("utf-8"))); + System.out.println(toString(convertedDoc.getDocumentElement())); + XMLUnit.setIgnoreWhitespace(true); + XMLUnit.setIgnoreComments(true); + new Diff(XMLUnit.buildControlDocument(toString(expectedDoc + .getDocumentElement())), + XMLUnit.buildTestDocument(toString(convertedDoc.getDocumentElement()))) + .similar(); + System.out.println(toString(expectedDoc.getDocumentElement())); + + } + + + @Test + public void testConversionFromXmlToNormalizedNode() throws Exception { + SimpleNormalizedNodeMessage.NormalizedNodeXml nnXml = + EncoderDecoderUtil.encode(parseTestSchema("/test.yang"), + listLeafListWithAttributes()); + Document expectedDoc = loadDocument("/simple_xml_with_attributes.xml"); + Document convertedDoc = + EncoderDecoderUtil.factory.newDocumentBuilder().parse( + new ByteArrayInputStream(nnXml.getXmlString().getBytes("utf-8"))); + System.out.println(toString(convertedDoc.getDocumentElement())); + XMLUnit.setIgnoreWhitespace(true); + XMLUnit.setIgnoreComments(true); + new Diff(XMLUnit.buildControlDocument(toString(expectedDoc + .getDocumentElement())), + XMLUnit.buildTestDocument(toString(convertedDoc.getDocumentElement()))) + .similar(); + System.out.println(toString(expectedDoc.getDocumentElement())); + + // now we will try to convert xml back to normalize node. + ContainerNode cn = + (ContainerNode) EncoderDecoderUtil.decode( + parseTestSchema("/test.yang"), nnXml); + junit.framework.Assert.assertEquals(listLeafListWithAttributes(), cn); + + } + +} diff --git a/opendaylight/md-sal/sal-clustering-commons/src/test/java/org/opendaylight/controller/cluster/datastore/util/TestModel.java b/opendaylight/md-sal/sal-clustering-commons/src/test/java/org/opendaylight/controller/cluster/datastore/util/TestModel.java new file mode 100644 index 0000000000..3eeb06f93c --- /dev/null +++ b/opendaylight/md-sal/sal-clustering-commons/src/test/java/org/opendaylight/controller/cluster/datastore/util/TestModel.java @@ -0,0 +1,470 @@ +/* + * + * 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.cluster.datastore.util; + +import org.opendaylight.yangtools.yang.common.QName; +import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier; +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.LeafSetEntryNode; +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.opendaylight.yangtools.yang.data.impl.schema.ImmutableNodes; +import org.opendaylight.yangtools.yang.data.impl.schema.builder.api.CollectionNodeBuilder; +import org.opendaylight.yangtools.yang.data.impl.schema.builder.api.DataContainerNodeAttrBuilder; +import org.opendaylight.yangtools.yang.data.impl.schema.builder.api.DataContainerNodeBuilder; +import org.opendaylight.yangtools.yang.data.impl.schema.builder.impl.ImmutableContainerNodeBuilder; +import org.opendaylight.yangtools.yang.data.impl.schema.builder.impl.ImmutableLeafSetEntryNodeBuilder; +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.model.api.Module; +import org.opendaylight.yangtools.yang.model.api.SchemaContext; +import org.opendaylight.yangtools.yang.parser.impl.YangParserImpl; + +import java.io.InputStream; +import java.util.ArrayList; +import java.util.HashSet; +import java.util.List; +import java.util.Set; + +import static org.opendaylight.yangtools.yang.data.impl.schema.ImmutableNodes.mapEntry; +import static org.opendaylight.yangtools.yang.data.impl.schema.ImmutableNodes.mapEntryBuilder; +import static org.opendaylight.yangtools.yang.data.impl.schema.ImmutableNodes.mapNodeBuilder; + +public class TestModel { + + public static final QName TEST_QNAME = QName.create( + "urn:opendaylight:params:xml:ns:yang:controller:md:sal:dom:store:test", + "2014-03-13", "test"); + + public static final QName AUG_NAME_QNAME = QName.create( + "urn:opendaylight:params:xml:ns:yang:controller:md:sal:dom:store:aug", + "2014-03-13", "name"); + + public static final QName AUG_CONT_QNAME = QName.create( + "urn:opendaylight:params:xml:ns:yang:controller:md:sal:dom:store:aug", + "2014-03-13", "cont"); + + + public static final QName DESC_QNAME = QName.create(TEST_QNAME, "desc"); + public static final QName POINTER_QNAME = QName.create(TEST_QNAME, "pointer"); + public static final QName SOME_REF_QNAME = QName.create(TEST_QNAME, + "some-ref"); + public static final QName MYIDENTITY_QNAME = QName.create(TEST_QNAME, + "myidentity"); + public static final QName SWITCH_FEATURES_QNAME = QName.create(TEST_QNAME, + "switch-features"); + + public static final QName AUGMENTED_LIST_QNAME = QName.create(TEST_QNAME, + "augmented-list"); + + public static final QName OUTER_LIST_QNAME = QName.create(TEST_QNAME, + "outer-list"); + public static final QName INNER_LIST_QNAME = QName.create(TEST_QNAME, + "inner-list"); + public static final QName OUTER_CHOICE_QNAME = QName.create(TEST_QNAME, + "outer-choice"); + public static final QName ID_QNAME = QName.create(TEST_QNAME, "id"); + public static final QName NAME_QNAME = QName.create(TEST_QNAME, "name"); + public static final QName VALUE_QNAME = QName.create(TEST_QNAME, "value"); + private static final String DATASTORE_TEST_YANG = "/odl-datastore-test.yang"; + private static final String DATASTORE_AUG_YANG = + "/odl-datastore-augmentation.yang"; + private static final String DATASTORE_TEST_NOTIFICATION_YANG = + "/odl-datastore-test-notification.yang"; + + + public static final YangInstanceIdentifier TEST_PATH = YangInstanceIdentifier + .of(TEST_QNAME); + public static final YangInstanceIdentifier DESC_PATH = YangInstanceIdentifier + .builder(TEST_PATH).node(DESC_QNAME).build(); + public static final YangInstanceIdentifier OUTER_LIST_PATH = + YangInstanceIdentifier.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"); + + private static final Integer ONE_ID = 1; + private static final Integer TWO_ID = 2; + private static final String TWO_ONE_NAME = "one"; + private static final String TWO_TWO_NAME = "two"; + private static final String DESC = "Hello there"; + + // Family specific constants + public static final QName FAMILY_QNAME = + QName + .create( + "urn:opendaylight:params:xml:ns:yang:controller:md:sal:dom:store:notification-test", + "2014-04-17", "family"); + public static final QName CHILDREN_QNAME = QName.create(FAMILY_QNAME, + "children"); + public static final QName GRAND_CHILDREN_QNAME = QName.create(FAMILY_QNAME, + "grand-children"); + public static final QName CHILD_NUMBER_QNAME = QName.create(FAMILY_QNAME, + "child-number"); + public static final QName CHILD_NAME_QNAME = QName.create(FAMILY_QNAME, + "child-name"); + public static final QName GRAND_CHILD_NUMBER_QNAME = QName.create( + FAMILY_QNAME, "grand-child-number"); + public static final QName GRAND_CHILD_NAME_QNAME = QName.create(FAMILY_QNAME, + "grand-child-name"); + + public static final YangInstanceIdentifier FAMILY_PATH = + YangInstanceIdentifier.of(FAMILY_QNAME); + public static final YangInstanceIdentifier FAMILY_DESC_PATH = + YangInstanceIdentifier.builder(FAMILY_PATH).node(DESC_QNAME).build(); + public static final YangInstanceIdentifier CHILDREN_PATH = + YangInstanceIdentifier.builder(FAMILY_PATH).node(CHILDREN_QNAME).build(); + + private static final Integer FIRST_CHILD_ID = 1; + private static final Integer SECOND_CHILD_ID = 2; + + private static final String FIRST_CHILD_NAME = "first child"; + private static final String SECOND_CHILD_NAME = "second child"; + + private static final Integer FIRST_GRAND_CHILD_ID = 1; + private static final Integer SECOND_GRAND_CHILD_ID = 2; + + private static final String FIRST_GRAND_CHILD_NAME = "first grand child"; + private static final String SECOND_GRAND_CHILD_NAME = "second grand child"; + + // first child + private static final YangInstanceIdentifier CHILDREN_1_PATH = + YangInstanceIdentifier.builder(CHILDREN_PATH) + .nodeWithKey(CHILDREN_QNAME, CHILD_NUMBER_QNAME, FIRST_CHILD_ID) // + .build(); + private static final YangInstanceIdentifier CHILDREN_1_NAME_PATH = + YangInstanceIdentifier.builder(CHILDREN_PATH) + .nodeWithKey(CHILDREN_QNAME, CHILD_NAME_QNAME, FIRST_CHILD_NAME) // + .build(); + + private static final YangInstanceIdentifier CHILDREN_2_PATH = + YangInstanceIdentifier.builder(CHILDREN_PATH) + .nodeWithKey(CHILDREN_QNAME, CHILD_NUMBER_QNAME, SECOND_CHILD_ID) // + .build(); + private static final YangInstanceIdentifier CHILDREN_2_NAME_PATH = + YangInstanceIdentifier.builder(CHILDREN_PATH) + .nodeWithKey(CHILDREN_QNAME, CHILD_NAME_QNAME, SECOND_CHILD_NAME) // + .build(); + + + private static final YangInstanceIdentifier GRAND_CHILD_1_PATH = + YangInstanceIdentifier + .builder(CHILDREN_1_PATH) + .node(GRAND_CHILDREN_QNAME) + // + .nodeWithKey(GRAND_CHILDREN_QNAME, GRAND_CHILD_NUMBER_QNAME, + FIRST_GRAND_CHILD_ID) // + .build(); + + private static final YangInstanceIdentifier GRAND_CHILD_1_NAME_PATH = + YangInstanceIdentifier + .builder(CHILDREN_1_PATH) + .node(GRAND_CHILDREN_QNAME) + // + .nodeWithKey(GRAND_CHILDREN_QNAME, GRAND_CHILD_NAME_QNAME, + FIRST_GRAND_CHILD_NAME) // + .build(); + + private static final YangInstanceIdentifier GRAND_CHILD_2_PATH = + YangInstanceIdentifier + .builder(CHILDREN_2_PATH) + .node(GRAND_CHILDREN_QNAME) + // + .nodeWithKey(GRAND_CHILDREN_QNAME, GRAND_CHILD_NUMBER_QNAME, + SECOND_GRAND_CHILD_ID) // + .build(); + + private static final YangInstanceIdentifier GRAND_CHILD_2_NAME_PATH = + YangInstanceIdentifier + .builder(CHILDREN_2_PATH) + .node(GRAND_CHILDREN_QNAME) + // + .nodeWithKey(GRAND_CHILDREN_QNAME, GRAND_CHILD_NAME_QNAME, + SECOND_GRAND_CHILD_NAME) // + .build(); + + private static final YangInstanceIdentifier DESC_PATH_ID = + YangInstanceIdentifier.builder(DESC_PATH).build(); + private static final YangInstanceIdentifier OUTER_LIST_1_PATH = + YangInstanceIdentifier.builder(OUTER_LIST_PATH) + .nodeWithKey(OUTER_LIST_QNAME, ID_QNAME, ONE_ID) // + .build(); + + private static final YangInstanceIdentifier OUTER_LIST_2_PATH = + YangInstanceIdentifier.builder(OUTER_LIST_PATH) + .nodeWithKey(OUTER_LIST_QNAME, ID_QNAME, TWO_ID) // + .build(); + + private static final YangInstanceIdentifier TWO_TWO_PATH = + YangInstanceIdentifier.builder(OUTER_LIST_2_PATH).node(INNER_LIST_QNAME) // + .nodeWithKey(INNER_LIST_QNAME, NAME_QNAME, TWO_TWO_NAME) // + .build(); + + private static final YangInstanceIdentifier TWO_TWO_VALUE_PATH = + YangInstanceIdentifier.builder(TWO_TWO_PATH).node(VALUE_QNAME) // + .build(); + + private static final MapEntryNode BAR_NODE = mapEntryBuilder( + OUTER_LIST_QNAME, ID_QNAME, TWO_ID) // + .withChild(mapNodeBuilder(INNER_LIST_QNAME) // + .withChild(mapEntry(INNER_LIST_QNAME, NAME_QNAME, TWO_ONE_NAME)) // + .withChild(mapEntry(INNER_LIST_QNAME, NAME_QNAME, TWO_TWO_NAME)) // + .build()) // + .build(); + + public static final InputStream getDatastoreTestInputStream() { + return getInputStream(DATASTORE_TEST_YANG); + } + + public static final InputStream getDatastoreAugInputStream() { + return getInputStream(DATASTORE_AUG_YANG); + } + + public static final InputStream getDatastoreTestNotificationInputStream() { + return getInputStream(DATASTORE_TEST_NOTIFICATION_YANG); + } + + private static InputStream getInputStream(final String resourceName) { + return TestModel.class.getResourceAsStream(resourceName); + } + + public static SchemaContext createTestContext() { + List inputStreams = new ArrayList<>(); + inputStreams.add(getDatastoreTestInputStream()); + inputStreams.add(getDatastoreAugInputStream()); + inputStreams.add(getDatastoreTestNotificationInputStream()); + + YangParserImpl parser = new YangParserImpl(); + Set modules = parser.parseYangModelsFromStreams(inputStreams); + return parser.resolveSchemaContext(modules); + } + + /** + * Returns a test document + *

    + * + *

    +   * test
    +   *     outer-list
    +   *          id 1
    +   *     outer-list
    +   *          id 2
    +   *          inner-list
    +   *                  name "one"
    +   *          inner-list
    +   *                  name "two"
    +   *
    +   * 
    + * + * @return + */ + public static NormalizedNode createDocumentOne( + SchemaContext schemaContext) { + return ImmutableContainerNodeBuilder + .create() + .withNodeIdentifier( + new YangInstanceIdentifier.NodeIdentifier(schemaContext.getQName())) + .withChild(createTestContainer()).build(); + + } + + public static ContainerNode createTestContainer() { + + + // Create a list of shoes + // This is to test leaf list entry + final LeafSetEntryNode nike = + ImmutableLeafSetEntryNodeBuilder + .create() + .withNodeIdentifier( + new YangInstanceIdentifier.NodeWithValue(QName.create( + TEST_QNAME, "shoe"), "nike")).withValue("nike").build(); + + final LeafSetEntryNode puma = + ImmutableLeafSetEntryNodeBuilder + .create() + .withNodeIdentifier( + new YangInstanceIdentifier.NodeWithValue(QName.create( + TEST_QNAME, "shoe"), "puma")).withValue("puma").build(); + + final LeafSetNode shoes = + ImmutableLeafSetNodeBuilder + .create() + .withNodeIdentifier( + new YangInstanceIdentifier.NodeIdentifier(QName.create( + TEST_QNAME, "shoe"))).withChild(nike).withChild(puma) + .build(); + + + // Test a leaf-list where each entry contains an identity + final LeafSetEntryNode cap1 = + ImmutableLeafSetEntryNodeBuilder + .create() + .withNodeIdentifier( + new YangInstanceIdentifier.NodeWithValue(QName.create( + TEST_QNAME, "capability"), DESC_QNAME)) + .withValue(DESC_QNAME).build(); + + final LeafSetNode capabilities = + ImmutableLeafSetNodeBuilder + .create() + .withNodeIdentifier( + new YangInstanceIdentifier.NodeIdentifier(QName.create( + TEST_QNAME, "capability"))).withChild(cap1).build(); + + ContainerNode switchFeatures = + ImmutableContainerNodeBuilder + .create() + .withNodeIdentifier( + new YangInstanceIdentifier.NodeIdentifier(SWITCH_FEATURES_QNAME)) + .withChild(capabilities).build(); + + // Create a leaf list with numbers + final LeafSetEntryNode five = + ImmutableLeafSetEntryNodeBuilder + .create() + .withNodeIdentifier( + (new YangInstanceIdentifier.NodeWithValue(QName.create( + TEST_QNAME, "number"), 5))).withValue(5).build(); + final LeafSetEntryNode fifteen = + ImmutableLeafSetEntryNodeBuilder + .create() + .withNodeIdentifier( + (new YangInstanceIdentifier.NodeWithValue(QName.create( + TEST_QNAME, "number"), 15))).withValue(15).build(); + final LeafSetNode numbers = + ImmutableLeafSetNodeBuilder + .create() + .withNodeIdentifier( + new YangInstanceIdentifier.NodeIdentifier(QName.create( + TEST_QNAME, "number"))).withChild(five).withChild(fifteen) + .build(); + + + // Create augmentations + MapEntryNode mapEntry = createAugmentedListEntry(1, "First Test"); + + + // Create the document + return ImmutableContainerNodeBuilder + .create() + .withNodeIdentifier( + new YangInstanceIdentifier.NodeIdentifier(TEST_QNAME)) + .withChild(ImmutableNodes.leafNode(DESC_QNAME, DESC)) + .withChild(ImmutableNodes.leafNode(POINTER_QNAME, "pointer")) + .withChild( + ImmutableNodes.leafNode(SOME_REF_QNAME, YangInstanceIdentifier + .builder().build())) + .withChild(ImmutableNodes.leafNode(MYIDENTITY_QNAME, DESC_QNAME)) + + // .withChild(augmentationNode) + .withChild(shoes) + .withChild(numbers) + .withChild(switchFeatures) + .withChild( + mapNodeBuilder(AUGMENTED_LIST_QNAME).withChild(mapEntry).build()) + .withChild( + mapNodeBuilder(OUTER_LIST_QNAME) + .withChild(mapEntry(OUTER_LIST_QNAME, ID_QNAME, ONE_ID)) + .withChild(BAR_NODE).build()).build(); + + } + + public static MapEntryNode createAugmentedListEntry(int id, String name) { + + Set childAugmentations = new HashSet<>(); + childAugmentations.add(AUG_CONT_QNAME); + + ContainerNode augCont = + ImmutableContainerNodeBuilder + .create() + .withNodeIdentifier( + new YangInstanceIdentifier.NodeIdentifier(AUG_CONT_QNAME)) + .withChild(ImmutableNodes.leafNode(AUG_NAME_QNAME, name)).build(); + + + final YangInstanceIdentifier.AugmentationIdentifier augmentationIdentifier = + new YangInstanceIdentifier.AugmentationIdentifier(childAugmentations); + + final AugmentationNode augmentationNode = + Builders.augmentationBuilder() + .withNodeIdentifier(augmentationIdentifier).withChild(augCont) + .build(); + + return ImmutableMapEntryNodeBuilder + .create() + .withNodeIdentifier( + new YangInstanceIdentifier.NodeIdentifierWithPredicates( + AUGMENTED_LIST_QNAME, ID_QNAME, id)) + .withChild(ImmutableNodes.leafNode(ID_QNAME, id)) + .withChild(augmentationNode).build(); + } + + + public static ContainerNode createFamily() { + final DataContainerNodeAttrBuilder familyContainerBuilder = + ImmutableContainerNodeBuilder.create().withNodeIdentifier( + new YangInstanceIdentifier.NodeIdentifier(FAMILY_QNAME)); + + final CollectionNodeBuilder childrenBuilder = + mapNodeBuilder(CHILDREN_QNAME); + + final DataContainerNodeBuilder firstChildBuilder = + mapEntryBuilder(CHILDREN_QNAME, CHILD_NUMBER_QNAME, FIRST_CHILD_ID); + final DataContainerNodeBuilder secondChildBuilder = + mapEntryBuilder(CHILDREN_QNAME, CHILD_NUMBER_QNAME, SECOND_CHILD_ID); + + final DataContainerNodeBuilder firstGrandChildBuilder = + mapEntryBuilder(GRAND_CHILDREN_QNAME, GRAND_CHILD_NUMBER_QNAME, + FIRST_GRAND_CHILD_ID); + final DataContainerNodeBuilder secondGrandChildBuilder = + mapEntryBuilder(GRAND_CHILDREN_QNAME, GRAND_CHILD_NUMBER_QNAME, + SECOND_GRAND_CHILD_ID); + + firstGrandChildBuilder + .withChild( + ImmutableNodes.leafNode(GRAND_CHILD_NUMBER_QNAME, + FIRST_GRAND_CHILD_ID)).withChild( + ImmutableNodes.leafNode(GRAND_CHILD_NAME_QNAME, + FIRST_GRAND_CHILD_NAME)); + + secondGrandChildBuilder.withChild( + ImmutableNodes + .leafNode(GRAND_CHILD_NUMBER_QNAME, SECOND_GRAND_CHILD_ID)) + .withChild( + ImmutableNodes.leafNode(GRAND_CHILD_NAME_QNAME, + SECOND_GRAND_CHILD_NAME)); + + firstChildBuilder + .withChild(ImmutableNodes.leafNode(CHILD_NUMBER_QNAME, FIRST_CHILD_ID)) + .withChild(ImmutableNodes.leafNode(CHILD_NAME_QNAME, FIRST_CHILD_NAME)) + .withChild( + mapNodeBuilder(GRAND_CHILDREN_QNAME).withChild( + firstGrandChildBuilder.build()).build()); + + + secondChildBuilder + .withChild(ImmutableNodes.leafNode(CHILD_NUMBER_QNAME, SECOND_CHILD_ID)) + .withChild(ImmutableNodes.leafNode(CHILD_NAME_QNAME, SECOND_CHILD_NAME)) + .withChild( + mapNodeBuilder(GRAND_CHILDREN_QNAME).withChild( + firstGrandChildBuilder.build()).build()); + + childrenBuilder.withChild(firstChildBuilder.build()); + childrenBuilder.withChild(secondChildBuilder.build()); + + return familyContainerBuilder.withChild(childrenBuilder.build()).build(); + } + +} diff --git a/opendaylight/md-sal/sal-clustering-commons/src/test/java/org/opendaylight/controller/protobuff/messages/AbstractMessagesTest.java b/opendaylight/md-sal/sal-clustering-commons/src/test/java/org/opendaylight/controller/protobuff/messages/AbstractMessagesTest.java new file mode 100644 index 0000000000..c6c4afd505 --- /dev/null +++ b/opendaylight/md-sal/sal-clustering-commons/src/test/java/org/opendaylight/controller/protobuff/messages/AbstractMessagesTest.java @@ -0,0 +1,77 @@ +/* + * + * 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.protobuff.messages; + +import java.io.File; +import java.io.FileInputStream; +import java.io.FileOutputStream; + +/** + * @author: syedbahm Date: 7/31/14 + */ +public abstract class AbstractMessagesTest { + public final String VERSION_COMPATIBILTY_TEST_DATA_PATH = "." + + File.separator + "src" + File.separator + "test" + File.separator + + "resources" + File.separator + "version-compatibility-serialized-data"; + private File file; + private File testDataFile; + + protected AbstractMessagesTest() { + init(); + } + + protected void init() { + file = new File(getTestFileName()); + testDataFile = + new File(VERSION_COMPATIBILTY_TEST_DATA_PATH + File.separator + + getTestFileName() + "Data"); + } + + + + abstract public void verifySerialization() throws Exception; + + + protected void writeToFile( + com.google.protobuf.GeneratedMessage.Builder builder) throws Exception { + + FileOutputStream output = new FileOutputStream(file); + builder.build().writeTo(output); + output.close();; + + } + + protected com.google.protobuf.GeneratedMessage readFromFile( + com.google.protobuf.Parser parser) throws Exception { + com.google.protobuf.GeneratedMessage message = + (com.google.protobuf.GeneratedMessage) parser + .parseFrom(new FileInputStream(file)); + + /*Note: we will delete only the test file -- comment below if you want to capture the + version-compatibility-serialized-data test data file.The file will be generated at root of the + sal-protocolbuffer-encoding + and you need to move it to test/resources/version-compatbility-serialized-data folder renaming the file to include suffix "Data" + */ + file.delete(); + return message; + } + + protected com.google.protobuf.GeneratedMessage readFromTestDataFile( + com.google.protobuf.Parser parser) throws Exception { + return (com.google.protobuf.GeneratedMessage) parser + .parseFrom(new FileInputStream(testDataFile)); + } + + + public abstract String getTestFileName(); + + +} diff --git a/opendaylight/md-sal/sal-clustering-commons/src/test/java/org/opendaylight/controller/protobuff/messages/cohort3pc/ThreePhaseCommitCohortMessagesTest.java b/opendaylight/md-sal/sal-clustering-commons/src/test/java/org/opendaylight/controller/protobuff/messages/cohort3pc/ThreePhaseCommitCohortMessagesTest.java new file mode 100644 index 0000000000..a01ccb88c7 --- /dev/null +++ b/opendaylight/md-sal/sal-clustering-commons/src/test/java/org/opendaylight/controller/protobuff/messages/cohort3pc/ThreePhaseCommitCohortMessagesTest.java @@ -0,0 +1,68 @@ +/* + * + * 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.protobuff.messages.cohort3pc; + +import org.junit.Assert; +import org.junit.Test; +import org.opendaylight.controller.protobuff.messages.AbstractMessagesTest; + +/** + * This test case is present to ensure that if others have used proper version of protocol buffer + * for the cohort.proto messages + * + * If a different version of protocol buffer and there is change in serializaiton format + * this test would break as we are comparing with protocol buffer 2.5 generated + * serialized data. + * + * @author: syedbahm + * + */ + + +public class ThreePhaseCommitCohortMessagesTest extends AbstractMessagesTest { + + + @Test + public void verifySerialization() throws Exception { + + + + ThreePhaseCommitCohortMessages.CanCommitTransactionReply.Builder builder = + ThreePhaseCommitCohortMessages.CanCommitTransactionReply.newBuilder(); + builder.setCanCommit(true); + + writeToFile((com.google.protobuf.GeneratedMessage.Builder) builder); + + // Here we will read from the just serialized data + + ThreePhaseCommitCohortMessages.CanCommitTransactionReply newCanCommitTransactionReply = + (ThreePhaseCommitCohortMessages.CanCommitTransactionReply) readFromFile(ThreePhaseCommitCohortMessages.CanCommitTransactionReply.PARSER); + + Assert.assertTrue(newCanCommitTransactionReply.getCanCommit()); + + + // Here we will read the same from our test-data file and check we got back what we had saved + // earlier + ThreePhaseCommitCohortMessages.CanCommitTransactionReply originalCanCommitTransactionReply = + (ThreePhaseCommitCohortMessages.CanCommitTransactionReply) readFromTestDataFile(ThreePhaseCommitCohortMessages.CanCommitTransactionReply.PARSER); + + Assert.assertEquals(newCanCommitTransactionReply.getCanCommit(), + originalCanCommitTransactionReply.getCanCommit()); + + } + + @Override + public String getTestFileName() { + return ThreePhaseCommitCohortMessagesTest.class.getSimpleName(); + } + + +} diff --git a/opendaylight/md-sal/sal-clustering-commons/src/test/java/org/opendaylight/controller/protobuff/messages/common/NormalizedNodeMessagesTest.java b/opendaylight/md-sal/sal-clustering-commons/src/test/java/org/opendaylight/controller/protobuff/messages/common/NormalizedNodeMessagesTest.java new file mode 100644 index 0000000000..c68eceace4 --- /dev/null +++ b/opendaylight/md-sal/sal-clustering-commons/src/test/java/org/opendaylight/controller/protobuff/messages/common/NormalizedNodeMessagesTest.java @@ -0,0 +1,58 @@ +/* + * + * 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.protobuff.messages.common; + +import org.junit.Assert; +import org.junit.Test; +import org.opendaylight.controller.protobuff.messages.AbstractMessagesTest; + +/** + * This test case is present to ensure that if others have used proper version of protocol buffer + * for the common.proto messages + * + * If a different version of protocol buffer and there is change in serializaiton format + * this test would break as we are comparing with protocol buffer 2.5 generated + * serialized data. + * + * @author: syedbahm + * + */ + +public class NormalizedNodeMessagesTest extends AbstractMessagesTest { + + @Override + @Test + public void verifySerialization() throws Exception { + NormalizedNodeMessages.Attribute.Builder builder = + NormalizedNodeMessages.Attribute.newBuilder(); + builder.setName("test"); + builder.setType("fake"); + builder.setValue("testValue"); + writeToFile((com.google.protobuf.GeneratedMessage.Builder) builder); + + NormalizedNodeMessages.Attribute attributeNew = + (NormalizedNodeMessages.Attribute) readFromFile(NormalizedNodeMessages.Attribute.PARSER); + Assert.assertEquals("test", attributeNew.getName()); + Assert.assertEquals("fake", attributeNew.getType()); + Assert.assertEquals("testValue", attributeNew.getValue()); + + NormalizedNodeMessages.Attribute attributeOriginal = + (NormalizedNodeMessages.Attribute) readFromTestDataFile(NormalizedNodeMessages.Attribute.PARSER); + Assert.assertEquals(attributeNew.getName(), attributeOriginal.getName()); + } + + @Override + public String getTestFileName() { + return NormalizedNodeMessagesTest.class.getSimpleName(); + } + + +} diff --git a/opendaylight/md-sal/sal-clustering-commons/src/test/java/org/opendaylight/controller/protobuff/messages/datachange/notification/DataChangeListenerMessagesTest.java b/opendaylight/md-sal/sal-clustering-commons/src/test/java/org/opendaylight/controller/protobuff/messages/datachange/notification/DataChangeListenerMessagesTest.java new file mode 100644 index 0000000000..e9339286f9 --- /dev/null +++ b/opendaylight/md-sal/sal-clustering-commons/src/test/java/org/opendaylight/controller/protobuff/messages/datachange/notification/DataChangeListenerMessagesTest.java @@ -0,0 +1,78 @@ +/* + * + * 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.protobuff.messages.datachange.notification; + +import org.junit.Assert; +import org.junit.Test; +import org.opendaylight.controller.protobuff.messages.AbstractMessagesTest; +import org.opendaylight.controller.protobuff.messages.common.NormalizedNodeMessages; +import org.opendaylight.yangtools.yang.common.QName; + +/** + * This test case is present to ensure that if others have used proper version of protocol buffer + * for the DataChangeListener.proto messages + * + * If a different version of protocol buffer and there is change in serializaiton format + * this test would break as we are comparing with protocol buffer 2.5 generated + * serialized data. + * + * @author: syedbahm + * + */ + +public class DataChangeListenerMessagesTest extends AbstractMessagesTest { + + private final String namespace = "urn:protobuff", revision = "2014-07-31", + localName = "test"; + + @Override + @Test + public void verifySerialization() throws Exception { + NormalizedNodeMessages.InstanceIdentifier.Builder instanceIdentifierBuilder = + NormalizedNodeMessages.InstanceIdentifier.newBuilder(); + NormalizedNodeMessages.PathArgument.Builder pathArgument = + NormalizedNodeMessages.PathArgument.newBuilder(); + pathArgument.setNodeType(NormalizedNodeMessages.QName.newBuilder() + .setValue(QName.create(namespace, revision, localName).toString()) + .build()); + pathArgument.setValue("test"); + instanceIdentifierBuilder.addArguments(pathArgument.build()); + + NormalizedNodeMessages.InstanceIdentifier expectedOne = + instanceIdentifierBuilder.build(); + DataChangeListenerMessages.DataChanged.Builder builder = + DataChangeListenerMessages.DataChanged.newBuilder(); + builder.addRemovedPaths(expectedOne); + + writeToFile((com.google.protobuf.GeneratedMessage.Builder) builder); + + DataChangeListenerMessages.DataChanged dataChangedNew = + (DataChangeListenerMessages.DataChanged) readFromFile(DataChangeListenerMessages.DataChanged.PARSER); + Assert.assertEquals(expectedOne.getArgumentsCount(), dataChangedNew + .getRemovedPaths(0).getArgumentsCount()); + Assert.assertEquals(expectedOne.getArguments(0).getType(), dataChangedNew + .getRemovedPaths(0).getArguments(0).getType()); + + DataChangeListenerMessages.DataChanged dataChangedOriginal = + (DataChangeListenerMessages.DataChanged) readFromTestDataFile(DataChangeListenerMessages.DataChanged.PARSER); + Assert.assertEquals(dataChangedNew.getRemovedPathsCount(), + dataChangedOriginal.getRemovedPathsCount()); + Assert.assertEquals(dataChangedNew.getRemovedPaths(0).getArguments(0) + .getValue(), dataChangedOriginal.getRemovedPaths(0).getArguments(0) + .getValue()); + + } + + @Override + public String getTestFileName() { + return DataChangeListenerMessages.class.getSimpleName(); + } +} diff --git a/opendaylight/md-sal/sal-clustering-commons/src/test/java/org/opendaylight/controller/protobuff/messages/persistent/PersistentMessagesTest.java b/opendaylight/md-sal/sal-clustering-commons/src/test/java/org/opendaylight/controller/protobuff/messages/persistent/PersistentMessagesTest.java new file mode 100644 index 0000000000..a8ade30099 --- /dev/null +++ b/opendaylight/md-sal/sal-clustering-commons/src/test/java/org/opendaylight/controller/protobuff/messages/persistent/PersistentMessagesTest.java @@ -0,0 +1,82 @@ +/* + * + * 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.protobuff.messages.persistent; + +import org.junit.Assert; +import org.junit.Test; +import org.opendaylight.controller.protobuff.messages.AbstractMessagesTest; +import org.opendaylight.controller.protobuff.messages.common.NormalizedNodeMessages; +import org.opendaylight.yangtools.yang.common.QName; + + +/** + * This test case is present to ensure that if others have used proper version of protocol buffer + * for the peristent.proto messages + * + * If a different version of protocol buffer and there is change in serializaiton format + * this test would break as we are comparing with protocol buffer 2.5 generated + * serialized data. + * + * @author: syedbahm + * + */ + +public class PersistentMessagesTest extends AbstractMessagesTest { + + private final String namespace = "urn:protobuff", revision = "2014-07-31", + localName = "test"; + + @Override + @Test + public void verifySerialization() throws Exception { + NormalizedNodeMessages.InstanceIdentifier.Builder instanceIdentifierBuilder = + NormalizedNodeMessages.InstanceIdentifier.newBuilder(); + NormalizedNodeMessages.PathArgument.Builder pathArgument = + NormalizedNodeMessages.PathArgument.newBuilder(); + pathArgument.setNodeType(NormalizedNodeMessages.QName.newBuilder() + .setValue(QName.create(namespace, revision, localName).toString()) + .build()); + pathArgument.setValue("test"); + instanceIdentifierBuilder.addArguments(pathArgument.build()); + NormalizedNodeMessages.InstanceIdentifier expectedOne = + instanceIdentifierBuilder.build(); + + PersistentMessages.Modification.Builder builder = + PersistentMessages.Modification.newBuilder(); + builder.setType("test"); + builder.setPath(expectedOne); + + writeToFile((com.google.protobuf.GeneratedMessage.Builder) builder); + + PersistentMessages.Modification modificationNew = + (PersistentMessages.Modification) readFromFile(PersistentMessages.Modification.PARSER); + Assert.assertEquals("test", modificationNew.getType()); + Assert.assertEquals(expectedOne.getArguments(0).getValue(), modificationNew + .getPath().getArguments(0).getValue()); + Assert.assertEquals(expectedOne.getArguments(0).getType(), modificationNew + .getPath().getArguments(0).getType()); + + // we will compare with the serialized data that we had shipped + PersistentMessages.Modification modificationOriginal = + (PersistentMessages.Modification) readFromTestDataFile(PersistentMessages.Modification.PARSER); + Assert.assertEquals(modificationOriginal.getPath().getArguments(0) + .getValue(), modificationNew.getPath().getArguments(0).getValue()); + Assert.assertEquals(modificationOriginal.getPath().getArguments(0) + .getType(), modificationNew.getPath().getArguments(0).getType()); + + + } + + @Override + public String getTestFileName() { + return PersistentMessagesTest.class.getSimpleName(); + } +} diff --git a/opendaylight/md-sal/sal-clustering-commons/src/test/java/org/opendaylight/controller/protobuff/messages/registration/ListenerRegistrationMessagesTest.java b/opendaylight/md-sal/sal-clustering-commons/src/test/java/org/opendaylight/controller/protobuff/messages/registration/ListenerRegistrationMessagesTest.java new file mode 100644 index 0000000000..1d50872a66 --- /dev/null +++ b/opendaylight/md-sal/sal-clustering-commons/src/test/java/org/opendaylight/controller/protobuff/messages/registration/ListenerRegistrationMessagesTest.java @@ -0,0 +1,58 @@ +/* + * + * 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.protobuff.messages.registration; + +import org.junit.Assert; +import org.junit.Test; +import org.opendaylight.controller.protobuff.messages.AbstractMessagesTest; + +/** + * This test case is present to ensure that if others have used proper version of protocol buffer + * for the ListenerRegistration.proto messages + * + * If a different version of protocol buffer and there is change in serializaiton format + * this test would break as we are comparing with protocol buffer 2.5 generated + * serialized data. + * + * @author: syedbahm + * + */ + +public class ListenerRegistrationMessagesTest extends AbstractMessagesTest { + + @Override + @Test + public void verifySerialization() throws Exception { + String testListenerRegistrationPath = + "(urn:opendaylight:params:xml:ns:yang:controller:md:sal:dom:store:notification-test?revision=2014-04-15)family"; + ListenerRegistrationMessages.RegisterChangeListenerReply.Builder builder = + ListenerRegistrationMessages.RegisterChangeListenerReply.newBuilder(); + builder.setListenerRegistrationPath(testListenerRegistrationPath); + + writeToFile((com.google.protobuf.GeneratedMessage.Builder) builder); + + ListenerRegistrationMessages.RegisterChangeListenerReply rclrNew = + (ListenerRegistrationMessages.RegisterChangeListenerReply) readFromFile(ListenerRegistrationMessages.RegisterChangeListenerReply.PARSER); + Assert.assertEquals(testListenerRegistrationPath, + rclrNew.getListenerRegistrationPath()); + + ListenerRegistrationMessages.RegisterChangeListenerReply rclrOriginal = + (ListenerRegistrationMessages.RegisterChangeListenerReply) readFromTestDataFile(ListenerRegistrationMessages.RegisterChangeListenerReply.PARSER); + Assert.assertEquals(rclrOriginal.getListenerRegistrationPath(), + rclrNew.getListenerRegistrationPath()); + + } + + @Override + public String getTestFileName() { + return ListenerRegistrationMessages.class.getSimpleName(); + } +} diff --git a/opendaylight/md-sal/sal-clustering-commons/src/test/java/org/opendaylight/controller/protobuff/messages/shard/ShardManagerMessagesTest.java b/opendaylight/md-sal/sal-clustering-commons/src/test/java/org/opendaylight/controller/protobuff/messages/shard/ShardManagerMessagesTest.java new file mode 100644 index 0000000000..45dcd12d05 --- /dev/null +++ b/opendaylight/md-sal/sal-clustering-commons/src/test/java/org/opendaylight/controller/protobuff/messages/shard/ShardManagerMessagesTest.java @@ -0,0 +1,61 @@ +/* + * + * 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.protobuff.messages.shard; + +/** + * This test case is present to ensure that if others have used proper version of protocol buffer + * for the ShardManager.proto messages + * + * If a different version of protocol buffer and there is change in serializaiton format + * this test would break as we are comparing with protocol buffer 2.5 generated + * serialized data. + * + * @author: syedbahm + * + */ + +import org.junit.Assert; +import org.junit.Test; +import org.opendaylight.controller.protobuff.messages.AbstractMessagesTest; + +public class ShardManagerMessagesTest extends AbstractMessagesTest { + + @Test + public void verifySerialization() throws Exception { + ShardManagerMessages.FindPrimary.Builder builder = + ShardManagerMessages.FindPrimary.newBuilder(); + builder.setShardName("Inventory"); + + writeToFile((com.google.protobuf.GeneratedMessage.Builder) builder); + + + // Here we will read the same and check we got back what we had saved + ShardManagerMessages.FindPrimary findPrimaryNew = + (ShardManagerMessages.FindPrimary) readFromFile(ShardManagerMessages.FindPrimary.PARSER); + + Assert.assertEquals("Inventory", findPrimaryNew.getShardName()); + + // Here we compare with the version we had shipped to catch any protobuff compiler version + // changes + ShardManagerMessages.FindPrimary findPrimaryOriginal = + (ShardManagerMessages.FindPrimary) readFromTestDataFile(ShardManagerMessages.FindPrimary.PARSER); + + Assert.assertEquals(findPrimaryNew.getShardName(), + findPrimaryOriginal.getShardName()); + + } + + @Override + public String getTestFileName() { + return ShardManagerMessagesTest.class.getSimpleName(); + } + +} diff --git a/opendaylight/md-sal/sal-clustering-commons/src/test/java/org/opendaylight/controller/protobuff/messages/transaction/ShardTransactionChainMessagesTest.java b/opendaylight/md-sal/sal-clustering-commons/src/test/java/org/opendaylight/controller/protobuff/messages/transaction/ShardTransactionChainMessagesTest.java new file mode 100644 index 0000000000..c0e91ab0d0 --- /dev/null +++ b/opendaylight/md-sal/sal-clustering-commons/src/test/java/org/opendaylight/controller/protobuff/messages/transaction/ShardTransactionChainMessagesTest.java @@ -0,0 +1,69 @@ +/* + * + * 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.protobuff.messages.transaction; + +import org.junit.Assert; +import org.junit.Test; +import org.opendaylight.controller.protobuff.messages.AbstractMessagesTest; +import org.opendaylight.controller.protobuff.messages.common.NormalizedNodeMessages; +import org.opendaylight.yangtools.yang.common.QName; + +/** + * This test case is present to ensure that if others have used proper version of protocol buffer + * for the ShardTransactionChain.proto messages + * + * If a different version of protocol buffer and there is change in serializaiton format + * this test would break as we are comparing with protocol buffer 2.5 generated + * serialized data. + * + * @author: syedbahm + * + */ + + +public class ShardTransactionChainMessagesTest extends AbstractMessagesTest { + + @Override + @Test + public void verifySerialization() throws Exception { + String testTransactionChainPath = + "/actor/path"; + + ShardTransactionChainMessages.CreateTransactionChainReply.Builder builder = + ShardTransactionChainMessages.CreateTransactionChainReply.newBuilder(); + builder.setTransactionChainPath(testTransactionChainPath); + + writeToFile((com.google.protobuf.GeneratedMessage.Builder) builder); + + // Here we will read the same and check we got back what we had saved + ShardTransactionChainMessages.CreateTransactionChainReply replyNew = + (ShardTransactionChainMessages.CreateTransactionChainReply) readFromFile(ShardTransactionChainMessages.CreateTransactionChainReply.PARSER); + + Assert.assertEquals(replyNew.getTransactionChainPath(),testTransactionChainPath); + + // the following will compare with the version we had shipped + ShardTransactionChainMessages.CreateTransactionChainReply replyOriginal = + (ShardTransactionChainMessages.CreateTransactionChainReply) readFromTestDataFile(ShardTransactionChainMessages.CreateTransactionChainReply.PARSER); + + + Assert.assertEquals(replyOriginal.getTransactionChainPath(), + replyNew.getTransactionChainPath()); + + } + + @Override + public String getTestFileName() { + return ShardTransactionChainMessagesTest.class.getSimpleName(); + } + + + +} diff --git a/opendaylight/md-sal/sal-clustering-commons/src/test/java/org/opendaylight/controller/protobuff/messages/transaction/ShardTransactionMessagesTest.java b/opendaylight/md-sal/sal-clustering-commons/src/test/java/org/opendaylight/controller/protobuff/messages/transaction/ShardTransactionMessagesTest.java new file mode 100644 index 0000000000..6b538dab0d --- /dev/null +++ b/opendaylight/md-sal/sal-clustering-commons/src/test/java/org/opendaylight/controller/protobuff/messages/transaction/ShardTransactionMessagesTest.java @@ -0,0 +1,85 @@ +/* + * + * 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.protobuff.messages.transaction; + +import org.junit.Assert; +import org.junit.Test; +import org.opendaylight.controller.protobuff.messages.AbstractMessagesTest; +import org.opendaylight.controller.protobuff.messages.common.NormalizedNodeMessages; +import org.opendaylight.yangtools.yang.common.QName; + +/** + * This test case is present to ensure that if others have used proper version of protocol buffer + * for the ShardTransaction.proto messages + * + * If a different version of protocol buffer and there is change in serializaiton format + * this test would break as we are comparing with protocol buffer 2.5 generated + * serialized data. + * + * @author: syedbahm + * + */ + + +public class ShardTransactionMessagesTest extends AbstractMessagesTest { + + private final String namespace = "urn:protobuff", revision = "2014-07-31", + localName = "test"; + + @Test + public void verifySerialization() throws Exception { + NormalizedNodeMessages.InstanceIdentifier.Builder instanceIdentifierBuilder = + NormalizedNodeMessages.InstanceIdentifier.newBuilder(); + NormalizedNodeMessages.PathArgument.Builder pathArgument = + NormalizedNodeMessages.PathArgument.newBuilder(); + pathArgument.setNodeType(NormalizedNodeMessages.QName.newBuilder() + .setValue(QName.create(namespace, revision, localName).toString()) + .build()); + pathArgument.setValue("test"); + instanceIdentifierBuilder.addArguments(pathArgument.build()); + ShardTransactionMessages.ReadData.Builder builder = + ShardTransactionMessages.ReadData.newBuilder(); + NormalizedNodeMessages.InstanceIdentifier expectedOne = + instanceIdentifierBuilder.build(); + builder.setInstanceIdentifierPathArguments(expectedOne); + + writeToFile((com.google.protobuf.GeneratedMessage.Builder) builder); + + // Here we will read the same and check we got back what we had saved + ShardTransactionMessages.ReadData readDataNew = + (ShardTransactionMessages.ReadData) readFromFile(ShardTransactionMessages.ReadData.PARSER); + + + Assert.assertEquals(expectedOne.getArgumentsCount(), readDataNew + .getInstanceIdentifierPathArguments().getArgumentsCount()); + Assert.assertEquals(expectedOne.getArguments(0), readDataNew + .getInstanceIdentifierPathArguments().getArguments(0)); + + + // the following will compare with the version we had shipped + ShardTransactionMessages.ReadData readDataOriginal = + (ShardTransactionMessages.ReadData) readFromTestDataFile(ShardTransactionMessages.ReadData.PARSER); + + + Assert.assertEquals(readDataNew.getInstanceIdentifierPathArguments() + .getArguments(0), readDataOriginal.getInstanceIdentifierPathArguments() + .getArguments(0)); + + } + + @Override + public String getTestFileName() { + return ShardTransactionMessagesTest.class.getSimpleName(); + } + + + +} diff --git a/opendaylight/md-sal/sal-protocolbuffer-encoding/src/test/resources/application.conf b/opendaylight/md-sal/sal-clustering-commons/src/test/resources/application.conf similarity index 100% rename from opendaylight/md-sal/sal-protocolbuffer-encoding/src/test/resources/application.conf rename to opendaylight/md-sal/sal-clustering-commons/src/test/resources/application.conf diff --git a/opendaylight/md-sal/sal-protocolbuffer-encoding/src/test/resources/augment_choice.xml b/opendaylight/md-sal/sal-clustering-commons/src/test/resources/augment_choice.xml similarity index 54% rename from opendaylight/md-sal/sal-protocolbuffer-encoding/src/test/resources/augment_choice.xml rename to opendaylight/md-sal/sal-clustering-commons/src/test/resources/augment_choice.xml index c5a581cecc..7de3d077b4 100644 --- a/opendaylight/md-sal/sal-protocolbuffer-encoding/src/test/resources/augment_choice.xml +++ b/opendaylight/md-sal/sal-clustering-commons/src/test/resources/augment_choice.xml @@ -1,3 +1,13 @@ + + 2 diff --git a/opendaylight/md-sal/sal-protocolbuffer-encoding/src/test/resources/augment_choice.yang b/opendaylight/md-sal/sal-clustering-commons/src/test/resources/augment_choice.yang similarity index 100% rename from opendaylight/md-sal/sal-protocolbuffer-encoding/src/test/resources/augment_choice.yang rename to opendaylight/md-sal/sal-clustering-commons/src/test/resources/augment_choice.yang diff --git a/opendaylight/md-sal/sal-protocolbuffer-encoding/src/test/resources/odl-datastore-augmentation.yang b/opendaylight/md-sal/sal-clustering-commons/src/test/resources/odl-datastore-augmentation.yang similarity index 100% rename from opendaylight/md-sal/sal-protocolbuffer-encoding/src/test/resources/odl-datastore-augmentation.yang rename to opendaylight/md-sal/sal-clustering-commons/src/test/resources/odl-datastore-augmentation.yang diff --git a/opendaylight/md-sal/sal-protocolbuffer-encoding/src/test/resources/odl-datastore-test-notification.yang b/opendaylight/md-sal/sal-clustering-commons/src/test/resources/odl-datastore-test-notification.yang similarity index 100% rename from opendaylight/md-sal/sal-protocolbuffer-encoding/src/test/resources/odl-datastore-test-notification.yang rename to opendaylight/md-sal/sal-clustering-commons/src/test/resources/odl-datastore-test-notification.yang diff --git a/opendaylight/md-sal/sal-protocolbuffer-encoding/src/test/resources/odl-datastore-test.yang b/opendaylight/md-sal/sal-clustering-commons/src/test/resources/odl-datastore-test.yang similarity index 100% rename from opendaylight/md-sal/sal-protocolbuffer-encoding/src/test/resources/odl-datastore-test.yang rename to opendaylight/md-sal/sal-clustering-commons/src/test/resources/odl-datastore-test.yang diff --git a/opendaylight/md-sal/sal-protocolbuffer-encoding/src/test/resources/simple_xml_with_attributes.xml b/opendaylight/md-sal/sal-clustering-commons/src/test/resources/simple_xml_with_attributes.xml similarity index 51% rename from opendaylight/md-sal/sal-protocolbuffer-encoding/src/test/resources/simple_xml_with_attributes.xml rename to opendaylight/md-sal/sal-clustering-commons/src/test/resources/simple_xml_with_attributes.xml index 0316d7a4a8..934d876747 100644 --- a/opendaylight/md-sal/sal-protocolbuffer-encoding/src/test/resources/simple_xml_with_attributes.xml +++ b/opendaylight/md-sal/sal-clustering-commons/src/test/resources/simple_xml_with_attributes.xml @@ -1,3 +1,13 @@ + + diff --git a/opendaylight/md-sal/sal-protocolbuffer-encoding/src/test/resources/test.yang b/opendaylight/md-sal/sal-clustering-commons/src/test/resources/test.yang similarity index 100% rename from opendaylight/md-sal/sal-protocolbuffer-encoding/src/test/resources/test.yang rename to opendaylight/md-sal/sal-clustering-commons/src/test/resources/test.yang diff --git a/opendaylight/md-sal/sal-clustering-commons/src/test/resources/version-compatibility-serialized-data/DataChangeListenerMessagesData b/opendaylight/md-sal/sal-clustering-commons/src/test/resources/version-compatibility-serialized-data/DataChangeListenerMessagesData new file mode 100644 index 0000000000..883bcad86c --- /dev/null +++ b/opendaylight/md-sal/sal-clustering-commons/src/test/resources/version-compatibility-serialized-data/DataChangeListenerMessagesData @@ -0,0 +1,4 @@ +23 +1 +test) +'(urn:protobuff?revision=2014-07-31)test \ No newline at end of file diff --git a/opendaylight/md-sal/sal-clustering-commons/src/test/resources/version-compatibility-serialized-data/ListenerRegistrationMessagesData b/opendaylight/md-sal/sal-clustering-commons/src/test/resources/version-compatibility-serialized-data/ListenerRegistrationMessagesData new file mode 100644 index 0000000000..1718a01d48 --- /dev/null +++ b/opendaylight/md-sal/sal-clustering-commons/src/test/resources/version-compatibility-serialized-data/ListenerRegistrationMessagesData @@ -0,0 +1,2 @@ + +m(urn:opendaylight:params:xml:ns:yang:controller:md:sal:dom:store:notification-test?revision=2014-04-15)family \ No newline at end of file diff --git a/opendaylight/md-sal/sal-clustering-commons/src/test/resources/version-compatibility-serialized-data/NormalizedNodeMessagesTestData b/opendaylight/md-sal/sal-clustering-commons/src/test/resources/version-compatibility-serialized-data/NormalizedNodeMessagesTestData new file mode 100644 index 0000000000..c4ec3776d2 --- /dev/null +++ b/opendaylight/md-sal/sal-clustering-commons/src/test/resources/version-compatibility-serialized-data/NormalizedNodeMessagesTestData @@ -0,0 +1,2 @@ + +test testValuefake \ No newline at end of file diff --git a/opendaylight/md-sal/sal-clustering-commons/src/test/resources/version-compatibility-serialized-data/PersistentMessagesTestData b/opendaylight/md-sal/sal-clustering-commons/src/test/resources/version-compatibility-serialized-data/PersistentMessagesTestData new file mode 100644 index 0000000000..efb8e15bcc --- /dev/null +++ b/opendaylight/md-sal/sal-clustering-commons/src/test/resources/version-compatibility-serialized-data/PersistentMessagesTestData @@ -0,0 +1,5 @@ + +test3 +1 +test) +'(urn:protobuff?revision=2014-07-31)test \ No newline at end of file diff --git a/opendaylight/md-sal/sal-clustering-commons/src/test/resources/version-compatibility-serialized-data/ShardManagerMessagesTestData b/opendaylight/md-sal/sal-clustering-commons/src/test/resources/version-compatibility-serialized-data/ShardManagerMessagesTestData new file mode 100644 index 0000000000..82eea07964 --- /dev/null +++ b/opendaylight/md-sal/sal-clustering-commons/src/test/resources/version-compatibility-serialized-data/ShardManagerMessagesTestData @@ -0,0 +1,2 @@ + + Inventory \ No newline at end of file diff --git a/opendaylight/md-sal/sal-clustering-commons/src/test/resources/version-compatibility-serialized-data/ShardTransactionChainMessagesTestData b/opendaylight/md-sal/sal-clustering-commons/src/test/resources/version-compatibility-serialized-data/ShardTransactionChainMessagesTestData new file mode 100644 index 0000000000..577d9c4efc --- /dev/null +++ b/opendaylight/md-sal/sal-clustering-commons/src/test/resources/version-compatibility-serialized-data/ShardTransactionChainMessagesTestData @@ -0,0 +1,2 @@ + + /actor/path \ No newline at end of file diff --git a/opendaylight/md-sal/sal-clustering-commons/src/test/resources/version-compatibility-serialized-data/ShardTransactionMessagesTestData b/opendaylight/md-sal/sal-clustering-commons/src/test/resources/version-compatibility-serialized-data/ShardTransactionMessagesTestData new file mode 100644 index 0000000000..db43fa48f4 --- /dev/null +++ b/opendaylight/md-sal/sal-clustering-commons/src/test/resources/version-compatibility-serialized-data/ShardTransactionMessagesTestData @@ -0,0 +1,5 @@ + +3 +1 +test) +'(urn:protobuff?revision=2014-07-31)test \ No newline at end of file diff --git a/opendaylight/md-sal/sal-clustering-commons/src/test/resources/version-compatibility-serialized-data/ThreePhaseCommitCohortMessagesTestData b/opendaylight/md-sal/sal-clustering-commons/src/test/resources/version-compatibility-serialized-data/ThreePhaseCommitCohortMessagesTestData new file mode 100644 index 0000000000..e19a122a54 --- /dev/null +++ b/opendaylight/md-sal/sal-clustering-commons/src/test/resources/version-compatibility-serialized-data/ThreePhaseCommitCohortMessagesTestData @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/opendaylight/md-sal/sal-clustering-commons/src/test/resources/version-compatibility-serialized-data/readme.txt b/opendaylight/md-sal/sal-clustering-commons/src/test/resources/version-compatibility-serialized-data/readme.txt new file mode 100644 index 0000000000..06a561e36c --- /dev/null +++ b/opendaylight/md-sal/sal-clustering-commons/src/test/resources/version-compatibility-serialized-data/readme.txt @@ -0,0 +1,18 @@ +This directory contains one serialized test data file for one of the messages in each .proto file. +These files are utilized as part of the test cases, mostly to fail the test cases in case some engineer has used +a different version of protocol buffer than what we ship with (Protocol Buffer 2.5.0) to generate the messages source f +file. + +1. If you see protocolbuffer version/invalid message exception in the test case + 1. ensure you are using the right version of protocol buffer/protoc compiler i.e protocol + +2. If you have knowingly updated an existing .proto message than please update the corresponding version-compatibility-serialized-data +file. You can get the file by commenting out the test file deletion in AbstractMessagesTest look for comments + + /* we will delete only the test file -- comment below if you want to capture the + version-compatibility-serialized-data test data file.The file will be generated at root of the sal-protocolbuffer-encoding + and you need to move it to version-compatbility-serialized-data folder renaming the file to include suffix "Data" + */ + +3. If you are creating a new .proto file -- Follow an existing test case e.g. ThreePhaseCommitCohortMessagesTest to + check how the test case is created and create the corresponding serialized test data file in version-compatibility-serialized-data diff --git a/opendaylight/md-sal/sal-clustering-config/pom.xml b/opendaylight/md-sal/sal-clustering-config/pom.xml new file mode 100644 index 0000000000..d726823b98 --- /dev/null +++ b/opendaylight/md-sal/sal-clustering-config/pom.xml @@ -0,0 +1,46 @@ + + + + + 4.0.0 + + org.opendaylight.controller + sal-parent + 1.1-SNAPSHOT + + sal-clustering-config + Configuration files for md-sal clustering + jar + + + + org.codehaus.mojo + build-helper-maven-plugin + + + attach-artifacts + + attach-artifact + + package + + + + ${project.build.directory}/classes/initial/*.conf + xml + config + + + + + + + + + diff --git a/opendaylight/md-sal/sal-clustering-config/src/main/resources/initial/05-clustering.xml.conf b/opendaylight/md-sal/sal-clustering-config/src/main/resources/initial/05-clustering.xml.conf new file mode 100644 index 0000000000..7891ee2088 --- /dev/null +++ b/opendaylight/md-sal/sal-clustering-config/src/main/resources/initial/05-clustering.xml.conf @@ -0,0 +1,85 @@ + + + + + + + + + prefix:dom-inmemory-data-broker + inmemory-data-broker + + + dom:schema-service + yang-schema-service + + + + config-dom-store-spi:config-dom-datastore + distributed-config-store-service + + + + operational-dom-store-spi:operational-dom-datastore + distributed-operational-store-service + + + + + prefix:distributed-operational-datastore-provider + distributed-operational-store-module + + dom:schema-service + yang-schema-service + + + + + prefix:distributed-config-datastore-provider + distributed-config-store-module + + dom:schema-service + yang-schema-service + + + + + prefix:remote-rpc-connector + remote-rpc-connector + + dom:dom-broker-osgi-registry + dom-broker + + + + + + + + config-dom-store-spi:config-dom-datastore + + distributed-config-store-service + /modules/module[type='distributed-config-datastore-provider'][name='distributed-config-store-module'] + + + + operational-dom-store-spi:operational-dom-datastore + + distributed-operational-store-service + /modules/module[type='distributed-operational-datastore-provider'][name='distributed-operational-store-module'] + + + + + + + + urn:opendaylight:params:xml:ns:yang:controller:md:sal:dom:impl?module=opendaylight-sal-dom-broker-impl&revision=2013-10-28 + + diff --git a/opendaylight/md-sal/sal-clustering-config/src/main/resources/initial/akka.conf b/opendaylight/md-sal/sal-clustering-config/src/main/resources/initial/akka.conf new file mode 100644 index 0000000000..9749ae27ae --- /dev/null +++ b/opendaylight/md-sal/sal-clustering-config/src/main/resources/initial/akka.conf @@ -0,0 +1,55 @@ + +odl-cluster-data { + akka { + actor { + provider = "akka.cluster.ClusterActorRefProvider" + serializers { + java = "akka.serialization.JavaSerializer" + proto = "akka.remote.serialization.ProtobufSerializer" + } + + serialization-bindings { + "com.google.protobuf.Message" = proto + + } + } + remote { + log-remote-lifecycle-events = off + netty.tcp { + hostname = "" + port = 2550 + maximum-frame-size = 2097152 + send-buffer-size = 52428800 + receive-buffer-size = 52428800 + } + } + + cluster { + seed-nodes = ["akka.tcp://opendaylight-cluster-data@:2550"] + + auto-down-unreachable-after = 10s + } + } +} + +odl-cluster-rpc { + akka { + actor { + provider = "akka.cluster.ClusterActorRefProvider" + + } + remote { + log-remote-lifecycle-events = off + netty.tcp { + hostname = "" + port = 2551 + } + } + + cluster { + seed-nodes = ["akka.tcp://opendaylight-cluster-rpc@:2551"] + + auto-down-unreachable-after = 10s + } + } +} diff --git a/opendaylight/md-sal/sal-clustering-config/src/main/resources/initial/module-shards.conf b/opendaylight/md-sal/sal-clustering-config/src/main/resources/initial/module-shards.conf new file mode 100644 index 0000000000..8449abb7b0 --- /dev/null +++ b/opendaylight/md-sal/sal-clustering-config/src/main/resources/initial/module-shards.conf @@ -0,0 +1,70 @@ +# This file describes which shards live on which members +# The format for a module-shards is as follows, +# { +# name = "" +# shards = [ +# { +# name="" +# replicas = [ +# "" +# ] +# ] +# } +# +# For Helium we support only one shard per module. Beyond Helium +# we will support more than 1 +# The replicas section is a collection of member names. This information +# will be used to decide on which members replicas of a particular shard will be +# located. Once replication is integrated with the distributed data store then +# this section can have multiple entries. +# +# + + +module-shards = [ + { + name = "default" + shards = [ + { + name="default" + replicas = [ + "member-1" + ] + } + ] + }, + { + name = "topology" + shards = [ + { + name="topology" + replicas = [ + "member-1" + ] + } + ] + }, + { + name = "inventory" + shards = [ + { + name="inventory" + replicas = [ + "member-1" + ] + } + ] + }, + { + name = "toaster" + shards = [ + { + name="toaster" + replicas = [ + "member-1" + ] + } + ] + } + +] diff --git a/opendaylight/md-sal/sal-clustering-config/src/main/resources/initial/modules.conf b/opendaylight/md-sal/sal-clustering-config/src/main/resources/initial/modules.conf new file mode 100644 index 0000000000..68347eeda9 --- /dev/null +++ b/opendaylight/md-sal/sal-clustering-config/src/main/resources/initial/modules.conf @@ -0,0 +1,32 @@ +# This file should describe all the modules that need to be placed in a separate shard +# The format of the configuration is as follows +# { +# name = "" +# namespace = "" +# shard-strategy = "module" +# } +# +# Note that at this time the only shard-strategy we support is module which basically +# will put all the data of a single module in two shards (one for config and one for +# operational data) + +modules = [ + { + name = "inventory" + namespace = "urn:opendaylight:inventory" + shard-strategy = "module" + }, + + { + name = "topology" + namespace = "urn:TBD:params:xml:ns:yang:network-topology" + shard-strategy = "module" + }, + + { + name = "toaster" + namespace = "http://netconfcentral.org/ns/toaster" + shard-strategy = "module" + } + +] diff --git a/opendaylight/md-sal/sal-common-api/pom.xml b/opendaylight/md-sal/sal-common-api/pom.xml index 3449c5488e..e46fe1fe78 100644 --- a/opendaylight/md-sal/sal-common-api/pom.xml +++ b/opendaylight/md-sal/sal-common-api/pom.xml @@ -19,6 +19,10 @@ org.opendaylight.yangtools concepts + + org.opendaylight.yangtools + util + org.opendaylight.yangtools yang-common diff --git a/opendaylight/md-sal/sal-common-api/src/main/java/org/opendaylight/controller/md/sal/common/api/data/ReadFailedException.java b/opendaylight/md-sal/sal-common-api/src/main/java/org/opendaylight/controller/md/sal/common/api/data/ReadFailedException.java new file mode 100644 index 0000000000..b0a7807b76 --- /dev/null +++ b/opendaylight/md-sal/sal-common-api/src/main/java/org/opendaylight/controller/md/sal/common/api/data/ReadFailedException.java @@ -0,0 +1,37 @@ +/* + * Copyright (c) 2014 Brocade Communications Systems, Inc. and others. All rights reserved. + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License v1.0 which accompanies this distribution, + * and is available at http://www.eclipse.org/legal/epl-v10.html + */ + +package org.opendaylight.controller.md.sal.common.api.data; + +import org.opendaylight.yangtools.util.concurrent.ExceptionMapper; +import org.opendaylight.yangtools.yang.common.OperationFailedException; +import org.opendaylight.yangtools.yang.common.RpcError; + +/** + * An exception for a failed read. + */ +public class ReadFailedException extends OperationFailedException { + + private static final long serialVersionUID = 1L; + + public static final ExceptionMapper MAPPER = + new ExceptionMapper("read", ReadFailedException.class) { + @Override + protected ReadFailedException newWithCause(String message, Throwable cause) { + return new ReadFailedException(message, cause); + } + }; + + public ReadFailedException(String message, RpcError... errors) { + super(message, errors); + } + + public ReadFailedException(String message, Throwable cause, RpcError... errors) { + super(message, cause, errors); + } +} diff --git a/opendaylight/md-sal/sal-common-api/src/main/java/org/opendaylight/controller/md/sal/common/api/data/TransactionCommitDeadlockException.java b/opendaylight/md-sal/sal-common-api/src/main/java/org/opendaylight/controller/md/sal/common/api/data/TransactionCommitDeadlockException.java new file mode 100644 index 0000000000..60313bf109 --- /dev/null +++ b/opendaylight/md-sal/sal-common-api/src/main/java/org/opendaylight/controller/md/sal/common/api/data/TransactionCommitDeadlockException.java @@ -0,0 +1,46 @@ +/* + * Copyright (c) 2014 Brocade Communications Systems, Inc. and others. All rights reserved. + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License v1.0 which accompanies this distribution, + * and is available at http://www.eclipse.org/legal/epl-v10.html + */ + +package org.opendaylight.controller.md.sal.common.api.data; + +import org.opendaylight.yangtools.yang.common.RpcError; +import org.opendaylight.yangtools.yang.common.RpcResultBuilder; +import org.opendaylight.yangtools.yang.common.RpcError.ErrorType; + +import com.google.common.base.Function; + +/** + * A type of TransactionCommitFailedException that indicates a situation that would result in a + * threading deadlock. This can occur if a caller that submits a write transaction tries to perform + * a blocking call via one of the get methods on the returned ListenableFuture. Callers + * should process the commit result asynchronously (via Futures#addCallback) to ensure deadlock + * won't occur. + * + * @author Thomas Pantelis + */ +public class TransactionCommitDeadlockException extends TransactionCommitFailedException { + + private static final long serialVersionUID = 1L; + + private static final String DEADLOCK_MESSAGE = + "An attempt to block on a ListenableFuture via a get method from a write " + + "transaction submit was detected that would result in deadlock. The commit " + + "result must be obtained asynchronously, e.g. via Futures#addCallback, to avoid deadlock."; + + public static Function DEADLOCK_EXECUTOR_FUNCTION = new Function() { + @Override + public Exception apply(Void notUsed) { + return new TransactionCommitDeadlockException( DEADLOCK_MESSAGE, + RpcResultBuilder.newError(ErrorType.APPLICATION, "lock-denied", DEADLOCK_MESSAGE)); + } + }; + + public TransactionCommitDeadlockException(String message, final RpcError... errors) { + super(message, errors); + } +} diff --git a/opendaylight/md-sal/sal-common-api/src/main/java/org/opendaylight/controller/md/sal/common/api/data/TransactionCommitFailedException.java b/opendaylight/md-sal/sal-common-api/src/main/java/org/opendaylight/controller/md/sal/common/api/data/TransactionCommitFailedException.java index 18a857e1d5..7ac76e47b1 100644 --- a/opendaylight/md-sal/sal-common-api/src/main/java/org/opendaylight/controller/md/sal/common/api/data/TransactionCommitFailedException.java +++ b/opendaylight/md-sal/sal-common-api/src/main/java/org/opendaylight/controller/md/sal/common/api/data/TransactionCommitFailedException.java @@ -7,14 +7,8 @@ */ package org.opendaylight.controller.md.sal.common.api.data; -import java.util.Arrays; -import java.util.List; - +import org.opendaylight.yangtools.yang.common.OperationFailedException; import org.opendaylight.yangtools.yang.common.RpcError; -import org.opendaylight.yangtools.yang.common.RpcResultBuilder; -import org.opendaylight.yangtools.yang.common.RpcError.ErrorType; - -import com.google.common.collect.ImmutableList; /** * @@ -24,41 +18,16 @@ import com.google.common.collect.ImmutableList; * failed. * */ -public class TransactionCommitFailedException extends Exception { +public class TransactionCommitFailedException extends OperationFailedException { private static final long serialVersionUID = 1L; - private final List errorList; - public TransactionCommitFailedException(final String message, final RpcError... errors) { this(message, null, errors); } public TransactionCommitFailedException(final String message, final Throwable cause, final RpcError... errors) { - super(message, cause); - - if( errors != null && errors.length > 0 ) { - errorList = ImmutableList.builder().addAll( Arrays.asList( errors ) ).build(); - } - else { - // Add a default RpcError. - errorList = ImmutableList.of(RpcResultBuilder.newError(ErrorType.APPLICATION, null, - getMessage(), null, null, getCause())); - } - } - - /** - * Returns additional error information about this exception. - * - * @return a List of RpcErrors. There is always at least one RpcError. - */ - public List getErrorList() { - return errorList; - } - - @Override - public String getMessage() { - return new StringBuilder( super.getMessage() ).append(", errors: ").append( errorList ).toString(); + super(message, cause, errors); } } diff --git a/opendaylight/md-sal/sal-common-util/pom.xml b/opendaylight/md-sal/sal-common-util/pom.xml index 9108f8603b..e42c86a993 100644 --- a/opendaylight/md-sal/sal-common-util/pom.xml +++ b/opendaylight/md-sal/sal-common-util/pom.xml @@ -15,6 +15,11 @@ com.google.guava guava + + junit + junit + test + org.opendaylight.controller sal-common-api diff --git a/opendaylight/md-sal/sal-distributed-datastore/client.conf b/opendaylight/md-sal/sal-distributed-datastore/client.conf new file mode 100644 index 0000000000..90bfb4c3e1 --- /dev/null +++ b/opendaylight/md-sal/sal-distributed-datastore/client.conf @@ -0,0 +1,36 @@ +ODLCluster{ + akka { + actor { + serialize-messages = on + + provider = "akka.cluster.ClusterActorRefProvider" + serializers { + java = "akka.serialization.JavaSerializer" + proto = "akka.remote.serialization.ProtobufSerializer" + } + + serialization-bindings { + "com.google.protobuf.Message" = proto + "com.google.protobuf.GeneratedMessage" = proto + "com.google.protobuf.GeneratedMessage$GeneratedExtension" = proto + "com.google.protobuf.FieldSet" = proto + } + } + remote { + log-remote-lifecycle-events = off + netty.tcp { + hostname = "127.0.0.1" + port = 2552 + maximum-frame-size = 2097152 + send-buffer-size = 52428800 + receive-buffer-size = 52428800 + } + } + + cluster { + seed-nodes = ["akka.tcp://opendaylight-cluster@127.0.0.1:2550"] + + auto-down-unreachable-after = 10s + } + } +} diff --git a/opendaylight/md-sal/sal-distributed-datastore/pom.xml b/opendaylight/md-sal/sal-distributed-datastore/pom.xml index 94c895dab3..848d425bf9 100644 --- a/opendaylight/md-sal/sal-distributed-datastore/pom.xml +++ b/opendaylight/md-sal/sal-distributed-datastore/pom.xml @@ -120,7 +120,7 @@ org.opendaylight.controller - sal-protocolbuffer-encoding + sal-clustering-commons 1.1-SNAPSHOT @@ -165,7 +165,7 @@ !*snappy;!org.jboss.*;* - sal-protocolbuffer-encoding; + sal-clustering-commons; sal-akka-raft; !sal*; !*config-api*; diff --git a/opendaylight/md-sal/sal-distributed-datastore/server.conf b/opendaylight/md-sal/sal-distributed-datastore/server.conf new file mode 100644 index 0000000000..6209adfc17 --- /dev/null +++ b/opendaylight/md-sal/sal-distributed-datastore/server.conf @@ -0,0 +1,37 @@ + +ODLCluster{ + akka { + actor { + serialize-messages = on + + provider = "akka.cluster.ClusterActorRefProvider" + serializers { + java = "akka.serialization.JavaSerializer" + proto = "akka.remote.serialization.ProtobufSerializer" + } + + serialization-bindings { + "com.google.protobuf.Message" = proto + "com.google.protobuf.GeneratedMessage" = proto + "com.google.protobuf.GeneratedMessage$GeneratedExtension" = proto + "com.google.protobuf.FieldSet" = proto + } + } + remote { + log-remote-lifecycle-events = off + netty.tcp { + hostname = "127.0.0.1" + port = 2550 + maximum-frame-size = 2097152 + send-buffer-size = 52428800 + receive-buffer-size = 52428800 + } + } + + cluster { + seed-nodes = ["akka.tcp://opendaylight-cluster@127.0.0.1:2550"] + + auto-down-unreachable-after = 10s + } + } +} diff --git a/opendaylight/md-sal/sal-distributed-datastore/src/main/java/org/opendaylight/controller/cluster/datastore/ActorSystemFactory.java b/opendaylight/md-sal/sal-distributed-datastore/src/main/java/org/opendaylight/controller/cluster/datastore/ActorSystemFactory.java index baf04fe43b..15c0548761 100644 --- a/opendaylight/md-sal/sal-distributed-datastore/src/main/java/org/opendaylight/controller/cluster/datastore/ActorSystemFactory.java +++ b/opendaylight/md-sal/sal-distributed-datastore/src/main/java/org/opendaylight/controller/cluster/datastore/ActorSystemFactory.java @@ -20,8 +20,8 @@ public class ActorSystemFactory { @Nullable @Override public ActorSystem apply(@Nullable Void aVoid) { ActorSystem system = - ActorSystem.create("opendaylight-cluster", ConfigFactory - .load().getConfig("ODLCluster")); + ActorSystem.create("opendaylight-cluster-data", ConfigFactory + .load().getConfig("odl-cluster-data")); system.actorOf(Props.create(TerminationMonitor.class), "termination-monitor"); return system; } diff --git a/opendaylight/md-sal/sal-distributed-datastore/src/main/java/org/opendaylight/controller/cluster/datastore/CompositeModificationPayload.java b/opendaylight/md-sal/sal-distributed-datastore/src/main/java/org/opendaylight/controller/cluster/datastore/CompositeModificationPayload.java index 955e4bbf22..abc69f1897 100644 --- a/opendaylight/md-sal/sal-distributed-datastore/src/main/java/org/opendaylight/controller/cluster/datastore/CompositeModificationPayload.java +++ b/opendaylight/md-sal/sal-distributed-datastore/src/main/java/org/opendaylight/controller/cluster/datastore/CompositeModificationPayload.java @@ -10,7 +10,8 @@ package org.opendaylight.controller.cluster.datastore; import com.google.common.base.Preconditions; import com.google.protobuf.GeneratedMessage; -import org.opendaylight.controller.cluster.example.protobuff.messages.KeyValueMessages; +import com.google.protobuf.InvalidProtocolBufferException; +import com.google.protobuf.UnknownFieldSet; import org.opendaylight.controller.cluster.raft.protobuff.client.messages.Payload; import org.opendaylight.controller.cluster.raft.protobuff.messages.AppendEntriesMessages; import org.opendaylight.controller.protobuff.messages.persistent.PersistentMessages; @@ -43,7 +44,28 @@ public class CompositeModificationPayload extends Payload implements PersistentMessages.CompositeModification modification = payload .getExtension( org.opendaylight.controller.mdsal.CompositeModificationPayload.modification); - payload.getExtension(KeyValueMessages.value); + + + + // The extension was put in the unknown field. + // This is because extensions need to be registered + // see org.opendaylight.controller.mdsal.CompositeModificationPayload.registerAllExtensions + // also see https://developers.google.com/protocol-buffers/docs/reference/java/com/google/protobuf/ExtensionRegistry + // If that is not done then on the other end the extension shows up as an unknown field + // Need to figure out a better way to do this + if(payload.getUnknownFields().hasField(2)){ + UnknownFieldSet.Field field = + payload.getUnknownFields().getField(2); + + try { + modification = + PersistentMessages.CompositeModification + .parseFrom(field.getLengthDelimitedList().get(0)); + } catch (InvalidProtocolBufferException e) { + + } + } + return new CompositeModificationPayload(modification); } diff --git a/opendaylight/md-sal/sal-distributed-datastore/src/main/java/org/opendaylight/controller/cluster/datastore/DataChangeListener.java b/opendaylight/md-sal/sal-distributed-datastore/src/main/java/org/opendaylight/controller/cluster/datastore/DataChangeListener.java index 3af6f56a2c..cdf04dd093 100644 --- a/opendaylight/md-sal/sal-distributed-datastore/src/main/java/org/opendaylight/controller/cluster/datastore/DataChangeListener.java +++ b/opendaylight/md-sal/sal-distributed-datastore/src/main/java/org/opendaylight/controller/cluster/datastore/DataChangeListener.java @@ -12,6 +12,7 @@ import akka.actor.Props; import akka.japi.Creator; import org.opendaylight.controller.cluster.datastore.messages.DataChanged; import org.opendaylight.controller.cluster.datastore.messages.DataChangedReply; +import org.opendaylight.controller.cluster.datastore.messages.EnableNotification; import org.opendaylight.controller.md.sal.common.api.data.AsyncDataChangeEvent; import org.opendaylight.controller.md.sal.common.api.data.AsyncDataChangeListener; import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier; @@ -22,6 +23,7 @@ public class DataChangeListener extends AbstractUntypedActor { private final AsyncDataChangeListener> listener; private final SchemaContext schemaContext; private final YangInstanceIdentifier pathId; + private boolean notificationsEnabled = false; public DataChangeListener(SchemaContext schemaContext, AsyncDataChangeListener> listener, YangInstanceIdentifier pathId) { @@ -31,16 +33,31 @@ public class DataChangeListener extends AbstractUntypedActor { } @Override public void handleReceive(Object message) throws Exception { - if(message.getClass().equals(DataChanged.SERIALIZABLE_CLASS)){ - DataChanged reply = DataChanged.fromSerialize(schemaContext,message, pathId); - AsyncDataChangeEvent> - change = reply.getChange(); - this.listener.onDataChanged(change); - - if(getSender() != null){ - getSender().tell(new DataChangedReply().toSerializable(), getSelf()); - } + if(message instanceof DataChanged){ + dataChanged(message); + } else if(message instanceof EnableNotification){ + enableNotification((EnableNotification) message); + } + } + + private void enableNotification(EnableNotification message) { + notificationsEnabled = message.isEnabled(); + } + + public void dataChanged(Object message) { + + // Do nothing if notifications are not enabled + if(!notificationsEnabled){ + return; + } + + DataChanged reply = (DataChanged) message; + AsyncDataChangeEvent> + change = reply.getChange(); + this.listener.onDataChanged(change); + if(getSender() != null){ + getSender().tell(new DataChangedReply(), getSelf()); } } diff --git a/opendaylight/md-sal/sal-distributed-datastore/src/main/java/org/opendaylight/controller/cluster/datastore/DataChangeListenerProxy.java b/opendaylight/md-sal/sal-distributed-datastore/src/main/java/org/opendaylight/controller/cluster/datastore/DataChangeListenerProxy.java index cd9c330268..a4ca456268 100644 --- a/opendaylight/md-sal/sal-distributed-datastore/src/main/java/org/opendaylight/controller/cluster/datastore/DataChangeListenerProxy.java +++ b/opendaylight/md-sal/sal-distributed-datastore/src/main/java/org/opendaylight/controller/cluster/datastore/DataChangeListenerProxy.java @@ -30,6 +30,6 @@ public class DataChangeListenerProxy implements AsyncDataChangeListener> change) { - dataChangeListenerActor.tell(new DataChanged(schemaContext,change).toSerializable(), null); + dataChangeListenerActor.tell(new DataChanged(schemaContext,change), null); } } diff --git a/opendaylight/md-sal/sal-distributed-datastore/src/main/java/org/opendaylight/controller/cluster/datastore/DistributedDataStore.java b/opendaylight/md-sal/sal-distributed-datastore/src/main/java/org/opendaylight/controller/cluster/datastore/DistributedDataStore.java index 2ef8e5f449..479af79748 100644 --- a/opendaylight/md-sal/sal-distributed-datastore/src/main/java/org/opendaylight/controller/cluster/datastore/DistributedDataStore.java +++ b/opendaylight/md-sal/sal-distributed-datastore/src/main/java/org/opendaylight/controller/cluster/datastore/DistributedDataStore.java @@ -10,6 +10,8 @@ package org.opendaylight.controller.cluster.datastore; import akka.actor.ActorRef; import akka.actor.ActorSystem; +import com.google.common.util.concurrent.ListeningExecutorService; +import com.google.common.util.concurrent.MoreExecutors; import org.opendaylight.controller.cluster.datastore.messages.RegisterChangeListener; import org.opendaylight.controller.cluster.datastore.messages.RegisterChangeListenerReply; import org.opendaylight.controller.cluster.datastore.messages.UpdateSchemaContext; @@ -30,7 +32,6 @@ import org.opendaylight.yangtools.yang.model.api.SchemaContextListener; import org.slf4j.Logger; import org.slf4j.LoggerFactory; -import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; /** @@ -41,6 +42,7 @@ public class DistributedDataStore implements DOMStore, SchemaContextListener, Au private static final Logger LOG = LoggerFactory.getLogger(DistributedDataStore.class); + private static final int DEFAULT_EXECUTOR_POOL_SIZE = 10; private final String type; private final ActorContext actorContext; @@ -55,10 +57,10 @@ public class DistributedDataStore implements DOMStore, SchemaContextListener, Au * This is typically used when we need to make a request to an actor and * wait for it's response and the consumer needs to be provided a Future. * - * FIXME : Make the thread pool configurable + * FIXME : Make the thread pool size configurable. */ - private final ExecutorService executor = - Executors.newFixedThreadPool(10); + private final ListeningExecutorService executor = + MoreExecutors.listeningDecorator(Executors.newFixedThreadPool(DEFAULT_EXECUTOR_POOL_SIZE)); public DistributedDataStore(ActorSystem actorSystem, String type, ClusterWrapper cluster, Configuration configuration) { this(new ActorContext(actorSystem, actorSystem @@ -82,18 +84,29 @@ public class DistributedDataStore implements DOMStore, SchemaContextListener, Au String shardName = ShardStrategyFactory.getStrategy(path).findShard(path); - Object result = actorContext.executeShardOperation(shardName, + Object result = actorContext.executeLocalShardOperation(shardName, new RegisterChangeListener(path, dataChangeListenerActor.path(), - scope).toSerializable(), + scope), ActorContext.ASK_DURATION ); - RegisterChangeListenerReply reply = RegisterChangeListenerReply.fromSerializable(actorContext.getActorSystem(),result); - return new DataChangeListenerRegistrationProxy(actorContext.actorSelection(reply.getListenerRegistrationPath()), listener, dataChangeListenerActor); + if (result != null) { + RegisterChangeListenerReply reply = (RegisterChangeListenerReply) result; + return new DataChangeListenerRegistrationProxy(actorContext + .actorSelection(reply.getListenerRegistrationPath()), listener, + dataChangeListenerActor); + } + + LOG.debug( + "No local shard for shardName {} was found so returning a noop registration", + shardName); + return new NoOpDataChangeListenerRegistration(listener); } + + @Override public DOMStoreTransactionChain createTransactionChain() { return new TransactionChainProxy(actorContext, executor, schemaContext); diff --git a/opendaylight/md-sal/sal-distributed-datastore/src/main/java/org/opendaylight/controller/cluster/datastore/DistributedDataStoreFactory.java b/opendaylight/md-sal/sal-distributed-datastore/src/main/java/org/opendaylight/controller/cluster/datastore/DistributedDataStoreFactory.java index 692d1b4954..6d87271f00 100644 --- a/opendaylight/md-sal/sal-distributed-datastore/src/main/java/org/opendaylight/controller/cluster/datastore/DistributedDataStoreFactory.java +++ b/opendaylight/md-sal/sal-distributed-datastore/src/main/java/org/opendaylight/controller/cluster/datastore/DistributedDataStoreFactory.java @@ -20,7 +20,7 @@ public class DistributedDataStoreFactory { new DistributedDataStore(actorSystem, name, new ClusterWrapperImpl(actorSystem),config ); ShardStrategyFactory.setConfiguration(config); schemaService - .registerSchemaServiceListener(dataStore); + .registerSchemaContextListener(dataStore); return dataStore; } diff --git a/opendaylight/md-sal/sal-distributed-datastore/src/main/java/org/opendaylight/controller/cluster/datastore/NoOpDataChangeListenerRegistration.java b/opendaylight/md-sal/sal-distributed-datastore/src/main/java/org/opendaylight/controller/cluster/datastore/NoOpDataChangeListenerRegistration.java new file mode 100644 index 0000000000..14af31e898 --- /dev/null +++ b/opendaylight/md-sal/sal-distributed-datastore/src/main/java/org/opendaylight/controller/cluster/datastore/NoOpDataChangeListenerRegistration.java @@ -0,0 +1,46 @@ +/* + * 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.cluster.datastore; + +import org.opendaylight.controller.md.sal.common.api.data.AsyncDataChangeListener; +import org.opendaylight.yangtools.concepts.ListenerRegistration; +import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier; +import org.opendaylight.yangtools.yang.data.api.schema.NormalizedNode; + +/** + * When a consumer registers a data change listener and no local shard is + * available to register that listener with then we return an instance of + * NoOpDataChangeListenerRegistration + * + *

    + * + * The NoOpDataChangeListenerRegistration as it's name suggests does + * nothing when an operation is invoked on it + */ +public class NoOpDataChangeListenerRegistration + implements ListenerRegistration { + + private final AsyncDataChangeListener> + listener; + + public >> NoOpDataChangeListenerRegistration( + AsyncDataChangeListener> listener) { + + this.listener = listener; + } + + @Override + public AsyncDataChangeListener> getInstance() { + return listener; + } + + @Override public void close() { + + } +} diff --git a/opendaylight/md-sal/sal-distributed-datastore/src/main/java/org/opendaylight/controller/cluster/datastore/Shard.java b/opendaylight/md-sal/sal-distributed-datastore/src/main/java/org/opendaylight/controller/cluster/datastore/Shard.java index 999d0f8baf..10dbbc84d8 100644 --- a/opendaylight/md-sal/sal-distributed-datastore/src/main/java/org/opendaylight/controller/cluster/datastore/Shard.java +++ b/opendaylight/md-sal/sal-distributed-datastore/src/main/java/org/opendaylight/controller/cluster/datastore/Shard.java @@ -15,6 +15,7 @@ import akka.event.Logging; import akka.event.LoggingAdapter; import akka.japi.Creator; import akka.serialization.Serialization; +import com.google.common.base.Optional; import com.google.common.util.concurrent.ListenableFuture; import com.google.common.util.concurrent.ListeningExecutorService; import com.google.common.util.concurrent.MoreExecutors; @@ -25,6 +26,7 @@ import org.opendaylight.controller.cluster.datastore.messages.CreateTransaction; import org.opendaylight.controller.cluster.datastore.messages.CreateTransactionChain; import org.opendaylight.controller.cluster.datastore.messages.CreateTransactionChainReply; import org.opendaylight.controller.cluster.datastore.messages.CreateTransactionReply; +import org.opendaylight.controller.cluster.datastore.messages.EnableNotification; import org.opendaylight.controller.cluster.datastore.messages.ForwardedCommitTransaction; import org.opendaylight.controller.cluster.datastore.messages.PeerAddressResolved; import org.opendaylight.controller.cluster.datastore.messages.RegisterChangeListener; @@ -32,6 +34,8 @@ import org.opendaylight.controller.cluster.datastore.messages.RegisterChangeList import org.opendaylight.controller.cluster.datastore.messages.UpdateSchemaContext; import org.opendaylight.controller.cluster.datastore.modification.Modification; import org.opendaylight.controller.cluster.datastore.modification.MutableCompositeModification; +import org.opendaylight.controller.cluster.raft.ConfigParams; +import org.opendaylight.controller.cluster.raft.DefaultConfigParamsImpl; import org.opendaylight.controller.cluster.raft.RaftActor; import org.opendaylight.controller.md.sal.common.api.data.AsyncDataChangeListener; import org.opendaylight.controller.md.sal.dom.store.impl.InMemoryDOMDataStore; @@ -41,11 +45,15 @@ import org.opendaylight.controller.sal.core.spi.data.DOMStoreTransactionChain; import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier; import org.opendaylight.yangtools.yang.data.api.schema.NormalizedNode; import org.opendaylight.yangtools.yang.model.api.SchemaContext; +import scala.concurrent.duration.FiniteDuration; +import java.util.ArrayList; import java.util.HashMap; +import java.util.List; import java.util.Map; import java.util.concurrent.ExecutionException; import java.util.concurrent.Executors; +import java.util.concurrent.TimeUnit; /** * A Shard represents a portion of the logical data tree
    @@ -55,6 +63,8 @@ import java.util.concurrent.Executors; */ public class Shard extends RaftActor { + private static final ConfigParams configParams = new ShardConfigParams(); + public static final String DEFAULT_NAME = "default"; private final ListeningExecutorService storeExecutor = @@ -74,12 +84,14 @@ public class Shard extends RaftActor { private final String name; - private SchemaContext schemaContext; + private volatile SchemaContext schemaContext; private final ShardStats shardMBean; + private final List dataChangeListeners = new ArrayList<>(); + private Shard(String name, Map peerAddresses) { - super(name, peerAddresses); + super(name, peerAddresses, Optional.of(configParams)); this.name = name; @@ -116,8 +128,8 @@ public class Shard extends RaftActor { } else if(getLeader() != null){ getLeader().forward(message, getContext()); } - } else if (message.getClass().equals(RegisterChangeListener.SERIALIZABLE_CLASS)) { - registerChangeListener(RegisterChangeListener.fromSerializable(getContext().system(), message)); + } else if (message instanceof RegisterChangeListener) { + registerChangeListener((RegisterChangeListener) message); } else if (message instanceof UpdateSchemaContext) { updateSchemaContext((UpdateSchemaContext) message); } else if (message instanceof ForwardedCommitTransaction) { @@ -136,13 +148,29 @@ public class Shard extends RaftActor { } } + private ActorRef createTypedTransactionActor(CreateTransaction createTransaction,String transactionId){ + if(createTransaction.getTransactionType()== TransactionProxy.TransactionType.READ_ONLY.ordinal()){ + return getContext().actorOf( + ShardTransaction.props( store.newReadOnlyTransaction(), getSelf(), schemaContext), transactionId); + + }else if (createTransaction.getTransactionType()== TransactionProxy.TransactionType.READ_WRITE.ordinal()){ + return getContext().actorOf( + ShardTransaction.props( store.newReadWriteTransaction(), getSelf(), schemaContext), transactionId); + + + }else if (createTransaction.getTransactionType()== TransactionProxy.TransactionType.WRITE_ONLY.ordinal()){ + return getContext().actorOf( + ShardTransaction.props( store.newWriteOnlyTransaction(), getSelf(), schemaContext), transactionId); + }else{ + throw new IllegalArgumentException ("CreateTransaction message has unidentified transaction type="+createTransaction.getTransactionType()) ; + } + } + private void createTransaction(CreateTransaction createTransaction) { - DOMStoreReadWriteTransaction transaction = - store.newReadWriteTransaction(); + String transactionId = "shard-" + createTransaction.getTransactionId(); LOG.info("Creating transaction : {} " , transactionId); - ActorRef transactionActor = getContext().actorOf( - ShardTransaction.props(transaction, getSelf(), schemaContext), transactionId); + ActorRef transactionActor = createTypedTransactionActor(createTransaction,transactionId); getSender() .tell(new CreateTransactionReply(Serialization.serializedActorPath(transactionActor), createTransaction.getTransactionId()).toSerializable(), @@ -155,10 +183,23 @@ public class Shard extends RaftActor { modificationToCohort.remove(serialized); if (cohort == null) { LOG.error( - "Could not find cohort for modification : " + modification); + "Could not find cohort for modification : {}", modification); LOG.info("Writing modification using a new transaction"); - modification.apply(store.newReadWriteTransaction()); - return; + DOMStoreReadWriteTransaction transaction = + store.newReadWriteTransaction(); + modification.apply(transaction); + DOMStoreThreePhaseCommitCohort commitCohort = transaction.ready(); + ListenableFuture future = + commitCohort.preCommit(); + try { + future.get(); + future = commitCohort.commit(); + future.get(); + } catch (InterruptedException e) { + LOG.error("Failed to commit", e); + } catch (ExecutionException e) { + LOG.error("Failed to commit", e); + } } final ListenableFuture future = cohort.commit(); @@ -213,6 +254,16 @@ public class Shard extends RaftActor { .system().actorSelection( registerChangeListener.getDataChangeListenerPath()); + + // Notify the listener if notifications should be enabled or not + // If this shard is the leader then it will enable notifications else + // it will not + dataChangeListenerPath.tell(new EnableNotification(isLeader()), getSelf()); + + // Now store a reference to the data change listener so it can be notified + // at a later point if notifications should be enabled or disabled + dataChangeListeners.add(dataChangeListenerPath); + AsyncDataChangeListener> listener = new DataChangeListenerProxy(schemaContext,dataChangeListenerPath); @@ -227,7 +278,7 @@ public class Shard extends RaftActor { LOG.debug("registerDataChangeListener sending reply, listenerRegistrationPath = " + listenerRegistration.path().toString()); getSender() - .tell(new RegisterChangeListenerReply(listenerRegistration.path()).toSerializable(), + .tell(new RegisterChangeListenerReply(listenerRegistration.path()), getSelf()); } @@ -248,7 +299,14 @@ public class Shard extends RaftActor { if(data instanceof CompositeModificationPayload){ Object modification = ((CompositeModificationPayload) data).getModification(); - commit(clientActor, modification); + + if(modification != null){ + commit(clientActor, modification); + } else { + LOG.error("modification is null - this is very unexpected"); + } + + } else { LOG.error("Unknown state received {}", data); } @@ -263,7 +321,29 @@ public class Shard extends RaftActor { throw new UnsupportedOperationException("applySnapshot"); } + @Override protected void onStateChanged() { + for(ActorSelection dataChangeListener : dataChangeListeners){ + dataChangeListener.tell(new EnableNotification(isLeader()), getSelf()); + } + + if(getLeaderId() != null){ + shardMBean.setLeader(getLeaderId()); + } + + shardMBean.setRaftState(getRaftState().name()); + } + @Override public String persistenceId() { return this.name; } + + + private static class ShardConfigParams extends DefaultConfigParamsImpl { + public static final FiniteDuration HEART_BEAT_INTERVAL = + new FiniteDuration(500, TimeUnit.MILLISECONDS); + + @Override public FiniteDuration getHeartBeatInterval() { + return HEART_BEAT_INTERVAL; + } + } } diff --git a/opendaylight/md-sal/sal-distributed-datastore/src/main/java/org/opendaylight/controller/cluster/datastore/ShardManager.java b/opendaylight/md-sal/sal-distributed-datastore/src/main/java/org/opendaylight/controller/cluster/datastore/ShardManager.java index 5fbce4cd98..64c6821120 100644 --- a/opendaylight/md-sal/sal-distributed-datastore/src/main/java/org/opendaylight/controller/cluster/datastore/ShardManager.java +++ b/opendaylight/md-sal/sal-distributed-datastore/src/main/java/org/opendaylight/controller/cluster/datastore/ShardManager.java @@ -18,7 +18,10 @@ import akka.cluster.ClusterEvent; import akka.japi.Creator; import akka.japi.Function; import com.google.common.base.Preconditions; +import org.opendaylight.controller.cluster.datastore.messages.FindLocalShard; import org.opendaylight.controller.cluster.datastore.messages.FindPrimary; +import org.opendaylight.controller.cluster.datastore.messages.LocalShardFound; +import org.opendaylight.controller.cluster.datastore.messages.LocalShardNotFound; import org.opendaylight.controller.cluster.datastore.messages.PeerAddressResolved; import org.opendaylight.controller.cluster.datastore.messages.PrimaryFound; import org.opendaylight.controller.cluster.datastore.messages.PrimaryNotFound; @@ -31,35 +34,27 @@ import java.util.Map; /** * The ShardManager has the following jobs, - *

    + *

      *
    • Create all the local shard replicas that belong on this cluster member + *
    • Find the address of the local shard *
    • Find the primary replica for any given shard - *
    • Engage in shard replica elections which decide which replica should be the primary - *

      - *

      - *

      >Creation of Shard replicas

      - * When the ShardManager is constructed it reads the cluster configuration to find out which shard replicas - * belong on this member. It finds out the name of the current cluster member from the Akka Clustering Service. - *

      - *

      - *

      Replica Elections

      - *

      - *

      - * The Shard Manager uses multiple cues to initiate election. - *

    • When a member of the cluster dies - *
    • When a local shard replica dies - *
    • When a local shard replica comes alive - *

      + *
    • Monitor the cluster members and store their addresses + *
        */ public class ShardManager extends AbstractUntypedActor { // Stores a mapping between a member name and the address of the member + // Member names look like "member-1", "member-2" etc and are as specified + // in configuration private final Map memberNameToAddress = new HashMap<>(); + // Stores a mapping between a shard name and it's corresponding information + // Shard names look like inventory, topology etc and are as specified in + // configuration private final Map localShards = new HashMap<>(); - + // The type of a ShardManager reflects the type of the datastore itself + // A data store could be of type config/operational private final String type; private final ClusterWrapper cluster; @@ -102,7 +97,8 @@ public class ShardManager extends AbstractUntypedActor { if (message.getClass().equals(FindPrimary.SERIALIZABLE_CLASS)) { findPrimary( FindPrimary.fromSerializable(message)); - + } else if(message instanceof FindLocalShard){ + findLocalShard((FindLocalShard) message); } else if (message instanceof UpdateSchemaContext) { updateSchemaContext(message); } else if (message instanceof ClusterEvent.MemberUp){ @@ -117,6 +113,18 @@ public class ShardManager extends AbstractUntypedActor { } + private void findLocalShard(FindLocalShard message) { + ShardInformation shardInformation = + localShards.get(message.getShardName()); + + if(shardInformation != null){ + getSender().tell(new LocalShardFound(shardInformation.getActor()), getSelf()); + return; + } + + getSender().tell(new LocalShardNotFound(message.getShardName()), getSelf()); + } + private void ignoreMessage(Object message){ LOG.debug("Unhandled message : " + message); } @@ -137,6 +145,11 @@ public class ShardManager extends AbstractUntypedActor { } } + /** + * Notifies all the local shards of a change in the schema context + * + * @param message + */ private void updateSchemaContext(Object message) { for(ShardInformation info : localShards.values()){ info.getActor().tell(message,getSelf()); @@ -180,10 +193,7 @@ public class ShardManager extends AbstractUntypedActor { getSender().tell(new PrimaryNotFound(shardName).toSerializable(), getSelf()); } - private String - - - getShardActorPath(String shardName, String memberName) { + private String getShardActorPath(String shardName, String memberName) { Address address = memberNameToAddress.get(memberName); if(address != null) { return address.toString() + "/user/shardmanager-" + this.type + "/" @@ -193,11 +203,23 @@ public class ShardManager extends AbstractUntypedActor { return null; } + /** + * Construct the name of the shard actor given the name of the member on + * which the shard resides and the name of the shard + * + * @param memberName + * @param shardName + * @return + */ private String getShardActorName(String memberName, String shardName){ return memberName + "-shard-" + shardName + "-" + this.type; } - // Create the shards that are local to this member + /** + * Create shards that are local to the member on which the ShardManager + * runs + * + */ private void createLocalShards() { String memberName = this.cluster.getCurrentMemberName(); List memberShardNames = @@ -214,6 +236,12 @@ public class ShardManager extends AbstractUntypedActor { } + /** + * Given the name of the shard find the addresses of all it's peers + * + * @param shardName + * @return + */ private Map getPeerAddresses(String shardName){ Map peerAddresses = new HashMap<>(); diff --git a/opendaylight/md-sal/sal-distributed-datastore/src/main/java/org/opendaylight/controller/cluster/datastore/ShardReadTransaction.java b/opendaylight/md-sal/sal-distributed-datastore/src/main/java/org/opendaylight/controller/cluster/datastore/ShardReadTransaction.java new file mode 100644 index 0000000000..f78935b5e7 --- /dev/null +++ b/opendaylight/md-sal/sal-distributed-datastore/src/main/java/org/opendaylight/controller/cluster/datastore/ShardReadTransaction.java @@ -0,0 +1,58 @@ +/* + * + * 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.cluster.datastore; + +import akka.actor.ActorRef; +import akka.actor.PoisonPill; +import akka.event.Logging; +import akka.event.LoggingAdapter; +import org.opendaylight.controller.cluster.datastore.messages.CloseTransaction; +import org.opendaylight.controller.cluster.datastore.messages.CloseTransactionReply; +import org.opendaylight.controller.cluster.datastore.messages.ReadData; +import org.opendaylight.controller.sal.core.spi.data.DOMStoreReadTransaction; +import org.opendaylight.controller.sal.core.spi.data.DOMStoreTransactionChain; +import org.opendaylight.yangtools.yang.model.api.SchemaContext; + +/** + * @author: syedbahm + * Date: 8/6/14 + */ +public class ShardReadTransaction extends ShardTransaction { + private final DOMStoreReadTransaction transaction; + private final LoggingAdapter log = + Logging.getLogger(getContext().system(), this); + + public ShardReadTransaction(DOMStoreReadTransaction transaction, ActorRef shardActor, SchemaContext schemaContext) { + super(shardActor, schemaContext); + this.transaction = transaction; + + } + + public ShardReadTransaction(DOMStoreTransactionChain transactionChain, DOMStoreReadTransaction transaction, ActorRef shardActor, SchemaContext schemaContext) { + super(transactionChain, shardActor, schemaContext); + this.transaction = transaction; + } + + @Override + public void handleReceive(Object message) throws Exception { + if (ReadData.SERIALIZABLE_CLASS.equals(message.getClass())) { + readData(transaction,ReadData.fromSerializable(message)); + } else { + super.handleReceive(message); + } + } + protected void closeTransaction(CloseTransaction message) { + transaction.close(); + getSender().tell(new CloseTransactionReply().toSerializable(), getSelf()); + getSelf().tell(PoisonPill.getInstance(), getSelf()); + } + +} diff --git a/opendaylight/md-sal/sal-distributed-datastore/src/main/java/org/opendaylight/controller/cluster/datastore/ShardReadWriteTransaction.java b/opendaylight/md-sal/sal-distributed-datastore/src/main/java/org/opendaylight/controller/cluster/datastore/ShardReadWriteTransaction.java new file mode 100644 index 0000000000..6733bcfb9f --- /dev/null +++ b/opendaylight/md-sal/sal-distributed-datastore/src/main/java/org/opendaylight/controller/cluster/datastore/ShardReadWriteTransaction.java @@ -0,0 +1,68 @@ +/* + * + * 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.cluster.datastore; + +import akka.actor.ActorRef; +import akka.actor.PoisonPill; +import akka.event.Logging; +import akka.event.LoggingAdapter; +import org.opendaylight.controller.cluster.datastore.messages.CloseTransaction; +import org.opendaylight.controller.cluster.datastore.messages.CloseTransactionReply; +import org.opendaylight.controller.cluster.datastore.messages.DeleteData; +import org.opendaylight.controller.cluster.datastore.messages.MergeData; +import org.opendaylight.controller.cluster.datastore.messages.ReadData; +import org.opendaylight.controller.cluster.datastore.messages.ReadyTransaction; +import org.opendaylight.controller.cluster.datastore.messages.WriteData; +import org.opendaylight.controller.sal.core.spi.data.DOMStoreReadWriteTransaction; +import org.opendaylight.controller.sal.core.spi.data.DOMStoreTransactionChain; +import org.opendaylight.yangtools.yang.model.api.SchemaContext; + +/** + * @author: syedbahm + * Date: 8/6/14 + */ +public class ShardReadWriteTransaction extends ShardTransaction { + private final DOMStoreReadWriteTransaction transaction; + private final LoggingAdapter log = + Logging.getLogger(getContext().system(), this); + public ShardReadWriteTransaction(DOMStoreTransactionChain transactionChain, DOMStoreReadWriteTransaction transaction, ActorRef shardActor, SchemaContext schemaContext) { + super(transactionChain, shardActor, schemaContext); + this.transaction = transaction; + } + + public ShardReadWriteTransaction(DOMStoreReadWriteTransaction transaction, ActorRef shardActor, SchemaContext schemaContext) { + super( shardActor, schemaContext); + this.transaction = transaction; + } + + @Override + public void handleReceive(Object message) throws Exception { + if (ReadData.SERIALIZABLE_CLASS.equals(message.getClass())) { + readData(transaction,ReadData.fromSerializable(message)); + }else if (WriteData.SERIALIZABLE_CLASS.equals(message.getClass())) { + writeData(transaction, WriteData.fromSerializable(message, schemaContext)); + } else if (MergeData.SERIALIZABLE_CLASS.equals(message.getClass())) { + mergeData(transaction, MergeData.fromSerializable(message, schemaContext)); + } else if (DeleteData.SERIALIZABLE_CLASS.equals(message.getClass())) { + deleteData(transaction,DeleteData.fromSerizalizable(message)); + } else if (ReadyTransaction.SERIALIZABLE_CLASS.equals(message.getClass())) { + readyTransaction(transaction,new ReadyTransaction()); + }else { + super.handleReceive(message); + } + } + + protected void closeTransaction(CloseTransaction message) { + transaction.close(); + getSender().tell(new CloseTransactionReply().toSerializable(), getSelf()); + getSelf().tell(PoisonPill.getInstance(), getSelf()); + } +} diff --git a/opendaylight/md-sal/sal-distributed-datastore/src/main/java/org/opendaylight/controller/cluster/datastore/ShardTransaction.java b/opendaylight/md-sal/sal-distributed-datastore/src/main/java/org/opendaylight/controller/cluster/datastore/ShardTransaction.java index 737f57bf5d..3a916bda2c 100644 --- a/opendaylight/md-sal/sal-distributed-datastore/src/main/java/org/opendaylight/controller/cluster/datastore/ShardTransaction.java +++ b/opendaylight/md-sal/sal-distributed-datastore/src/main/java/org/opendaylight/controller/cluster/datastore/ShardTransaction.java @@ -9,7 +9,6 @@ package org.opendaylight.controller.cluster.datastore; import akka.actor.ActorRef; -import akka.actor.PoisonPill; import akka.actor.Props; import akka.event.Logging; import akka.event.LoggingAdapter; @@ -17,7 +16,6 @@ import akka.japi.Creator; import com.google.common.base.Optional; import com.google.common.util.concurrent.ListenableFuture; import org.opendaylight.controller.cluster.datastore.messages.CloseTransaction; -import org.opendaylight.controller.cluster.datastore.messages.CloseTransactionReply; import org.opendaylight.controller.cluster.datastore.messages.DeleteData; import org.opendaylight.controller.cluster.datastore.messages.DeleteDataReply; import org.opendaylight.controller.cluster.datastore.messages.MergeData; @@ -34,9 +32,11 @@ import org.opendaylight.controller.cluster.datastore.modification.ImmutableCompo import org.opendaylight.controller.cluster.datastore.modification.MergeModification; import org.opendaylight.controller.cluster.datastore.modification.MutableCompositeModification; import org.opendaylight.controller.cluster.datastore.modification.WriteModification; +import org.opendaylight.controller.sal.core.spi.data.DOMStoreReadTransaction; import org.opendaylight.controller.sal.core.spi.data.DOMStoreReadWriteTransaction; import org.opendaylight.controller.sal.core.spi.data.DOMStoreThreePhaseCommitCohort; import org.opendaylight.controller.sal.core.spi.data.DOMStoreTransactionChain; +import org.opendaylight.controller.sal.core.spi.data.DOMStoreWriteTransaction; import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier; import org.opendaylight.yangtools.yang.data.api.schema.NormalizedNode; import org.opendaylight.yangtools.yang.model.api.SchemaContext; @@ -65,170 +65,200 @@ import java.util.concurrent.ExecutionException; *
      • {@link org.opendaylight.controller.cluster.datastore.messages.CloseTransaction} *

        */ -public class ShardTransaction extends AbstractUntypedActor { - - private final ActorRef shardActor; - private final SchemaContext schemaContext; - - // FIXME : see below - // If transactionChain is not null then this transaction is part of a - // transactionChain. Not really clear as to what that buys us - private final DOMStoreTransactionChain transactionChain; - - private final DOMStoreReadWriteTransaction transaction; - - private final MutableCompositeModification modification = - new MutableCompositeModification(); - - private final LoggingAdapter log = - Logging.getLogger(getContext().system(), this); - - public ShardTransaction(DOMStoreReadWriteTransaction transaction, - ActorRef shardActor, SchemaContext schemaContext) { - this(null, transaction, shardActor, schemaContext); - } - - public ShardTransaction(DOMStoreTransactionChain transactionChain, DOMStoreReadWriteTransaction transaction, - ActorRef shardActor, SchemaContext schemaContext) { - this.transactionChain = transactionChain; - this.transaction = transaction; - this.shardActor = shardActor; - this.schemaContext = schemaContext; - } - - - - public static Props props(final DOMStoreReadWriteTransaction transaction, - final ActorRef shardActor, final SchemaContext schemaContext) { - return Props.create(new Creator() { - - @Override - public ShardTransaction create() throws Exception { - return new ShardTransaction(transaction, shardActor, schemaContext); - } - }); - } - - public static Props props(final DOMStoreTransactionChain transactionChain, final DOMStoreReadWriteTransaction transaction, - final ActorRef shardActor, final SchemaContext schemaContext) { - return Props.create(new Creator() { - - @Override - public ShardTransaction create() throws Exception { - return new ShardTransaction(transactionChain, transaction, shardActor, schemaContext); - } - }); +public abstract class ShardTransaction extends AbstractUntypedActor { + + private final ActorRef shardActor; + protected final SchemaContext schemaContext; + + // FIXME : see below + // If transactionChain is not null then this transaction is part of a + // transactionChain. Not really clear as to what that buys us + private final DOMStoreTransactionChain transactionChain; + + + private final MutableCompositeModification modification = + new MutableCompositeModification(); + + private final LoggingAdapter log = + Logging.getLogger(getContext().system(), this); + + protected ShardTransaction( + ActorRef shardActor, SchemaContext schemaContext) { + this(null, shardActor, schemaContext); + } + + protected ShardTransaction(DOMStoreTransactionChain transactionChain, + ActorRef shardActor, SchemaContext schemaContext) { + this.transactionChain = transactionChain; + //this.transaction = transaction; + this.shardActor = shardActor; + this.schemaContext = schemaContext; + } + + + + public static Props props(final DOMStoreReadTransaction transaction, + final ActorRef shardActor, final SchemaContext schemaContext) { + return Props.create(new Creator() { + + @Override + public ShardTransaction create() throws Exception { + return new ShardReadTransaction(transaction, shardActor, schemaContext); + } + }); + } + + public static Props props(final DOMStoreTransactionChain transactionChain, final DOMStoreReadTransaction transaction, + final ActorRef shardActor, final SchemaContext schemaContext) { + return Props.create(new Creator() { + + @Override + public ShardTransaction create() throws Exception { + return new ShardReadTransaction(transactionChain, transaction, shardActor, schemaContext); + } + }); + } + + public static Props props(final DOMStoreReadWriteTransaction transaction, + final ActorRef shardActor, final SchemaContext schemaContext) { + return Props.create(new Creator() { + + @Override + public ShardTransaction create() throws Exception { + return new ShardReadWriteTransaction(transaction, shardActor, schemaContext); + } + }); + } + + public static Props props(final DOMStoreTransactionChain transactionChain, final DOMStoreReadWriteTransaction transaction, + final ActorRef shardActor, final SchemaContext schemaContext) { + return Props.create(new Creator() { + + @Override + public ShardTransaction create() throws Exception { + return new ShardReadWriteTransaction(transactionChain, transaction, shardActor, schemaContext); + } + }); + } + + + public static Props props(final DOMStoreWriteTransaction transaction, + final ActorRef shardActor, final SchemaContext schemaContext) { + return Props.create(new Creator() { + + @Override + public ShardTransaction create() throws Exception { + return new ShardWriteTransaction(transaction, shardActor, schemaContext); + } + }); + } + + public static Props props(final DOMStoreTransactionChain transactionChain, final DOMStoreWriteTransaction transaction, + final ActorRef shardActor, final SchemaContext schemaContext) { + return Props.create(new Creator() { + + @Override + public ShardTransaction create() throws Exception { + return new ShardWriteTransaction(transactionChain, transaction, shardActor, schemaContext); + } + }); + } + + + @Override + public void handleReceive(Object message) throws Exception { + if (message.getClass().equals(CloseTransaction.SERIALIZABLE_CLASS)) { + closeTransaction(new CloseTransaction()); + } else if (message instanceof GetCompositedModification) { + // This is here for testing only + getSender().tell(new GetCompositeModificationReply( + new ImmutableCompositeModification(modification)), getSelf()); + }else{ + throw new Exception ("ShardTransaction:handleRecieve received an unknown message"+message); } - - - @Override - public void handleReceive(Object message) throws Exception { - if (ReadData.SERIALIZABLE_CLASS.equals(message.getClass())) { - readData(ReadData.fromSerializable(message)); - } else if (WriteData.SERIALIZABLE_CLASS.equals(message.getClass())) { - writeData(WriteData.fromSerializable(message, schemaContext)); - } else if (MergeData.SERIALIZABLE_CLASS.equals(message.getClass())) { - mergeData(MergeData.fromSerializable(message, schemaContext)); - } else if (DeleteData.SERIALIZABLE_CLASS.equals(message.getClass())) { - deleteData(DeleteData.fromSerizalizable(message)); - } else if (ReadyTransaction.SERIALIZABLE_CLASS.equals(message.getClass())) { - readyTransaction(new ReadyTransaction()); - } else if (message.getClass().equals(CloseTransaction.SERIALIZABLE_CLASS)) { - closeTransaction(new CloseTransaction()); - } else if (message instanceof GetCompositedModification) { - // This is here for testing only - getSender().tell(new GetCompositeModificationReply( - new ImmutableCompositeModification(modification)), getSelf()); - }else{ - throw new Exception ("Shard:handleRecieve received an unknown message"+message); + } + + abstract protected void closeTransaction(CloseTransaction message); + + protected void readData(DOMStoreReadTransaction transaction,ReadData message) { + final ActorRef sender = getSender(); + final ActorRef self = getSelf(); + final YangInstanceIdentifier path = message.getPath(); + final ListenableFuture>> future = + transaction.read(path); + + future.addListener(new Runnable() { + @Override + public void run() { + try { + Optional> optional = future.get(); + if (optional.isPresent()) { + sender.tell(new ReadDataReply(schemaContext,optional.get()).toSerializable(), self); + } else { + sender.tell(new ReadDataReply(schemaContext,null).toSerializable(), self); + } + } catch (InterruptedException | ExecutionException e) { + log.error(e, + "An exception happened when reading data from path : " + + path.toString()); } - } - private void readData(ReadData message) { - final ActorRef sender = getSender(); - final ActorRef self = getSelf(); - final YangInstanceIdentifier path = message.getPath(); - final ListenableFuture>> future = - transaction.read(path); - - future.addListener(new Runnable() { - @Override - public void run() { - try { - Optional> optional = future.get(); - if (optional.isPresent()) { - sender.tell(new ReadDataReply(schemaContext,optional.get()).toSerializable(), self); - } else { - sender.tell(new ReadDataReply(schemaContext,null).toSerializable(), self); - } - } catch (InterruptedException | ExecutionException e) { - log.error(e, - "An exception happened when reading data from path : " - + path.toString()); - } - - } - }, getContext().dispatcher()); - } + } + }, getContext().dispatcher()); + } - private void writeData(WriteData message) { - modification.addModification( - new WriteModification(message.getPath(), message.getData(),schemaContext)); - LOG.debug("writeData at path : " + message.getPath().toString()); - transaction.write(message.getPath(), message.getData()); - getSender().tell(new WriteDataReply().toSerializable(), getSelf()); - } + protected void writeData(DOMStoreWriteTransaction transaction, WriteData message) { + modification.addModification( + new WriteModification(message.getPath(), message.getData(),schemaContext)); + LOG.debug("writeData at path : " + message.getPath().toString()); + transaction.write(message.getPath(), message.getData()); + getSender().tell(new WriteDataReply().toSerializable(), getSelf()); + } - private void mergeData(MergeData message) { - modification.addModification( - new MergeModification(message.getPath(), message.getData(), schemaContext)); - LOG.debug("mergeData at path : " + message.getPath().toString()); - transaction.merge(message.getPath(), message.getData()); - getSender().tell(new MergeDataReply().toSerializable(), getSelf()); - } + protected void mergeData(DOMStoreWriteTransaction transaction, MergeData message) { + modification.addModification( + new MergeModification(message.getPath(), message.getData(), schemaContext)); + LOG.debug("mergeData at path : " + message.getPath().toString()); + transaction.merge(message.getPath(), message.getData()); + getSender().tell(new MergeDataReply().toSerializable(), getSelf()); + } - private void deleteData(DeleteData message) { - modification.addModification(new DeleteModification(message.getPath())); - transaction.delete(message.getPath()); - getSender().tell(new DeleteDataReply().toSerializable(), getSelf()); - } + protected void deleteData(DOMStoreWriteTransaction transaction, DeleteData message) { + modification.addModification(new DeleteModification(message.getPath())); + transaction.delete(message.getPath()); + getSender().tell(new DeleteDataReply().toSerializable(), getSelf()); + } - private void readyTransaction(ReadyTransaction message) { - DOMStoreThreePhaseCommitCohort cohort = transaction.ready(); - ActorRef cohortActor = getContext().actorOf( - ThreePhaseCommitCohort.props(cohort, shardActor, modification), "cohort"); - getSender() - .tell(new ReadyTransactionReply(cohortActor.path()).toSerializable(), getSelf()); + protected void readyTransaction(DOMStoreWriteTransaction transaction, ReadyTransaction message) { + DOMStoreThreePhaseCommitCohort cohort = transaction.ready(); + ActorRef cohortActor = getContext().actorOf( + ThreePhaseCommitCohort.props(cohort, shardActor, modification), "cohort"); + getSender() + .tell(new ReadyTransactionReply(cohortActor.path()).toSerializable(), getSelf()); - } - - private void closeTransaction(CloseTransaction message) { - transaction.close(); - getSender().tell(new CloseTransactionReply().toSerializable(), getSelf()); - getSelf().tell(PoisonPill.getInstance(), getSelf()); - } + } - // These classes are in here for test purposes only + // These classes are in here for test purposes only - static class GetCompositedModification { + static class GetCompositedModification { - } + } - static class GetCompositeModificationReply { - private final CompositeModification modification; + static class GetCompositeModificationReply { + private final CompositeModification modification; - GetCompositeModificationReply(CompositeModification modification) { - this.modification = modification; - } + GetCompositeModificationReply(CompositeModification modification) { + this.modification = modification; + } - public CompositeModification getModification() { - return modification; - } + public CompositeModification getModification() { + return modification; } + } } diff --git a/opendaylight/md-sal/sal-distributed-datastore/src/main/java/org/opendaylight/controller/cluster/datastore/ShardTransactionChain.java b/opendaylight/md-sal/sal-distributed-datastore/src/main/java/org/opendaylight/controller/cluster/datastore/ShardTransactionChain.java index 50042411b1..ce63f1107d 100644 --- a/opendaylight/md-sal/sal-distributed-datastore/src/main/java/org/opendaylight/controller/cluster/datastore/ShardTransactionChain.java +++ b/opendaylight/md-sal/sal-distributed-datastore/src/main/java/org/opendaylight/controller/cluster/datastore/ShardTransactionChain.java @@ -15,7 +15,6 @@ import org.opendaylight.controller.cluster.datastore.messages.CloseTransactionCh import org.opendaylight.controller.cluster.datastore.messages.CloseTransactionChainReply; import org.opendaylight.controller.cluster.datastore.messages.CreateTransaction; import org.opendaylight.controller.cluster.datastore.messages.CreateTransactionReply; -import org.opendaylight.controller.sal.core.spi.data.DOMStoreReadWriteTransaction; import org.opendaylight.controller.sal.core.spi.data.DOMStoreTransactionChain; import org.opendaylight.yangtools.yang.model.api.SchemaContext; @@ -45,11 +44,27 @@ public class ShardTransactionChain extends AbstractUntypedActor { } } + private ActorRef createTypedTransactionActor(CreateTransaction createTransaction,String transactionId){ + if(createTransaction.getTransactionType()== TransactionProxy.TransactionType.READ_ONLY.ordinal()){ + return getContext().actorOf( + ShardTransaction.props( chain.newReadOnlyTransaction(), getSelf(), schemaContext), transactionId); + + }else if (createTransaction.getTransactionType()== TransactionProxy.TransactionType.READ_WRITE.ordinal()){ + return getContext().actorOf( + ShardTransaction.props( chain.newReadWriteTransaction(), getSelf(), schemaContext), transactionId); + + + }else if (createTransaction.getTransactionType()== TransactionProxy.TransactionType.WRITE_ONLY.ordinal()){ + return getContext().actorOf( + ShardTransaction.props( chain.newWriteOnlyTransaction(), getSelf(), schemaContext), transactionId); + }else{ + throw new IllegalArgumentException ("CreateTransaction message has unidentified transaction type="+createTransaction.getTransactionType()) ; + } + } + private void createTransaction(CreateTransaction createTransaction) { - DOMStoreReadWriteTransaction transaction = - chain.newReadWriteTransaction(); - ActorRef transactionActor = getContext().actorOf(ShardTransaction - .props(chain, transaction, getContext().parent(), schemaContext), "shard-" + createTransaction.getTransactionId()); + + ActorRef transactionActor = createTypedTransactionActor(createTransaction, "shard-" + createTransaction.getTransactionId()); getSender() .tell(new CreateTransactionReply(transactionActor.path().toString(),createTransaction.getTransactionId()).toSerializable(), getSelf()); diff --git a/opendaylight/md-sal/sal-distributed-datastore/src/main/java/org/opendaylight/controller/cluster/datastore/ShardWriteTransaction.java b/opendaylight/md-sal/sal-distributed-datastore/src/main/java/org/opendaylight/controller/cluster/datastore/ShardWriteTransaction.java new file mode 100644 index 0000000000..2a5429ba81 --- /dev/null +++ b/opendaylight/md-sal/sal-distributed-datastore/src/main/java/org/opendaylight/controller/cluster/datastore/ShardWriteTransaction.java @@ -0,0 +1,66 @@ +/* + * + * 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.cluster.datastore; + +import akka.actor.ActorRef; +import akka.actor.PoisonPill; +import akka.event.Logging; +import akka.event.LoggingAdapter; +import org.opendaylight.controller.cluster.datastore.messages.CloseTransaction; +import org.opendaylight.controller.cluster.datastore.messages.CloseTransactionReply; +import org.opendaylight.controller.cluster.datastore.messages.DeleteData; +import org.opendaylight.controller.cluster.datastore.messages.MergeData; +import org.opendaylight.controller.cluster.datastore.messages.ReadyTransaction; +import org.opendaylight.controller.cluster.datastore.messages.WriteData; +import org.opendaylight.controller.sal.core.spi.data.DOMStoreTransactionChain; +import org.opendaylight.controller.sal.core.spi.data.DOMStoreWriteTransaction; +import org.opendaylight.yangtools.yang.model.api.SchemaContext; + +/** + * @author: syedbahm + * Date: 8/6/14 + */ +public class ShardWriteTransaction extends ShardTransaction { + private final DOMStoreWriteTransaction transaction; + private final LoggingAdapter log = + Logging.getLogger(getContext().system(), this); + public ShardWriteTransaction(DOMStoreWriteTransaction transaction, ActorRef shardActor, SchemaContext schemaContext) { + super( shardActor, schemaContext); + this.transaction = transaction; + + } + + public ShardWriteTransaction(DOMStoreTransactionChain transactionChain, DOMStoreWriteTransaction transaction, ActorRef shardActor, SchemaContext schemaContext) { + super(transactionChain, shardActor, schemaContext); + this.transaction = transaction; + } + + @Override + public void handleReceive(Object message) throws Exception { + if (WriteData.SERIALIZABLE_CLASS.equals(message.getClass())) { + writeData(transaction, WriteData.fromSerializable(message, schemaContext)); + } else if (MergeData.SERIALIZABLE_CLASS.equals(message.getClass())) { + mergeData(transaction, MergeData.fromSerializable(message, schemaContext)); + } else if (DeleteData.SERIALIZABLE_CLASS.equals(message.getClass())) { + deleteData(transaction,DeleteData.fromSerizalizable(message)); + } else if (ReadyTransaction.SERIALIZABLE_CLASS.equals(message.getClass())) { + readyTransaction(transaction,new ReadyTransaction()); + }else { + super.handleReceive(message); + } + } + + protected void closeTransaction(CloseTransaction message) { + transaction.close(); + getSender().tell(new CloseTransactionReply().toSerializable(), getSelf()); + getSelf().tell(PoisonPill.getInstance(), getSelf()); + } +} diff --git a/opendaylight/md-sal/sal-distributed-datastore/src/main/java/org/opendaylight/controller/cluster/datastore/ThreePhaseCommitCohortProxy.java b/opendaylight/md-sal/sal-distributed-datastore/src/main/java/org/opendaylight/controller/cluster/datastore/ThreePhaseCommitCohortProxy.java index b56dc9432f..915b13dd8b 100644 --- a/opendaylight/md-sal/sal-distributed-datastore/src/main/java/org/opendaylight/controller/cluster/datastore/ThreePhaseCommitCohortProxy.java +++ b/opendaylight/md-sal/sal-distributed-datastore/src/main/java/org/opendaylight/controller/cluster/datastore/ThreePhaseCommitCohortProxy.java @@ -10,8 +10,10 @@ package org.opendaylight.controller.cluster.datastore; import akka.actor.ActorPath; import akka.actor.ActorSelection; + import com.google.common.util.concurrent.ListenableFuture; -import com.google.common.util.concurrent.ListenableFutureTask; +import com.google.common.util.concurrent.ListeningExecutorService; + import org.opendaylight.controller.cluster.datastore.exceptions.TimeoutException; import org.opendaylight.controller.cluster.datastore.messages.AbortTransaction; import org.opendaylight.controller.cluster.datastore.messages.AbortTransactionReply; @@ -29,7 +31,6 @@ import org.slf4j.LoggerFactory; import java.util.Collections; import java.util.List; import java.util.concurrent.Callable; -import java.util.concurrent.ExecutorService; /** * ThreePhaseCommitCohortProxy represents a set of remote cohort proxies @@ -42,14 +43,14 @@ public class ThreePhaseCommitCohortProxy implements private final ActorContext actorContext; private final List cohortPaths; - private final ExecutorService executor; + private final ListeningExecutorService executor; private final String transactionId; public ThreePhaseCommitCohortProxy(ActorContext actorContext, List cohortPaths, String transactionId, - ExecutorService executor) { + ListeningExecutorService executor) { this.actorContext = actorContext; this.cohortPaths = cohortPaths; @@ -58,42 +59,37 @@ public class ThreePhaseCommitCohortProxy implements } @Override public ListenableFuture canCommit() { - Callable call = new Callable() { - - @Override public Boolean call() throws Exception { - for(ActorPath actorPath : cohortPaths){ - ActorSelection cohort = actorContext.actorSelection(actorPath); - - try { - Object response = - actorContext.executeRemoteOperation(cohort, - new CanCommitTransaction().toSerializable(), - ActorContext.ASK_DURATION); - - if (response.getClass().equals(CanCommitTransactionReply.SERIALIZABLE_CLASS)) { - CanCommitTransactionReply reply = - CanCommitTransactionReply.fromSerializable(response); - if (!reply.getCanCommit()) { - return false; + Callable call = new Callable() { + + @Override + public Boolean call() throws Exception { + for(ActorPath actorPath : cohortPaths){ + ActorSelection cohort = actorContext.actorSelection(actorPath); + + try { + Object response = + actorContext.executeRemoteOperation(cohort, + new CanCommitTransaction().toSerializable(), + ActorContext.ASK_DURATION); + + if (response.getClass().equals(CanCommitTransactionReply.SERIALIZABLE_CLASS)) { + CanCommitTransactionReply reply = + CanCommitTransactionReply.fromSerializable(response); + if (!reply.getCanCommit()) { + return false; + } } + } catch(RuntimeException e){ + LOG.error("Unexpected Exception", e); + return false; } - } catch(RuntimeException e){ - LOG.error("Unexpected Exception", e); - return false; } - - } - return true; + return true; } }; - ListenableFutureTask - future = ListenableFutureTask.create(call); - - executor.submit(future); - - return future; + return executor.submit(call); } @Override public ListenableFuture preCommit() { @@ -138,13 +134,7 @@ public class ThreePhaseCommitCohortProxy implements } }; - ListenableFutureTask - future = ListenableFutureTask.create(call); - - executor.submit(future); - - return future; - + return executor.submit(call); } public List getCohortPaths() { diff --git a/opendaylight/md-sal/sal-distributed-datastore/src/main/java/org/opendaylight/controller/cluster/datastore/TransactionChainProxy.java b/opendaylight/md-sal/sal-distributed-datastore/src/main/java/org/opendaylight/controller/cluster/datastore/TransactionChainProxy.java index 2e8538d077..5e9defa5b5 100644 --- a/opendaylight/md-sal/sal-distributed-datastore/src/main/java/org/opendaylight/controller/cluster/datastore/TransactionChainProxy.java +++ b/opendaylight/md-sal/sal-distributed-datastore/src/main/java/org/opendaylight/controller/cluster/datastore/TransactionChainProxy.java @@ -15,17 +15,18 @@ import org.opendaylight.controller.sal.core.spi.data.DOMStoreTransactionChain; import org.opendaylight.controller.sal.core.spi.data.DOMStoreWriteTransaction; import org.opendaylight.yangtools.yang.model.api.SchemaContext; -import java.util.concurrent.ExecutorService; +import com.google.common.util.concurrent.ListeningExecutorService; /** * TransactionChainProxy acts as a proxy for a DOMStoreTransactionChain created on a remote shard */ public class TransactionChainProxy implements DOMStoreTransactionChain{ private final ActorContext actorContext; - private final ExecutorService transactionExecutor; + private final ListeningExecutorService transactionExecutor; private final SchemaContext schemaContext; - public TransactionChainProxy(ActorContext actorContext, ExecutorService transactionExecutor, SchemaContext schemaContext) { + public TransactionChainProxy(ActorContext actorContext, ListeningExecutorService transactionExecutor, + SchemaContext schemaContext) { this.actorContext = actorContext; this.transactionExecutor = transactionExecutor; this.schemaContext = schemaContext; diff --git a/opendaylight/md-sal/sal-distributed-datastore/src/main/java/org/opendaylight/controller/cluster/datastore/TransactionProxy.java b/opendaylight/md-sal/sal-distributed-datastore/src/main/java/org/opendaylight/controller/cluster/datastore/TransactionProxy.java index c85d32012f..fa98905a66 100644 --- a/opendaylight/md-sal/sal-distributed-datastore/src/main/java/org/opendaylight/controller/cluster/datastore/TransactionProxy.java +++ b/opendaylight/md-sal/sal-distributed-datastore/src/main/java/org/opendaylight/controller/cluster/datastore/TransactionProxy.java @@ -13,9 +13,10 @@ import akka.actor.ActorRef; import akka.actor.ActorSelection; import akka.actor.Props; import com.google.common.base.Optional; +import com.google.common.util.concurrent.CheckedFuture; import com.google.common.util.concurrent.Futures; -import com.google.common.util.concurrent.ListenableFuture; -import com.google.common.util.concurrent.ListenableFutureTask; +import com.google.common.util.concurrent.ListeningExecutorService; +import org.opendaylight.controller.cluster.datastore.exceptions.PrimaryNotFoundException; import org.opendaylight.controller.cluster.datastore.exceptions.TimeoutException; import org.opendaylight.controller.cluster.datastore.messages.CloseTransaction; import org.opendaylight.controller.cluster.datastore.messages.CreateTransaction; @@ -29,8 +30,10 @@ import org.opendaylight.controller.cluster.datastore.messages.ReadyTransactionRe import org.opendaylight.controller.cluster.datastore.messages.WriteData; import org.opendaylight.controller.cluster.datastore.shardstrategy.ShardStrategyFactory; import org.opendaylight.controller.cluster.datastore.utils.ActorContext; +import org.opendaylight.controller.md.sal.common.api.data.ReadFailedException; import org.opendaylight.controller.sal.core.spi.data.DOMStoreReadWriteTransaction; import org.opendaylight.controller.sal.core.spi.data.DOMStoreThreePhaseCommitCohort; +import org.opendaylight.yangtools.util.concurrent.MappingCheckedFuture; import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier; import org.opendaylight.yangtools.yang.data.api.schema.NormalizedNode; import org.opendaylight.yangtools.yang.model.api.SchemaContext; @@ -42,7 +45,6 @@ import java.util.HashMap; import java.util.List; import java.util.Map; import java.util.concurrent.Callable; -import java.util.concurrent.ExecutorService; import java.util.concurrent.atomic.AtomicLong; /** @@ -74,13 +76,13 @@ public class TransactionProxy implements DOMStoreReadWriteTransaction { private final ActorContext actorContext; private final Map remoteTransactionPaths = new HashMap<>(); private final String identifier; - private final ExecutorService executor; + private final ListeningExecutorService executor; private final SchemaContext schemaContext; public TransactionProxy( ActorContext actorContext, TransactionType transactionType, - ExecutorService executor, + ListeningExecutorService executor, SchemaContext schemaContext ) { @@ -94,7 +96,8 @@ public class TransactionProxy implements DOMStoreReadWriteTransaction { } @Override - public ListenableFuture>> read(final YangInstanceIdentifier path) { + public CheckedFuture>, ReadFailedException> read( + final YangInstanceIdentifier path) { createTransactionIfMissing(actorContext, path); @@ -177,7 +180,7 @@ public class TransactionProxy implements DOMStoreReadWriteTransaction { try { Object response = actorContext.executeShardOperation(shardName, - new CreateTransaction(identifier).toSerializable(), + new CreateTransaction(identifier,this.transactionType.ordinal() ).toSerializable(), ActorContext.ASK_DURATION); if (response.getClass() .equals(CreateTransactionReply.SERIALIZABLE_CLASS)) { @@ -196,8 +199,10 @@ public class TransactionProxy implements DOMStoreReadWriteTransaction { remoteTransactionPaths.put(shardName, transactionContext); } - } catch(TimeoutException e){ - remoteTransactionPaths.put(shardName, new NoOpTransactionContext(shardName)); + } catch(TimeoutException | PrimaryNotFoundException e){ + LOG.error("Creating NoOpTransaction because of : {}", e.getMessage()); + remoteTransactionPaths.put(shardName, + new NoOpTransactionContext(shardName)); } } @@ -214,7 +219,8 @@ public class TransactionProxy implements DOMStoreReadWriteTransaction { void mergeData(YangInstanceIdentifier path, NormalizedNode data); - ListenableFuture>> readData(final YangInstanceIdentifier path); + CheckedFuture>, ReadFailedException> readData( + final YangInstanceIdentifier path); void writeData(YangInstanceIdentifier path, NormalizedNode data); } @@ -266,9 +272,10 @@ public class TransactionProxy implements DOMStoreReadWriteTransaction { getActor().tell(new MergeData(path, data, schemaContext).toSerializable(), null); } - @Override public ListenableFuture>> readData(final YangInstanceIdentifier path) { + @Override public CheckedFuture>, ReadFailedException> readData( + final YangInstanceIdentifier path) { - Callable>> call = new Callable() { + Callable>> call = new Callable>>() { @Override public Optional> call() throws Exception { Object response = actorContext @@ -279,20 +286,14 @@ public class TransactionProxy implements DOMStoreReadWriteTransaction { if(reply.getNormalizedNode() == null){ return Optional.absent(); } - //FIXME : A cast should not be required here ??? - return (Optional>) Optional.of(reply.getNormalizedNode()); + return Optional.>of(reply.getNormalizedNode()); } return Optional.absent(); } }; - ListenableFutureTask>> - future = ListenableFutureTask.create(call); - - executor.submit(future); - - return future; + return MappingCheckedFuture.create(executor.submit(call), ReadFailedException.MAPPER); } @Override public void writeData(YangInstanceIdentifier path, NormalizedNode data) { @@ -342,10 +343,10 @@ public class TransactionProxy implements DOMStoreReadWriteTransaction { } @Override - public ListenableFuture>> readData( + public CheckedFuture>, ReadFailedException> readData( YangInstanceIdentifier path) { LOG.error("readData called path = {}", path); - return Futures.immediateFuture( + return Futures.immediateCheckedFuture( Optional.>absent()); } diff --git a/opendaylight/md-sal/sal-distributed-datastore/src/main/java/org/opendaylight/controller/cluster/datastore/jmx/mbeans/shard/ShardStats.java b/opendaylight/md-sal/sal-distributed-datastore/src/main/java/org/opendaylight/controller/cluster/datastore/jmx/mbeans/shard/ShardStats.java index 2da6aae85f..4eb6a8cef9 100644 --- a/opendaylight/md-sal/sal-distributed-datastore/src/main/java/org/opendaylight/controller/cluster/datastore/jmx/mbeans/shard/ShardStats.java +++ b/opendaylight/md-sal/sal-distributed-datastore/src/main/java/org/opendaylight/controller/cluster/datastore/jmx/mbeans/shard/ShardStats.java @@ -9,6 +9,8 @@ public class ShardStats extends AbstractBaseMBean implements ShardStatsMBean { private Long committedTransactionsCount; private Long journalMessagesCount; final private String shardName; + private String leader; + private String raftState; ShardStats(String shardName){ this.shardName = shardName; @@ -33,6 +35,13 @@ public class ShardStats extends AbstractBaseMBean implements ShardStatsMBean { return journalMessagesCount; } + @Override public String getLeader() { + return leader; + } + + @Override public String getRaftState() { + return raftState; + } public Long incrementCommittedTransactionCount() { return committedTransactionsCount++; @@ -49,6 +58,13 @@ public class ShardStats extends AbstractBaseMBean implements ShardStatsMBean { } + public void setLeader(String leader){ + this.leader = leader; + } + + public void setRaftState(String raftState){ + this.raftState = raftState; + } @Override diff --git a/opendaylight/md-sal/sal-distributed-datastore/src/main/java/org/opendaylight/controller/cluster/datastore/jmx/mbeans/shard/ShardStatsMBean.java b/opendaylight/md-sal/sal-distributed-datastore/src/main/java/org/opendaylight/controller/cluster/datastore/jmx/mbeans/shard/ShardStatsMBean.java index c107e49e85..9ebcc7fa5a 100644 --- a/opendaylight/md-sal/sal-distributed-datastore/src/main/java/org/opendaylight/controller/cluster/datastore/jmx/mbeans/shard/ShardStatsMBean.java +++ b/opendaylight/md-sal/sal-distributed-datastore/src/main/java/org/opendaylight/controller/cluster/datastore/jmx/mbeans/shard/ShardStatsMBean.java @@ -7,5 +7,6 @@ public interface ShardStatsMBean { String getShardName(); Long getCommittedTransactionsCount(); Long getJournalMessagesCount(); - + String getLeader(); + String getRaftState(); } diff --git a/opendaylight/md-sal/sal-distributed-datastore/src/main/java/org/opendaylight/controller/cluster/datastore/messages/CreateTransaction.java b/opendaylight/md-sal/sal-distributed-datastore/src/main/java/org/opendaylight/controller/cluster/datastore/messages/CreateTransaction.java index 795131fdbf..b27ad86be9 100644 --- a/opendaylight/md-sal/sal-distributed-datastore/src/main/java/org/opendaylight/controller/cluster/datastore/messages/CreateTransaction.java +++ b/opendaylight/md-sal/sal-distributed-datastore/src/main/java/org/opendaylight/controller/cluster/datastore/messages/CreateTransaction.java @@ -15,23 +15,28 @@ import org.opendaylight.controller.protobuff.messages.transaction.ShardTransacti public class CreateTransaction implements SerializableMessage { public static Class SERIALIZABLE_CLASS = ShardTransactionMessages.CreateTransaction.class; private final String transactionId; + private final int transactionType; - public CreateTransaction(String transactionId){ + public CreateTransaction(String transactionId, int transactionType){ this.transactionId = transactionId; + this.transactionType = transactionType; } public String getTransactionId() { return transactionId; } + public int getTransactionType() { return transactionType;} + @Override public Object toSerializable() { - return ShardTransactionMessages.CreateTransaction.newBuilder().setTransactionId(transactionId).build(); + return ShardTransactionMessages.CreateTransaction.newBuilder().setTransactionId(transactionId).setTransactionType(transactionType).build(); } public static CreateTransaction fromSerializable(Object message){ - return new CreateTransaction(((ShardTransactionMessages.CreateTransaction)message).getTransactionId()); + ShardTransactionMessages.CreateTransaction createTransaction = (ShardTransactionMessages.CreateTransaction)message; + return new CreateTransaction(createTransaction.getTransactionId(),createTransaction.getTransactionType() ); } } diff --git a/opendaylight/md-sal/sal-distributed-datastore/src/main/java/org/opendaylight/controller/cluster/datastore/messages/EnableNotification.java b/opendaylight/md-sal/sal-distributed-datastore/src/main/java/org/opendaylight/controller/cluster/datastore/messages/EnableNotification.java new file mode 100644 index 0000000000..67dab7e663 --- /dev/null +++ b/opendaylight/md-sal/sal-distributed-datastore/src/main/java/org/opendaylight/controller/cluster/datastore/messages/EnableNotification.java @@ -0,0 +1,21 @@ +/* + * 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.cluster.datastore.messages; + +public class EnableNotification { + private final boolean enabled; + + public EnableNotification(boolean enabled) { + this.enabled = enabled; + } + + public boolean isEnabled() { + return enabled; + } +} diff --git a/opendaylight/md-sal/sal-distributed-datastore/src/main/java/org/opendaylight/controller/cluster/datastore/messages/FindLocalShard.java b/opendaylight/md-sal/sal-distributed-datastore/src/main/java/org/opendaylight/controller/cluster/datastore/messages/FindLocalShard.java new file mode 100644 index 0000000000..c415db6efe --- /dev/null +++ b/opendaylight/md-sal/sal-distributed-datastore/src/main/java/org/opendaylight/controller/cluster/datastore/messages/FindLocalShard.java @@ -0,0 +1,25 @@ +/* + * 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.cluster.datastore.messages; + +/** + * FindLocalShard is a message that should be sent to the {@link org.opendaylight.controller.cluster.datastore.ShardManager} + * when we need to find a reference to a LocalShard + */ +public class FindLocalShard { + private final String shardName; + + public FindLocalShard(String shardName) { + this.shardName = shardName; + } + + public String getShardName() { + return shardName; + } +} diff --git a/opendaylight/md-sal/sal-distributed-datastore/src/main/java/org/opendaylight/controller/cluster/datastore/messages/LocalShardFound.java b/opendaylight/md-sal/sal-distributed-datastore/src/main/java/org/opendaylight/controller/cluster/datastore/messages/LocalShardFound.java new file mode 100644 index 0000000000..feea38f3e3 --- /dev/null +++ b/opendaylight/md-sal/sal-distributed-datastore/src/main/java/org/opendaylight/controller/cluster/datastore/messages/LocalShardFound.java @@ -0,0 +1,27 @@ +/* + * 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.cluster.datastore.messages; + +import akka.actor.ActorRef; + +/** + * LocalShardFound is a message that is sent by the {@link org.opendaylight.controller.cluster.datastore.ShardManager} + * when it finds a shard with the specified name in it's local shard registry + */ +public class LocalShardFound { + private final ActorRef path; + + public LocalShardFound(ActorRef path) { + this.path = path; + } + + public ActorRef getPath() { + return path; + } +} diff --git a/opendaylight/md-sal/sal-distributed-datastore/src/main/java/org/opendaylight/controller/cluster/datastore/messages/LocalShardNotFound.java b/opendaylight/md-sal/sal-distributed-datastore/src/main/java/org/opendaylight/controller/cluster/datastore/messages/LocalShardNotFound.java new file mode 100644 index 0000000000..f6c6634e1a --- /dev/null +++ b/opendaylight/md-sal/sal-distributed-datastore/src/main/java/org/opendaylight/controller/cluster/datastore/messages/LocalShardNotFound.java @@ -0,0 +1,29 @@ +/* + * 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.cluster.datastore.messages; + +/** + * LocalShardNotFound is a message that is sent by the {@link org.opendaylight.controller.cluster.datastore.ShardManager} + * when it cannot locate a shard in it's local registry with the shardName specified + */ +public class LocalShardNotFound { + private final String shardName; + + /** + * + * @param shardName the name of the shard that could not be found + */ + public LocalShardNotFound(String shardName) { + this.shardName = shardName; + } + + public String getShardName() { + return shardName; + } +} diff --git a/opendaylight/md-sal/sal-distributed-datastore/src/main/java/org/opendaylight/controller/cluster/datastore/shardstrategy/ModuleShardStrategy.java b/opendaylight/md-sal/sal-distributed-datastore/src/main/java/org/opendaylight/controller/cluster/datastore/shardstrategy/ModuleShardStrategy.java index 6f4b65a6f3..fc7ebd94dd 100644 --- a/opendaylight/md-sal/sal-distributed-datastore/src/main/java/org/opendaylight/controller/cluster/datastore/shardstrategy/ModuleShardStrategy.java +++ b/opendaylight/md-sal/sal-distributed-datastore/src/main/java/org/opendaylight/controller/cluster/datastore/shardstrategy/ModuleShardStrategy.java @@ -11,6 +11,8 @@ package org.opendaylight.controller.cluster.datastore.shardstrategy; import org.opendaylight.controller.cluster.datastore.Configuration; import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier; +import java.util.List; + public class ModuleShardStrategy implements ShardStrategy { public static final String NAME = "module"; @@ -25,6 +27,11 @@ public class ModuleShardStrategy implements ShardStrategy { } @Override public String findShard(YangInstanceIdentifier path) { - return configuration.getShardNamesFromModuleName(moduleName).get(0); + List shardNames = + configuration.getShardNamesFromModuleName(moduleName); + if(shardNames.size() == 0){ + return DefaultShardStrategy.DEFAULT_SHARD; + } + return shardNames.get(0); } } diff --git a/opendaylight/md-sal/sal-distributed-datastore/src/main/java/org/opendaylight/controller/cluster/datastore/shardstrategy/ShardStrategy.java b/opendaylight/md-sal/sal-distributed-datastore/src/main/java/org/opendaylight/controller/cluster/datastore/shardstrategy/ShardStrategy.java index 2df945edd5..9a05c381ea 100644 --- a/opendaylight/md-sal/sal-distributed-datastore/src/main/java/org/opendaylight/controller/cluster/datastore/shardstrategy/ShardStrategy.java +++ b/opendaylight/md-sal/sal-distributed-datastore/src/main/java/org/opendaylight/controller/cluster/datastore/shardstrategy/ShardStrategy.java @@ -16,6 +16,9 @@ import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier; public interface ShardStrategy { /** * Find the name of the shard in which the data pointed to by the specified path belongs in + *

        + * Should return the name of the default shard DefaultShardStrategy.DEFAULT_SHARD + * if no matching shard was found * * @param path The location of the data in the logical tree * @return diff --git a/opendaylight/md-sal/sal-distributed-datastore/src/main/java/org/opendaylight/controller/cluster/datastore/utils/ActorContext.java b/opendaylight/md-sal/sal-distributed-datastore/src/main/java/org/opendaylight/controller/cluster/datastore/utils/ActorContext.java index ac0893da5a..4706c66e25 100644 --- a/opendaylight/md-sal/sal-distributed-datastore/src/main/java/org/opendaylight/controller/cluster/datastore/utils/ActorContext.java +++ b/opendaylight/md-sal/sal-distributed-datastore/src/main/java/org/opendaylight/controller/cluster/datastore/utils/ActorContext.java @@ -18,7 +18,9 @@ import org.opendaylight.controller.cluster.datastore.ClusterWrapper; import org.opendaylight.controller.cluster.datastore.Configuration; import org.opendaylight.controller.cluster.datastore.exceptions.PrimaryNotFoundException; import org.opendaylight.controller.cluster.datastore.exceptions.TimeoutException; +import org.opendaylight.controller.cluster.datastore.messages.FindLocalShard; import org.opendaylight.controller.cluster.datastore.messages.FindPrimary; +import org.opendaylight.controller.cluster.datastore.messages.LocalShardFound; import org.opendaylight.controller.cluster.datastore.messages.PrimaryFound; import org.opendaylight.yangtools.yang.model.api.SchemaContext; import org.slf4j.Logger; @@ -91,6 +93,29 @@ public class ActorContext { return actorSystem.actorSelection(path); } + /** + * Finds a local shard given it's shard name and return it's ActorRef + * + * @param shardName the name of the local shard that needs to be found + * @return a reference to a local shard actor which represents the shard + * specified by the shardName + */ + public ActorRef findLocalShard(String shardName) { + Object result = executeLocalOperation(shardManager, + new FindLocalShard(shardName), ASK_DURATION); + + if (result instanceof LocalShardFound) { + LocalShardFound found = (LocalShardFound) result; + + LOG.debug("Local shard found {}", found.getPath()); + + return found.getPath(); + } + + return null; + } + + public String findPrimaryPath(String shardName) { Object result = executeLocalOperation(shardManager, new FindPrimary(shardName).toSerializable(), ASK_DURATION); @@ -170,6 +195,34 @@ public class ActorContext { return executeRemoteOperation(primary, message, duration); } + /** + * Execute an operation on the the local shard only + *

        + * This method first finds the address of the local shard if any. It then + * executes the operation on it. + *

        + * + * @param shardName the name of the shard on which the operation needs to be executed + * @param message the message that needs to be sent to the shard + * @param duration the time duration in which this operation should complete + * @return the message that was returned by the local actor on which the + * the operation was executed. If a local shard was not found then + * null is returned + * @throws org.opendaylight.controller.cluster.datastore.exceptions.TimeoutException + * if the operation does not complete in a specified time duration + */ + public Object executeLocalShardOperation(String shardName, Object message, + FiniteDuration duration) { + ActorRef local = findLocalShard(shardName); + + if(local != null) { + return executeLocalOperation(local, message, duration); + } + + return null; + } + + public void shutdown() { shardManager.tell(PoisonPill.getInstance(), null); actorSystem.shutdown(); diff --git a/opendaylight/md-sal/sal-distributed-datastore/src/main/resources/application.conf b/opendaylight/md-sal/sal-distributed-datastore/src/main/resources/application.conf index 76914c2c84..daac89c4c8 100644 --- a/opendaylight/md-sal/sal-distributed-datastore/src/main/resources/application.conf +++ b/opendaylight/md-sal/sal-distributed-datastore/src/main/resources/application.conf @@ -1,15 +1,60 @@ -ODLCluster{ -actor { - serializers { - java = "akka.serialization.JavaSerializer" - proto = "akka.remote.serialization.ProtobufSerializer" - } +odl-cluster-data { + akka { + cluster { + roles = [ + "member-1" + ] + } + actor { + provider = "akka.cluster.ClusterActorRefProvider" + serializers { + java = "akka.serialization.JavaSerializer" + proto = "akka.remote.serialization.ProtobufSerializer" + } + + serialization-bindings { + "com.google.protobuf.Message" = proto + + } + } + remote { + log-remote-lifecycle-events = off + netty.tcp { + hostname = "127.0.0.1" + port = 2550 + maximum-frame-size = 2097152 + send-buffer-size = 52428800 + receive-buffer-size = 52428800 + } + } - serialization-bindings { - "com.google.protobuf.Message" = proto + cluster { + seed-nodes = ["akka.tcp://opendaylight-cluster-data@127.0.0.1:2550"] - } + auto-down-unreachable-after = 10s } + } +} + +odl-cluster-rpc { + akka { + actor { + provider = "akka.cluster.ClusterActorRefProvider" -} \ No newline at end of file + } + remote { + log-remote-lifecycle-events = off + netty.tcp { + hostname = "127.0.0.1" + port = 2551 + } + } + + cluster { + seed-nodes = ["akka.tcp://opendaylight-cluster-rpc@127.0.0.1:2551"] + + auto-down-unreachable-after = 10s + } + } +} diff --git a/opendaylight/md-sal/sal-distributed-datastore/src/main/resources/modules.conf b/opendaylight/md-sal/sal-distributed-datastore/src/main/resources/modules.conf index 05ef33f759..e820703eeb 100644 --- a/opendaylight/md-sal/sal-distributed-datastore/src/main/resources/modules.conf +++ b/opendaylight/md-sal/sal-distributed-datastore/src/main/resources/modules.conf @@ -1,7 +1,7 @@ modules = [ { name = "inventory" - namespace = "urn:opendaylight:params:xml:ns:yang:controller:md:sal:dom:store:test:people" + namespace = "urn:opendaylight:inventory" shard-strategy = "module" } ] diff --git a/opendaylight/md-sal/sal-distributed-datastore/src/test/java/org/opendaylight/controller/cluster/datastore/BasicIntegrationTest.java b/opendaylight/md-sal/sal-distributed-datastore/src/test/java/org/opendaylight/controller/cluster/datastore/BasicIntegrationTest.java index 11ad559744..6599bd8eeb 100644 --- a/opendaylight/md-sal/sal-distributed-datastore/src/test/java/org/opendaylight/controller/cluster/datastore/BasicIntegrationTest.java +++ b/opendaylight/md-sal/sal-distributed-datastore/src/test/java/org/opendaylight/controller/cluster/datastore/BasicIntegrationTest.java @@ -12,6 +12,7 @@ import akka.actor.ActorPath; import akka.actor.ActorRef; import akka.actor.ActorSelection; import akka.actor.Props; +import akka.event.Logging; import akka.testkit.JavaTestKit; import junit.framework.Assert; import org.junit.Test; @@ -35,6 +36,8 @@ import scala.concurrent.duration.FiniteDuration; import java.util.Collections; +import static junit.framework.Assert.assertEquals; + public class BasicIntegrationTest extends AbstractActorTest { @Test @@ -61,17 +64,24 @@ public class BasicIntegrationTest extends AbstractActorTest { getRef()); - // Wait for Shard to become a Leader - try { - Thread.sleep(1000); - } catch (InterruptedException e) { - e.printStackTrace(); - } + // Wait for a specific log message to show up + final boolean result = + new JavaTestKit.EventFilter(Logging.Info.class + ) { + protected Boolean run() { + return true; + } + }.from(shard.path().toString()) + .message("Switching from state Candidate to Leader") + .occurrences(1).exec(); + + assertEquals(true, result); + // 1. Create a TransactionChain shard.tell(new CreateTransactionChain().toSerializable(), getRef()); final ActorSelection transactionChain = - new ExpectMsg("CreateTransactionChainReply") { + new ExpectMsg(duration("1 seconds"), "CreateTransactionChainReply") { protected ActorSelection match(Object in) { if (in.getClass().equals(CreateTransactionChainReply.SERIALIZABLE_CLASS)) { ActorPath transactionChainPath = @@ -90,10 +100,10 @@ public class BasicIntegrationTest extends AbstractActorTest { System.out.println("Successfully created transaction chain"); // 2. Create a Transaction on the TransactionChain - transactionChain.tell(new CreateTransaction("txn-1").toSerializable(), getRef()); + transactionChain.tell(new CreateTransaction("txn-1", TransactionProxy.TransactionType.WRITE_ONLY.ordinal() ).toSerializable(), getRef()); final ActorSelection transaction = - new ExpectMsg("CreateTransactionReply") { + new ExpectMsg(duration("1 seconds"), "CreateTransactionReply") { protected ActorSelection match(Object in) { if (CreateTransactionReply.SERIALIZABLE_CLASS.equals(in.getClass())) { CreateTransactionReply reply = CreateTransactionReply.fromSerializable(in); @@ -115,7 +125,7 @@ public class BasicIntegrationTest extends AbstractActorTest { ImmutableNodes.containerNode(TestModel.TEST_QNAME), TestModel.createTestContext()).toSerializable(), getRef()); - Boolean writeDone = new ExpectMsg("WriteDataReply") { + Boolean writeDone = new ExpectMsg(duration("1 seconds"), "WriteDataReply") { protected Boolean match(Object in) { if (in.getClass().equals(WriteDataReply.SERIALIZABLE_CLASS)) { return true; @@ -134,7 +144,7 @@ public class BasicIntegrationTest extends AbstractActorTest { transaction.tell(new ReadyTransaction().toSerializable(), getRef()); final ActorSelection cohort = - new ExpectMsg("ReadyTransactionReply") { + new ExpectMsg(duration("1 seconds"), "ReadyTransactionReply") { protected ActorSelection match(Object in) { if (in.getClass().equals(ReadyTransactionReply.SERIALIZABLE_CLASS)) { ActorPath cohortPath = @@ -157,7 +167,7 @@ public class BasicIntegrationTest extends AbstractActorTest { cohort.tell(new PreCommitTransaction().toSerializable(), getRef()); Boolean preCommitDone = - new ExpectMsg("PreCommitTransactionReply") { + new ExpectMsg(duration("1 seconds"), "PreCommitTransactionReply") { protected Boolean match(Object in) { if (in.getClass().equals(PreCommitTransactionReply.SERIALIZABLE_CLASS)) { return true; diff --git a/opendaylight/md-sal/sal-distributed-datastore/src/test/java/org/opendaylight/controller/cluster/datastore/CompositeModificationPayloadTest.java b/opendaylight/md-sal/sal-distributed-datastore/src/test/java/org/opendaylight/controller/cluster/datastore/CompositeModificationPayloadTest.java new file mode 100644 index 0000000000..400eab1d8e --- /dev/null +++ b/opendaylight/md-sal/sal-distributed-datastore/src/test/java/org/opendaylight/controller/cluster/datastore/CompositeModificationPayloadTest.java @@ -0,0 +1,84 @@ +package org.opendaylight.controller.cluster.datastore; + +import org.junit.After; +import org.junit.Assert; +import org.junit.Test; +import org.opendaylight.controller.cluster.datastore.modification.MutableCompositeModification; +import org.opendaylight.controller.cluster.datastore.modification.WriteModification; +import org.opendaylight.controller.cluster.raft.ReplicatedLogEntry; +import org.opendaylight.controller.cluster.raft.messages.AppendEntries; +import org.opendaylight.controller.cluster.raft.protobuff.client.messages.Payload; +import org.opendaylight.controller.cluster.raft.protobuff.messages.AppendEntriesMessages; +import org.opendaylight.controller.md.cluster.datastore.model.TestModel; +import org.opendaylight.yangtools.yang.data.impl.schema.ImmutableNodes; + +import java.io.File; +import java.io.FileInputStream; +import java.io.FileOutputStream; +import java.io.IOException; +import java.util.ArrayList; +import java.util.List; + +public class CompositeModificationPayloadTest { + + + private static final String SERIALIZE_OUT = "serialize.out"; + + @After + public void shutDown(){ + File f = new File(SERIALIZE_OUT); + if(f.exists()){ + f.delete(); + } + } + + @Test + public void testBasic() throws IOException { + + List entries = new ArrayList<>(); + + entries.add(0, new ReplicatedLogEntry() { + @Override public Payload getData() { + WriteModification writeModification = + new WriteModification(TestModel.TEST_PATH, ImmutableNodes + .containerNode(TestModel.TEST_QNAME), + TestModel.createTestContext()); + + MutableCompositeModification compositeModification = + new MutableCompositeModification(); + + compositeModification.addModification(writeModification); + + return new CompositeModificationPayload(compositeModification.toSerializable()); + } + + @Override public long getTerm() { + return 1; + } + + @Override public long getIndex() { + return 1; + } + }); + + AppendEntries appendEntries = + new AppendEntries(1, "member-1", 0, 100, entries, 1); + + AppendEntriesMessages.AppendEntries o = (AppendEntriesMessages.AppendEntries) appendEntries.toSerializable(); + + o.writeDelimitedTo(new FileOutputStream(SERIALIZE_OUT)); + + AppendEntriesMessages.AppendEntries appendEntries2 = + AppendEntriesMessages.AppendEntries + .parseDelimitedFrom(new FileInputStream(SERIALIZE_OUT)); + + AppendEntries appendEntries1 = AppendEntries.fromSerializable(appendEntries2); + + Payload data = appendEntries1.getEntries().get(0).getData(); + + + Assert.assertTrue(((CompositeModificationPayload) data).getModification().toString().contains(TestModel.TEST_QNAME.getNamespace().toString())); + + } + +} diff --git a/opendaylight/md-sal/sal-distributed-datastore/src/test/java/org/opendaylight/controller/cluster/datastore/DataChangeListenerProxyTest.java b/opendaylight/md-sal/sal-distributed-datastore/src/test/java/org/opendaylight/controller/cluster/datastore/DataChangeListenerProxyTest.java index 8c1cbbbba0..b2ee4a49fe 100644 --- a/opendaylight/md-sal/sal-distributed-datastore/src/test/java/org/opendaylight/controller/cluster/datastore/DataChangeListenerProxyTest.java +++ b/opendaylight/md-sal/sal-distributed-datastore/src/test/java/org/opendaylight/controller/cluster/datastore/DataChangeListenerProxyTest.java @@ -94,7 +94,7 @@ public class DataChangeListenerProxyTest extends AbstractActorTest { Assert.assertEquals(1, listMessages.size()); - Assert.assertTrue(listMessages.get(0).getClass().equals(DataChanged.SERIALIZABLE_CLASS)); + Assert.assertTrue(listMessages.get(0).getClass().equals(DataChanged.class)); } } diff --git a/opendaylight/md-sal/sal-distributed-datastore/src/test/java/org/opendaylight/controller/cluster/datastore/DataChangeListenerRegistrationTest.java b/opendaylight/md-sal/sal-distributed-datastore/src/test/java/org/opendaylight/controller/cluster/datastore/DataChangeListenerRegistrationTest.java index 8413bac3a7..920248521a 100644 --- a/opendaylight/md-sal/sal-distributed-datastore/src/test/java/org/opendaylight/controller/cluster/datastore/DataChangeListenerRegistrationTest.java +++ b/opendaylight/md-sal/sal-distributed-datastore/src/test/java/org/opendaylight/controller/cluster/datastore/DataChangeListenerRegistrationTest.java @@ -41,7 +41,7 @@ public class DataChangeListenerRegistrationTest extends AbstractActorTest { subject.tell(new CloseDataChangeListenerRegistration().toSerializable(), getRef()); - final String out = new ExpectMsg("match hint") { + final String out = new ExpectMsg(duration("1 seconds"), "match hint") { // do not put code outside this method, will run afterwards protected String match(Object in) { if (in.getClass().equals(CloseDataChangeListenerRegistrationReply.SERIALIZABLE_CLASS)) { diff --git a/opendaylight/md-sal/sal-distributed-datastore/src/test/java/org/opendaylight/controller/cluster/datastore/DataChangeListenerTest.java b/opendaylight/md-sal/sal-distributed-datastore/src/test/java/org/opendaylight/controller/cluster/datastore/DataChangeListenerTest.java index fd61032220..26ec583b3e 100644 --- a/opendaylight/md-sal/sal-distributed-datastore/src/test/java/org/opendaylight/controller/cluster/datastore/DataChangeListenerTest.java +++ b/opendaylight/md-sal/sal-distributed-datastore/src/test/java/org/opendaylight/controller/cluster/datastore/DataChangeListenerTest.java @@ -6,6 +6,7 @@ import akka.testkit.JavaTestKit; import org.junit.Test; import org.opendaylight.controller.cluster.datastore.messages.DataChanged; import org.opendaylight.controller.cluster.datastore.messages.DataChangedReply; +import org.opendaylight.controller.cluster.datastore.messages.EnableNotification; import org.opendaylight.controller.md.cluster.datastore.model.CompositeModel; import org.opendaylight.controller.md.sal.common.api.data.AsyncDataChangeEvent; import org.opendaylight.controller.md.sal.common.api.data.AsyncDataChangeListener; @@ -86,24 +87,28 @@ public class DataChangeListenerTest extends AbstractActorTest { } @Test - public void testDataChanged(){ + public void testDataChangedWhenNotificationsAreEnabled(){ new JavaTestKit(getSystem()) {{ final MockDataChangeListener listener = new MockDataChangeListener(); final Props props = DataChangeListener.props(CompositeModel.createTestContext(),listener,CompositeModel.FAMILY_PATH ); final ActorRef subject = - getSystem().actorOf(props, "testDataChanged"); + getSystem().actorOf(props, "testDataChangedNotificationsEnabled"); new Within(duration("1 seconds")) { protected void run() { + // Let the DataChangeListener know that notifications should + // be enabled + subject.tell(new EnableNotification(true), getRef()); + subject.tell( - new DataChanged(CompositeModel.createTestContext(),new MockDataChangedEvent()).toSerializable(), + new DataChanged(CompositeModel.createTestContext(),new MockDataChangedEvent()), getRef()); - final Boolean out = new ExpectMsg("dataChanged") { + final Boolean out = new ExpectMsg(duration("800 millis"), "dataChanged") { // do not put code outside this method, will run afterwards protected Boolean match(Object in) { - if (in.getClass().equals(DataChangedReply.SERIALIZABLE_CLASS)) { + if (in != null && in.getClass().equals(DataChangedReply.class)) { return true; } else { @@ -115,7 +120,30 @@ public class DataChangeListenerTest extends AbstractActorTest { assertTrue(out); assertTrue(listener.gotIt()); assertNotNull(listener.getChange().getCreatedData()); - // Will wait for the rest of the 3 seconds + + expectNoMsg(); + } + + + }; + }}; + } + + @Test + public void testDataChangedWhenNotificationsAreDisabled(){ + new JavaTestKit(getSystem()) {{ + final MockDataChangeListener listener = new MockDataChangeListener(); + final Props props = DataChangeListener.props(CompositeModel.createTestContext(),listener,CompositeModel.FAMILY_PATH ); + final ActorRef subject = + getSystem().actorOf(props, "testDataChangedNotificationsDisabled"); + + new Within(duration("1 seconds")) { + protected void run() { + + subject.tell( + new DataChanged(CompositeModel.createTestContext(),new MockDataChangedEvent()), + getRef()); + expectNoMsg(); } diff --git a/opendaylight/md-sal/sal-distributed-datastore/src/test/java/org/opendaylight/controller/cluster/datastore/DistributedDataStoreIntegrationTest.java b/opendaylight/md-sal/sal-distributed-datastore/src/test/java/org/opendaylight/controller/cluster/datastore/DistributedDataStoreIntegrationTest.java index b5e3d24ef6..fc527b6bff 100644 --- a/opendaylight/md-sal/sal-distributed-datastore/src/test/java/org/opendaylight/controller/cluster/datastore/DistributedDataStoreIntegrationTest.java +++ b/opendaylight/md-sal/sal-distributed-datastore/src/test/java/org/opendaylight/controller/cluster/datastore/DistributedDataStoreIntegrationTest.java @@ -1,9 +1,12 @@ package org.opendaylight.controller.cluster.datastore; import akka.actor.ActorSystem; +import akka.event.Logging; import akka.testkit.JavaTestKit; import com.google.common.base.Optional; import com.google.common.util.concurrent.ListenableFuture; +import junit.framework.Assert; +import org.apache.commons.io.FileUtils; import org.junit.After; import org.junit.Before; import org.junit.Test; @@ -18,17 +21,29 @@ import org.opendaylight.controller.sal.core.spi.data.DOMStoreThreePhaseCommitCoh import org.opendaylight.yangtools.yang.data.api.schema.NormalizedNode; import org.opendaylight.yangtools.yang.data.impl.schema.ImmutableNodes; +import java.io.File; +import java.io.IOException; import java.util.concurrent.ExecutionException; +import java.util.concurrent.TimeUnit; +import java.util.concurrent.TimeoutException; import static junit.framework.Assert.assertEquals; import static junit.framework.Assert.assertTrue; +import static junit.framework.Assert.fail; -public class DistributedDataStoreIntegrationTest{ +public class DistributedDataStoreIntegrationTest { private static ActorSystem system; @Before - public void setUp() { + public void setUp() throws IOException { + File journal = new File("journal"); + + if(journal.exists()) { + FileUtils.deleteDirectory(journal); + } + + System.setProperty("shard.persistent", "false"); system = ActorSystem.create("test"); } @@ -45,79 +60,152 @@ public class DistributedDataStoreIntegrationTest{ @Test public void integrationTest() throws Exception { - Configuration configuration = new ConfigurationImpl("module-shards.conf", "modules.conf"); + final Configuration configuration = new ConfigurationImpl("module-shards.conf", "modules.conf"); ShardStrategyFactory.setConfiguration(configuration); - DistributedDataStore distributedDataStore = - new DistributedDataStore(getSystem(), "config", new MockClusterWrapper(), configuration); - distributedDataStore.onGlobalContextUpdated(TestModel.createTestContext()); - Thread.sleep(1000); - DOMStoreReadWriteTransaction transaction = - distributedDataStore.newReadWriteTransaction(); + new JavaTestKit(getSystem()) { + { + + new Within(duration("10 seconds")) { + protected void run() { + try { + final DistributedDataStore distributedDataStore = + new DistributedDataStore(getSystem(), "config", new MockClusterWrapper(), configuration); + + distributedDataStore.onGlobalContextUpdated(TestModel.createTestContext()); + + // Wait for a specific log message to show up + final boolean result = + new JavaTestKit.EventFilter(Logging.Info.class + ) { + protected Boolean run() { + return true; + } + }.from("akka://test/user/shardmanager-config/member-1-shard-test-1-config") + .message("Switching from state Candidate to Leader") + .occurrences(1).exec(); + + assertEquals(true, result); + + DOMStoreReadWriteTransaction transaction = + distributedDataStore.newReadWriteTransaction(); - transaction.write(TestModel.TEST_PATH, ImmutableNodes.containerNode(TestModel.TEST_QNAME)); + transaction + .write(TestModel.TEST_PATH, ImmutableNodes + .containerNode(TestModel.TEST_QNAME)); - ListenableFuture>> future = - transaction.read(TestModel.TEST_PATH); + ListenableFuture>> + future = + transaction.read(TestModel.TEST_PATH); - Optional> optional = future.get(); + Optional> optional = + future.get(); - NormalizedNode normalizedNode = optional.get(); + Assert.assertTrue("Node not found", optional.isPresent()); - assertEquals(TestModel.TEST_QNAME, normalizedNode.getNodeType()); + NormalizedNode normalizedNode = + optional.get(); - DOMStoreThreePhaseCommitCohort ready = transaction.ready(); + assertEquals(TestModel.TEST_QNAME, + normalizedNode.getNodeType()); - ListenableFuture canCommit = ready.canCommit(); + DOMStoreThreePhaseCommitCohort ready = + transaction.ready(); - assertTrue(canCommit.get()); + ListenableFuture canCommit = + ready.canCommit(); - ListenableFuture preCommit = ready.preCommit(); + assertTrue(canCommit.get(5, TimeUnit.SECONDS)); - preCommit.get(); + ListenableFuture preCommit = + ready.preCommit(); - ListenableFuture commit = ready.commit(); + preCommit.get(5, TimeUnit.SECONDS); - commit.get(); + ListenableFuture commit = ready.commit(); + + commit.get(5, TimeUnit.SECONDS); + } catch (ExecutionException | TimeoutException | InterruptedException e){ + fail(e.getMessage()); + } + } + }; + } + }; } - @Test + //FIXME : Disabling test because it's flaky + //@Test public void integrationTestWithMultiShardConfiguration() - throws ExecutionException, InterruptedException { - Configuration configuration = new ConfigurationImpl("module-shards.conf", "modules.conf"); + throws ExecutionException, InterruptedException, TimeoutException { + final Configuration configuration = new ConfigurationImpl("module-shards.conf", "modules.conf"); ShardStrategyFactory.setConfiguration(configuration); - DistributedDataStore distributedDataStore = - new DistributedDataStore(getSystem(), "config", new MockClusterWrapper(), configuration); + + new JavaTestKit(getSystem()) { + { + + new Within(duration("10 seconds")) { + protected void run() { + try { + final DistributedDataStore distributedDataStore = + new DistributedDataStore(getSystem(), "config", + new MockClusterWrapper(), configuration); + + distributedDataStore.onGlobalContextUpdated( + SchemaContextHelper.full()); + + // Wait for a specific log message to show up + final boolean result = + new JavaTestKit.EventFilter( + Logging.Info.class + ) { + protected Boolean run() { + return true; + } + }.from( + "akka://test/user/shardmanager-config/member-1-shard-cars-1-config") + .message( + "Switching from state Candidate to Leader") + .occurrences(1) + .exec(); + + Thread.sleep(1000); - distributedDataStore.onGlobalContextUpdated(SchemaContextHelper.full()); + DOMStoreReadWriteTransaction transaction = + distributedDataStore.newReadWriteTransaction(); - Thread.sleep(1000); + transaction.write(CarsModel.BASE_PATH, CarsModel.emptyContainer()); + transaction.write(PeopleModel.BASE_PATH, PeopleModel.emptyContainer()); - DOMStoreReadWriteTransaction transaction = - distributedDataStore.newReadWriteTransaction(); + DOMStoreThreePhaseCommitCohort ready = transaction.ready(); - transaction.write(CarsModel.BASE_PATH, CarsModel.emptyContainer()); - transaction.write(PeopleModel.BASE_PATH, PeopleModel.emptyContainer()); + ListenableFuture canCommit = ready.canCommit(); - DOMStoreThreePhaseCommitCohort ready = transaction.ready(); + assertTrue(canCommit.get(5, TimeUnit.SECONDS)); - ListenableFuture canCommit = ready.canCommit(); + ListenableFuture preCommit = ready.preCommit(); - assertTrue(canCommit.get()); + preCommit.get(5, TimeUnit.SECONDS); - ListenableFuture preCommit = ready.preCommit(); + ListenableFuture commit = ready.commit(); - preCommit.get(); + commit.get(5, TimeUnit.SECONDS); - ListenableFuture commit = ready.commit(); + assertEquals(true, result); + } catch(ExecutionException | TimeoutException | InterruptedException e){ + fail(e.getMessage()); + } + } + }; + } + }; - commit.get(); } diff --git a/opendaylight/md-sal/sal-distributed-datastore/src/test/java/org/opendaylight/controller/cluster/datastore/DistributedDataStoreTest.java b/opendaylight/md-sal/sal-distributed-datastore/src/test/java/org/opendaylight/controller/cluster/datastore/DistributedDataStoreTest.java index 23a1ed4931..d1beab9049 100644 --- a/opendaylight/md-sal/sal-distributed-datastore/src/test/java/org/opendaylight/controller/cluster/datastore/DistributedDataStoreTest.java +++ b/opendaylight/md-sal/sal-distributed-datastore/src/test/java/org/opendaylight/controller/cluster/datastore/DistributedDataStoreTest.java @@ -54,8 +54,8 @@ public class DistributedDataStoreTest extends AbstractActorTest{ } @org.junit.Test - public void testRegisterChangeListener() throws Exception { - mockActorContext.setExecuteShardOperationResponse(new RegisterChangeListenerReply(doNothingActorRef.path()).toSerializable()); + public void testRegisterChangeListenerWhenShardIsNotLocal() throws Exception { + ListenerRegistration registration = distributedDataStore.registerChangeListener(TestModel.TEST_PATH, new AsyncDataChangeListener>() { @Override @@ -64,9 +64,31 @@ public class DistributedDataStoreTest extends AbstractActorTest{ } }, AsyncDataBroker.DataChangeScope.BASE); + // Since we do not expect the shard to be local registration will return a NoOpRegistration + Assert.assertTrue(registration instanceof NoOpDataChangeListenerRegistration); + + Assert.assertNotNull(registration); + } + + @org.junit.Test + public void testRegisterChangeListenerWhenShardIsLocal() throws Exception { + + mockActorContext.setExecuteLocalShardOperationResponse(new RegisterChangeListenerReply(doNothingActorRef.path())); + + ListenerRegistration registration = + distributedDataStore.registerChangeListener(TestModel.TEST_PATH, new AsyncDataChangeListener>() { + @Override + public void onDataChanged(AsyncDataChangeEvent> change) { + throw new UnsupportedOperationException("onDataChanged"); + } + }, AsyncDataBroker.DataChangeScope.BASE); + + Assert.assertTrue(registration instanceof DataChangeListenerRegistrationProxy); + Assert.assertNotNull(registration); } + @org.junit.Test public void testCreateTransactionChain() throws Exception { final DOMStoreTransactionChain transactionChain = distributedDataStore.createTransactionChain(); diff --git a/opendaylight/md-sal/sal-distributed-datastore/src/test/java/org/opendaylight/controller/cluster/datastore/ShardManagerTest.java b/opendaylight/md-sal/sal-distributed-datastore/src/test/java/org/opendaylight/controller/cluster/datastore/ShardManagerTest.java index 87d257a3f2..e9ad450ed8 100644 --- a/opendaylight/md-sal/sal-distributed-datastore/src/test/java/org/opendaylight/controller/cluster/datastore/ShardManagerTest.java +++ b/opendaylight/md-sal/sal-distributed-datastore/src/test/java/org/opendaylight/controller/cluster/datastore/ShardManagerTest.java @@ -1,5 +1,6 @@ package org.opendaylight.controller.cluster.datastore; +import akka.actor.ActorRef; import akka.actor.ActorSystem; import akka.actor.Props; import akka.testkit.JavaTestKit; @@ -8,13 +9,19 @@ import junit.framework.Assert; import org.junit.AfterClass; import org.junit.BeforeClass; import org.junit.Test; +import org.opendaylight.controller.cluster.datastore.messages.FindLocalShard; import org.opendaylight.controller.cluster.datastore.messages.FindPrimary; +import org.opendaylight.controller.cluster.datastore.messages.LocalShardFound; +import org.opendaylight.controller.cluster.datastore.messages.LocalShardNotFound; import org.opendaylight.controller.cluster.datastore.messages.PrimaryFound; import org.opendaylight.controller.cluster.datastore.messages.PrimaryNotFound; import org.opendaylight.controller.cluster.datastore.utils.MockClusterWrapper; import org.opendaylight.controller.cluster.datastore.utils.MockConfiguration; import scala.concurrent.duration.Duration; +import static junit.framework.Assert.assertEquals; +import static org.junit.Assert.assertTrue; + public class ShardManagerTest { private static ActorSystem system; @@ -47,7 +54,6 @@ public class ShardManagerTest { expectMsgEquals(Duration.Zero(), new PrimaryNotFound("inventory").toSerializable()); - // Will wait for the rest of the 3 seconds expectNoMsg(); } }; @@ -64,13 +70,81 @@ public class ShardManagerTest { final TestActorRef subject = TestActorRef.create(system, props); - // the run() method needs to finish within 3 seconds new Within(duration("1 seconds")) { protected void run() { subject.tell(new FindPrimary(Shard.DEFAULT_NAME).toSerializable(), getRef()); - expectMsgClass(PrimaryFound.SERIALIZABLE_CLASS); + expectMsgClass(duration("1 seconds"), PrimaryFound.SERIALIZABLE_CLASS); + + expectNoMsg(); + } + }; + }}; + } + + @Test + public void testOnReceiveFindLocalShardForNonExistentShard() throws Exception { + + new JavaTestKit(system) {{ + final Props props = ShardManager + .props("config", new MockClusterWrapper(), + new MockConfiguration()); + final TestActorRef subject = + TestActorRef.create(system, props); + + new Within(duration("1 seconds")) { + protected void run() { + + subject.tell(new FindLocalShard("inventory"), getRef()); + + final String out = new ExpectMsg(duration("1 seconds"), "find local") { + protected String match(Object in) { + if (in instanceof LocalShardNotFound) { + return ((LocalShardNotFound) in).getShardName(); + } else { + throw noMatch(); + } + } + }.get(); // this extracts the received message + + assertEquals("inventory", out); + + expectNoMsg(); + } + }; + }}; + } + + @Test + public void testOnReceiveFindLocalShardForExistentShard() throws Exception { + + final MockClusterWrapper mockClusterWrapper = new MockClusterWrapper(); + + new JavaTestKit(system) {{ + final Props props = ShardManager + .props("config", mockClusterWrapper, + new MockConfiguration()); + final TestActorRef subject = + TestActorRef.create(system, props); + + new Within(duration("1 seconds")) { + protected void run() { + + subject.tell(new FindLocalShard(Shard.DEFAULT_NAME), getRef()); + + final ActorRef out = new ExpectMsg(duration("1 seconds"), "find local") { + protected ActorRef match(Object in) { + if (in instanceof LocalShardFound) { + return ((LocalShardFound) in).getPath(); + } else { + throw noMatch(); + } + } + }.get(); // this extracts the received message + + assertTrue(out.path().toString(), out.path().toString().contains("member-1-shard-default-config")); + expectNoMsg(); } @@ -96,7 +170,7 @@ public class ShardManagerTest { subject.tell(new FindPrimary("astronauts").toSerializable(), getRef()); - final String out = new ExpectMsg("primary found") { + final String out = new ExpectMsg(duration("1 seconds"), "primary found") { // do not put code outside this method, will run afterwards protected String match(Object in) { if (in.getClass().equals(PrimaryFound.SERIALIZABLE_CLASS)) { @@ -134,13 +208,13 @@ public class ShardManagerTest { subject.tell(new FindPrimary("astronauts").toSerializable(), getRef()); - expectMsgClass(PrimaryFound.SERIALIZABLE_CLASS); + expectMsgClass(duration("1 seconds"), PrimaryFound.SERIALIZABLE_CLASS); MockClusterWrapper.sendMemberRemoved(subject, "member-2", getRef().path().toString()); subject.tell(new FindPrimary("astronauts").toSerializable(), getRef()); - expectMsgClass(PrimaryNotFound.SERIALIZABLE_CLASS); + expectMsgClass(duration("1 seconds"), PrimaryNotFound.SERIALIZABLE_CLASS); expectNoMsg(); } diff --git a/opendaylight/md-sal/sal-distributed-datastore/src/test/java/org/opendaylight/controller/cluster/datastore/ShardTest.java b/opendaylight/md-sal/sal-distributed-datastore/src/test/java/org/opendaylight/controller/cluster/datastore/ShardTest.java index 7d57ea8284..431a266b14 100644 --- a/opendaylight/md-sal/sal-distributed-datastore/src/test/java/org/opendaylight/controller/cluster/datastore/ShardTest.java +++ b/opendaylight/md-sal/sal-distributed-datastore/src/test/java/org/opendaylight/controller/cluster/datastore/ShardTest.java @@ -2,11 +2,14 @@ package org.opendaylight.controller.cluster.datastore; import akka.actor.ActorRef; import akka.actor.Props; +import akka.event.Logging; import akka.testkit.JavaTestKit; +import junit.framework.Assert; import org.junit.Test; import org.opendaylight.controller.cluster.datastore.messages.CreateTransaction; import org.opendaylight.controller.cluster.datastore.messages.CreateTransactionChain; import org.opendaylight.controller.cluster.datastore.messages.CreateTransactionChainReply; +import org.opendaylight.controller.cluster.datastore.messages.EnableNotification; import org.opendaylight.controller.cluster.datastore.messages.PeerAddressResolved; import org.opendaylight.controller.cluster.datastore.messages.RegisterChangeListener; import org.opendaylight.controller.cluster.datastore.messages.RegisterChangeListenerReply; @@ -24,6 +27,7 @@ import java.util.Collections; import java.util.HashMap; import java.util.Map; +import static junit.framework.Assert.assertFalse; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertTrue; @@ -36,19 +40,25 @@ public class ShardTest extends AbstractActorTest { getSystem().actorOf(props, "testCreateTransactionChain"); - // Wait for Shard to become a Leader - try { - Thread.sleep(1000); - } catch (InterruptedException e) { - e.printStackTrace(); - } + // Wait for a specific log message to show up + final boolean result = + new JavaTestKit.EventFilter(Logging.Info.class + ) { + protected Boolean run() { + return true; + } + }.from(subject.path().toString()) + .message("Switching from state Candidate to Leader") + .occurrences(1).exec(); + + Assert.assertEquals(true, result); new Within(duration("1 seconds")) { protected void run() { subject.tell(new CreateTransactionChain().toSerializable(), getRef()); - final String out = new ExpectMsg("match hint") { + final String out = new ExpectMsg(duration("1 seconds"), "match hint") { // do not put code outside this method, will run afterwards protected String match(Object in) { if (in.getClass().equals(CreateTransactionChainReply.SERIALIZABLE_CLASS)){ @@ -89,15 +99,28 @@ public class ShardTest extends AbstractActorTest { getRef()); subject.tell(new RegisterChangeListener(TestModel.TEST_PATH, - getRef().path(), AsyncDataBroker.DataChangeScope.BASE).toSerializable(), + getRef().path(), AsyncDataBroker.DataChangeScope.BASE), getRef()); - final String out = new ExpectMsg("match hint") { + final Boolean notificationEnabled = new ExpectMsg("enable notification") { + // do not put code outside this method, will run afterwards + protected Boolean match(Object in) { + if(in instanceof EnableNotification){ + return ((EnableNotification) in).isEnabled(); + } else { + throw noMatch(); + } + } + }.get(); // this extracts the received message + + assertFalse(notificationEnabled); + + final String out = new ExpectMsg(duration("1 seconds"), "match hint") { // do not put code outside this method, will run afterwards protected String match(Object in) { - if (in.getClass().equals(RegisterChangeListenerReply.SERIALIZABLE_CLASS)) { + if (in.getClass().equals(RegisterChangeListenerReply.class)) { RegisterChangeListenerReply reply = - RegisterChangeListenerReply.fromSerializable(getSystem(),in); + (RegisterChangeListenerReply) in; return reply.getListenerRegistrationPath() .toString(); } else { @@ -108,8 +131,6 @@ public class ShardTest extends AbstractActorTest { assertTrue(out.matches( "akka:\\/\\/test\\/user\\/testRegisterChangeListener\\/\\$.*")); - // Will wait for the rest of the 3 seconds - expectNoMsg(); } @@ -125,13 +146,18 @@ public class ShardTest extends AbstractActorTest { getSystem().actorOf(props, "testCreateTransaction"); - // Wait for Shard to become a Leader - try { - Thread.sleep(1000); - } catch (InterruptedException e) { - e.printStackTrace(); - } + // Wait for a specific log message to show up + final boolean result = + new JavaTestKit.EventFilter(Logging.Info.class + ) { + protected Boolean run() { + return true; + } + }.from(subject.path().toString()) + .message("Switching from state Candidate to Leader") + .occurrences(1).exec(); + Assert.assertEquals(true, result); new Within(duration("1 seconds")) { protected void run() { @@ -140,10 +166,10 @@ public class ShardTest extends AbstractActorTest { new UpdateSchemaContext(TestModel.createTestContext()), getRef()); - subject.tell(new CreateTransaction("txn-1").toSerializable(), + subject.tell(new CreateTransaction("txn-1", TransactionProxy.TransactionType.READ_ONLY.ordinal() ).toSerializable(), getRef()); - final String out = new ExpectMsg("match hint") { + final String out = new ExpectMsg(duration("1 seconds"), "match hint") { // do not put code outside this method, will run afterwards protected String match(Object in) { if (in instanceof CreateTransactionReply) { diff --git a/opendaylight/md-sal/sal-distributed-datastore/src/test/java/org/opendaylight/controller/cluster/datastore/ShardTransactionChainTest.java b/opendaylight/md-sal/sal-distributed-datastore/src/test/java/org/opendaylight/controller/cluster/datastore/ShardTransactionChainTest.java index 6330ad8acc..b35880a6a5 100644 --- a/opendaylight/md-sal/sal-distributed-datastore/src/test/java/org/opendaylight/controller/cluster/datastore/ShardTransactionChainTest.java +++ b/opendaylight/md-sal/sal-distributed-datastore/src/test/java/org/opendaylight/controller/cluster/datastore/ShardTransactionChainTest.java @@ -33,9 +33,9 @@ public class ShardTransactionChainTest extends AbstractActorTest { new Within(duration("1 seconds")) { protected void run() { - subject.tell(new CreateTransaction("txn-1").toSerializable(), getRef()); + subject.tell(new CreateTransaction("txn-1", TransactionProxy.TransactionType.READ_ONLY.ordinal() ).toSerializable(), getRef()); - final String out = new ExpectMsg("match hint") { + final String out = new ExpectMsg(duration("1 seconds"), "match hint") { // do not put code outside this method, will run afterwards protected String match(Object in) { if (in.getClass().equals(CreateTransactionReply.SERIALIZABLE_CLASS)) { @@ -70,7 +70,7 @@ public class ShardTransactionChainTest extends AbstractActorTest { subject.tell(new CloseTransactionChain().toSerializable(), getRef()); - final String out = new ExpectMsg("match hint") { + final String out = new ExpectMsg(duration("1 seconds"), "match hint") { // do not put code outside this method, will run afterwards protected String match(Object in) { if (in.getClass().equals(CloseTransactionChainReply.SERIALIZABLE_CLASS)) { diff --git a/opendaylight/md-sal/sal-distributed-datastore/src/test/java/org/opendaylight/controller/cluster/datastore/ShardTransactionTest.java b/opendaylight/md-sal/sal-distributed-datastore/src/test/java/org/opendaylight/controller/cluster/datastore/ShardTransactionTest.java index 7884eeccda..632ecc29cd 100644 --- a/opendaylight/md-sal/sal-distributed-datastore/src/test/java/org/opendaylight/controller/cluster/datastore/ShardTransactionTest.java +++ b/opendaylight/md-sal/sal-distributed-datastore/src/test/java/org/opendaylight/controller/cluster/datastore/ShardTransactionTest.java @@ -4,8 +4,10 @@ import akka.actor.ActorRef; import akka.actor.Props; import akka.actor.Terminated; import akka.testkit.JavaTestKit; +import akka.testkit.TestActorRef; import com.google.common.util.concurrent.ListeningExecutorService; import com.google.common.util.concurrent.MoreExecutors; +import org.junit.Assert; import org.junit.Test; import org.opendaylight.controller.cluster.datastore.messages.CloseTransaction; import org.opendaylight.controller.cluster.datastore.messages.CloseTransactionReply; @@ -53,7 +55,7 @@ public class ShardTransactionTest extends AbstractActorTest { new JavaTestKit(getSystem()) {{ final ActorRef shard = getSystem().actorOf(Shard.props("config", Collections.EMPTY_MAP)); final Props props = - ShardTransaction.props(store.newReadWriteTransaction(), shard, testSchemaContext); + ShardTransaction.props(store.newReadOnlyTransaction(), shard, testSchemaContext); final ActorRef subject = getSystem().actorOf(props, "testReadData"); new Within(duration("1 seconds")) { @@ -63,7 +65,7 @@ public class ShardTransactionTest extends AbstractActorTest { new ReadData(YangInstanceIdentifier.builder().build()).toSerializable(), getRef()); - final String out = new ExpectMsg("match hint") { + final String out = new ExpectMsg(duration("1 seconds"), "match hint") { // do not put code outside this method, will run afterwards protected String match(Object in) { if (in.getClass().equals(ReadDataReply.SERIALIZABLE_CLASS)) { @@ -93,7 +95,7 @@ public class ShardTransactionTest extends AbstractActorTest { new JavaTestKit(getSystem()) {{ final ActorRef shard = getSystem().actorOf(Shard.props("config", Collections.EMPTY_MAP)); final Props props = - ShardTransaction.props(store.newReadWriteTransaction(), shard, testSchemaContext); + ShardTransaction.props( store.newReadOnlyTransaction(), shard, testSchemaContext); final ActorRef subject = getSystem().actorOf(props, "testReadDataWhenDataNotFound"); new Within(duration("1 seconds")) { @@ -103,7 +105,7 @@ public class ShardTransactionTest extends AbstractActorTest { new ReadData(TestModel.TEST_PATH).toSerializable(), getRef()); - final String out = new ExpectMsg("match hint") { + final String out = new ExpectMsg(duration("1 seconds"), "match hint") { // do not put code outside this method, will run afterwards protected String match(Object in) { if (in.getClass().equals(ReadDataReply.SERIALIZABLE_CLASS)) { @@ -139,7 +141,7 @@ public class ShardTransactionTest extends AbstractActorTest { getRef()); final CompositeModification compositeModification = - new ExpectMsg("match hint") { + new ExpectMsg(duration("1 seconds"), "match hint") { // do not put code outside this method, will run afterwards protected CompositeModification match(Object in) { if (in instanceof ShardTransaction.GetCompositeModificationReply) { @@ -167,7 +169,7 @@ public class ShardTransactionTest extends AbstractActorTest { new JavaTestKit(getSystem()) {{ final ActorRef shard = getSystem().actorOf(Shard.props("config", Collections.EMPTY_MAP)); final Props props = - ShardTransaction.props(store.newReadWriteTransaction(), shard, TestModel.createTestContext()); + ShardTransaction.props(store.newWriteOnlyTransaction(), shard, TestModel.createTestContext()); final ActorRef subject = getSystem().actorOf(props, "testWriteData"); @@ -178,7 +180,7 @@ public class ShardTransactionTest extends AbstractActorTest { ImmutableNodes.containerNode(TestModel.TEST_QNAME), TestModel.createTestContext()).toSerializable(), getRef()); - final String out = new ExpectMsg("match hint") { + final String out = new ExpectMsg(duration("1 seconds"), "match hint") { // do not put code outside this method, will run afterwards protected String match(Object in) { if (in.getClass().equals(WriteDataReply.SERIALIZABLE_CLASS)) { @@ -244,7 +246,7 @@ public class ShardTransactionTest extends AbstractActorTest { new JavaTestKit(getSystem()) {{ final ActorRef shard = getSystem().actorOf(Shard.props("config", Collections.EMPTY_MAP)); final Props props = - ShardTransaction.props(store.newReadWriteTransaction(), shard, TestModel.createTestContext()); + ShardTransaction.props( store.newWriteOnlyTransaction(), shard, TestModel.createTestContext()); final ActorRef subject = getSystem().actorOf(props, "testDeleteData"); @@ -253,7 +255,7 @@ public class ShardTransactionTest extends AbstractActorTest { subject.tell(new DeleteData(TestModel.TEST_PATH).toSerializable(), getRef()); - final String out = new ExpectMsg("match hint") { + final String out = new ExpectMsg(duration("1 seconds"), "match hint") { // do not put code outside this method, will run afterwards protected String match(Object in) { if (in.getClass().equals(DeleteDataReply.SERIALIZABLE_CLASS)) { @@ -281,7 +283,7 @@ public class ShardTransactionTest extends AbstractActorTest { new JavaTestKit(getSystem()) {{ final ActorRef shard = getSystem().actorOf(Shard.props("config", Collections.EMPTY_MAP)); final Props props = - ShardTransaction.props(store.newReadWriteTransaction(), shard, TestModel.createTestContext()); + ShardTransaction.props( store.newReadWriteTransaction(), shard, TestModel.createTestContext()); final ActorRef subject = getSystem().actorOf(props, "testReadyTransaction"); @@ -290,7 +292,7 @@ public class ShardTransactionTest extends AbstractActorTest { subject.tell(new ReadyTransaction().toSerializable(), getRef()); - final String out = new ExpectMsg("match hint") { + final String out = new ExpectMsg(duration("1 seconds"), "match hint") { // do not put code outside this method, will run afterwards protected String match(Object in) { if (in.getClass().equals(ReadyTransactionReply.SERIALIZABLE_CLASS)) { @@ -328,7 +330,7 @@ public class ShardTransactionTest extends AbstractActorTest { subject.tell(new CloseTransaction().toSerializable(), getRef()); - final String out = new ExpectMsg("match hint") { + final String out = new ExpectMsg(duration("1 seconds"), "match hint") { // do not put code outside this method, will run afterwards protected String match(Object in) { if (in.getClass().equals(CloseTransactionReply.SERIALIZABLE_CLASS)) { @@ -341,7 +343,7 @@ public class ShardTransactionTest extends AbstractActorTest { assertEquals("match", out); - final String termination = new ExpectMsg("match hint") { + final String termination = new ExpectMsg(duration("1 seconds"), "match hint") { // do not put code outside this method, will run afterwards protected String match(Object in) { if (in instanceof Terminated) { @@ -361,4 +363,24 @@ public class ShardTransactionTest extends AbstractActorTest { }}; } + + + @Test + public void testNegativePerformingWriteOperationOnReadTransaction() throws Exception { + try { + + final ActorRef shard = getSystem().actorOf(Shard.props("config", Collections.EMPTY_MAP)); + final Props props = + ShardTransaction.props(store.newReadOnlyTransaction(), shard, TestModel.createTestContext()); + final TestActorRef subject = TestActorRef.apply(props,getSystem()); + + subject.receive(new DeleteData(TestModel.TEST_PATH).toSerializable(), ActorRef.noSender()); + Assert.assertFalse(true); + + + } catch (Exception cs) { + assertEquals(cs.getClass().getSimpleName(), Exception.class.getSimpleName()); + assertTrue(cs.getMessage().startsWith("ShardTransaction:handleRecieve received an unknown message")); + } + } } diff --git a/opendaylight/md-sal/sal-distributed-datastore/src/test/java/org/opendaylight/controller/cluster/datastore/ThreePhaseCommitCohortProxyTest.java b/opendaylight/md-sal/sal-distributed-datastore/src/test/java/org/opendaylight/controller/cluster/datastore/ThreePhaseCommitCohortProxyTest.java index 992518e100..4eca5671f6 100644 --- a/opendaylight/md-sal/sal-distributed-datastore/src/test/java/org/opendaylight/controller/cluster/datastore/ThreePhaseCommitCohortProxyTest.java +++ b/opendaylight/md-sal/sal-distributed-datastore/src/test/java/org/opendaylight/controller/cluster/datastore/ThreePhaseCommitCohortProxyTest.java @@ -2,8 +2,14 @@ package org.opendaylight.controller.cluster.datastore; import akka.actor.ActorRef; import akka.actor.Props; + import com.google.common.util.concurrent.ListenableFuture; +import com.google.common.util.concurrent.ListeningExecutorService; +import com.google.common.util.concurrent.MoreExecutors; + import junit.framework.Assert; + +import org.junit.After; import org.junit.Before; import org.junit.Test; import org.opendaylight.controller.cluster.datastore.messages.AbortTransactionReply; @@ -14,7 +20,6 @@ import org.opendaylight.controller.cluster.datastore.utils.MessageCollectorActor import org.opendaylight.controller.cluster.datastore.utils.MockActorContext; import java.util.Arrays; -import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; import static org.junit.Assert.assertNotNull; @@ -25,7 +30,8 @@ public class ThreePhaseCommitCohortProxyTest extends AbstractActorTest { private Props props; private ActorRef actorRef; private MockActorContext actorContext; - private ExecutorService executor = Executors.newSingleThreadExecutor(); + private final ListeningExecutorService executor = MoreExecutors.listeningDecorator( + Executors.newSingleThreadExecutor()); @Before public void setUp(){ @@ -39,6 +45,11 @@ public class ThreePhaseCommitCohortProxyTest extends AbstractActorTest { } + @After + public void tearDown() { + executor.shutdownNow(); + } + @Test public void testCanCommit() throws Exception { actorContext.setExecuteRemoteOperationResponse(new CanCommitTransactionReply(true).toSerializable()); diff --git a/opendaylight/md-sal/sal-distributed-datastore/src/test/java/org/opendaylight/controller/cluster/datastore/TransactionProxyTest.java b/opendaylight/md-sal/sal-distributed-datastore/src/test/java/org/opendaylight/controller/cluster/datastore/TransactionProxyTest.java index f654e3aced..0cd029c2ff 100644 --- a/opendaylight/md-sal/sal-distributed-datastore/src/test/java/org/opendaylight/controller/cluster/datastore/TransactionProxyTest.java +++ b/opendaylight/md-sal/sal-distributed-datastore/src/test/java/org/opendaylight/controller/cluster/datastore/TransactionProxyTest.java @@ -2,11 +2,19 @@ package org.opendaylight.controller.cluster.datastore; import akka.actor.ActorRef; import akka.actor.Props; + import com.google.common.base.Optional; import com.google.common.util.concurrent.ListenableFuture; +import com.google.common.util.concurrent.ListeningExecutorService; +import com.google.common.util.concurrent.MoreExecutors; + import junit.framework.Assert; + +import org.junit.After; import org.junit.Before; import org.junit.Test; +import org.opendaylight.controller.cluster.datastore.exceptions.PrimaryNotFoundException; +import org.opendaylight.controller.cluster.datastore.exceptions.TimeoutException; import org.opendaylight.controller.cluster.datastore.messages.CloseTransaction; import org.opendaylight.controller.cluster.datastore.messages.DeleteData; import org.opendaylight.controller.cluster.datastore.messages.MergeData; @@ -26,11 +34,17 @@ import org.opendaylight.controller.protobuff.messages.transaction.ShardTransacti import org.opendaylight.controller.sal.core.spi.data.DOMStoreThreePhaseCommitCohort; import org.opendaylight.yangtools.yang.data.api.schema.NormalizedNode; import org.opendaylight.yangtools.yang.data.impl.schema.ImmutableNodes; +import scala.concurrent.duration.FiniteDuration; import java.util.List; -import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; +import static junit.framework.Assert.fail; +import static org.mockito.Matchers.any; +import static org.mockito.Matchers.anyString; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.when; + public class TransactionProxyTest extends AbstractActorTest { private final Configuration configuration = new MockConfiguration(); @@ -38,14 +52,19 @@ public class TransactionProxyTest extends AbstractActorTest { private final ActorContext testContext = new ActorContext(getSystem(), getSystem().actorOf(Props.create(DoNothingActor.class)), new MockClusterWrapper(), configuration ); - private ExecutorService transactionExecutor = - Executors.newSingleThreadExecutor(); + private final ListeningExecutorService transactionExecutor = + MoreExecutors.listeningDecorator(Executors.newSingleThreadExecutor()); @Before public void setUp(){ ShardStrategyFactory.setConfiguration(configuration); } + @After + public void tearDown() { + transactionExecutor.shutdownNow(); + } + @Test public void testRead() throws Exception { final Props props = Props.create(DoNothingActor.class); @@ -111,6 +130,68 @@ public class TransactionProxyTest extends AbstractActorTest { Assert.assertFalse(normalizedNodeOptional.isPresent()); } + @Test + public void testReadWhenAPrimaryNotFoundExceptionIsThrown() throws Exception { + final ActorContext actorContext = mock(ActorContext.class); + + when(actorContext.executeShardOperation(anyString(), any(), any( + FiniteDuration.class))).thenThrow(new PrimaryNotFoundException("test")); + + TransactionProxy transactionProxy = + new TransactionProxy(actorContext, + TransactionProxy.TransactionType.READ_ONLY, transactionExecutor, TestModel.createTestContext()); + + + ListenableFuture>> read = + transactionProxy.read(TestModel.TEST_PATH); + + Assert.assertFalse(read.get().isPresent()); + + } + + + @Test + public void testReadWhenATimeoutExceptionIsThrown() throws Exception { + final ActorContext actorContext = mock(ActorContext.class); + + when(actorContext.executeShardOperation(anyString(), any(), any( + FiniteDuration.class))).thenThrow(new TimeoutException("test", new Exception("reason"))); + + TransactionProxy transactionProxy = + new TransactionProxy(actorContext, + TransactionProxy.TransactionType.READ_ONLY, transactionExecutor, TestModel.createTestContext()); + + + ListenableFuture>> read = + transactionProxy.read(TestModel.TEST_PATH); + + Assert.assertFalse(read.get().isPresent()); + + } + + @Test + public void testReadWhenAAnyOtherExceptionIsThrown() throws Exception { + final ActorContext actorContext = mock(ActorContext.class); + + when(actorContext.executeShardOperation(anyString(), any(), any( + FiniteDuration.class))).thenThrow(new NullPointerException()); + + TransactionProxy transactionProxy = + new TransactionProxy(actorContext, + TransactionProxy.TransactionType.READ_ONLY, transactionExecutor, TestModel.createTestContext()); + + + try { + ListenableFuture>> read = + transactionProxy.read(TestModel.TEST_PATH); + fail("A null pointer exception was expected"); + } catch(NullPointerException e){ + + } + } + + + @Test public void testWrite() throws Exception { final Props props = Props.create(MessageCollectorActor.class); diff --git a/opendaylight/md-sal/sal-distributed-datastore/src/test/java/org/opendaylight/controller/cluster/datastore/shardstrategy/ModuleShardStrategyTest.java b/opendaylight/md-sal/sal-distributed-datastore/src/test/java/org/opendaylight/controller/cluster/datastore/shardstrategy/ModuleShardStrategyTest.java index 88753e4b0a..3394cdc959 100644 --- a/opendaylight/md-sal/sal-distributed-datastore/src/test/java/org/opendaylight/controller/cluster/datastore/shardstrategy/ModuleShardStrategyTest.java +++ b/opendaylight/md-sal/sal-distributed-datastore/src/test/java/org/opendaylight/controller/cluster/datastore/shardstrategy/ModuleShardStrategyTest.java @@ -1,6 +1,5 @@ package org.opendaylight.controller.cluster.datastore.shardstrategy; -import junit.framework.Assert; import org.junit.BeforeClass; import org.junit.Rule; import org.junit.Test; @@ -8,6 +7,10 @@ import org.junit.rules.ExpectedException; import org.opendaylight.controller.cluster.datastore.Configuration; import org.opendaylight.controller.cluster.datastore.ConfigurationImpl; import org.opendaylight.controller.md.cluster.datastore.model.CarsModel; +import org.opendaylight.yangtools.yang.common.QName; +import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier; + +import static junit.framework.Assert.assertEquals; public class ModuleShardStrategyTest { @Rule @@ -28,6 +31,23 @@ public class ModuleShardStrategyTest { String shard = moduleShardStrategy.findShard(CarsModel.BASE_PATH); - Assert.assertEquals("cars-1", shard); + assertEquals("cars-1", shard); + } + + @Test + public void testFindShardWhenModuleConfigurationPresentInModulesButMissingInModuleShards() { + + final QName BASE_QNAME = QName.create("urn:opendaylight:params:xml:ns:yang:controller:md:sal:dom:store:test:missing", "2014-03-13", + "missing"); + + final YangInstanceIdentifier BASE_PATH = YangInstanceIdentifier.of(BASE_QNAME); + + ModuleShardStrategy moduleShardStrategy = + new ModuleShardStrategy("missing", configuration); + + String shard = moduleShardStrategy.findShard(BASE_PATH); + + assertEquals(DefaultShardStrategy.DEFAULT_SHARD, shard); + } } diff --git a/opendaylight/md-sal/sal-distributed-datastore/src/test/java/org/opendaylight/controller/cluster/datastore/utils/ActorContextTest.java b/opendaylight/md-sal/sal-distributed-datastore/src/test/java/org/opendaylight/controller/cluster/datastore/utils/ActorContextTest.java index 3dd0214e9b..5874eccda4 100644 --- a/opendaylight/md-sal/sal-distributed-datastore/src/test/java/org/opendaylight/controller/cluster/datastore/utils/ActorContextTest.java +++ b/opendaylight/md-sal/sal-distributed-datastore/src/test/java/org/opendaylight/controller/cluster/datastore/utils/ActorContextTest.java @@ -2,12 +2,20 @@ package org.opendaylight.controller.cluster.datastore.utils; import akka.actor.ActorRef; import akka.actor.ActorSystem; +import akka.actor.Props; +import akka.actor.UntypedActor; +import akka.japi.Creator; +import akka.testkit.JavaTestKit; import org.junit.Test; import org.opendaylight.controller.cluster.datastore.AbstractActorTest; import org.opendaylight.controller.cluster.datastore.ClusterWrapper; import org.opendaylight.controller.cluster.datastore.Configuration; +import org.opendaylight.controller.cluster.datastore.messages.FindLocalShard; +import org.opendaylight.controller.cluster.datastore.messages.LocalShardFound; +import org.opendaylight.controller.cluster.datastore.messages.LocalShardNotFound; import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertNull; import static org.mockito.Mockito.mock; public class ActorContextTest extends AbstractActorTest{ @@ -44,4 +52,145 @@ public class ActorContextTest extends AbstractActorTest{ System.out.println(actorContext .actorFor("akka://system/user/shardmanager/shard/transaction")); } + + + private static class MockShardManager extends UntypedActor { + + private final boolean found; + private final ActorRef actorRef; + + private MockShardManager(boolean found, ActorRef actorRef){ + + this.found = found; + this.actorRef = actorRef; + } + + @Override public void onReceive(Object message) throws Exception { + if(found){ + getSender().tell(new LocalShardFound(actorRef), getSelf()); + } else { + getSender().tell(new LocalShardNotFound(((FindLocalShard) message).getShardName()), getSelf()); + } + } + + private static Props props(final boolean found, final ActorRef actorRef){ + return Props.create(new Creator() { + + @Override public MockShardManager create() + throws Exception { + return new MockShardManager(found, + actorRef); + } + }); + } + } + + @Test + public void testExecuteLocalShardOperationWithShardFound(){ + new JavaTestKit(getSystem()) {{ + + new Within(duration("1 seconds")) { + protected void run() { + + ActorRef shardActorRef = getSystem().actorOf(Props.create(EchoActor.class)); + + ActorRef shardManagerActorRef = getSystem() + .actorOf(MockShardManager.props(true, shardActorRef)); + + ActorContext actorContext = + new ActorContext(getSystem(), shardManagerActorRef , mock(ClusterWrapper.class), + mock(Configuration.class)); + + Object out = actorContext.executeLocalShardOperation("default", "hello", duration("1 seconds")); + + assertEquals("hello", out); + + + expectNoMsg(); + } + }; + }}; + + } + + @Test + public void testExecuteLocalShardOperationWithShardNotFound(){ + new JavaTestKit(getSystem()) {{ + + new Within(duration("1 seconds")) { + protected void run() { + + ActorRef shardManagerActorRef = getSystem() + .actorOf(MockShardManager.props(false, null)); + + ActorContext actorContext = + new ActorContext(getSystem(), shardManagerActorRef , mock(ClusterWrapper.class), + mock(Configuration.class)); + + Object out = actorContext.executeLocalShardOperation("default", "hello", duration("1 seconds")); + + assertNull(out); + + + expectNoMsg(); + } + }; + }}; + + } + + + @Test + public void testFindLocalShardWithShardFound(){ + new JavaTestKit(getSystem()) {{ + + new Within(duration("1 seconds")) { + protected void run() { + + ActorRef shardActorRef = getSystem().actorOf(Props.create(EchoActor.class)); + + ActorRef shardManagerActorRef = getSystem() + .actorOf(MockShardManager.props(true, shardActorRef)); + + ActorContext actorContext = + new ActorContext(getSystem(), shardManagerActorRef , mock(ClusterWrapper.class), + mock(Configuration.class)); + + Object out = actorContext.findLocalShard("default"); + + assertEquals(shardActorRef, out); + + + expectNoMsg(); + } + }; + }}; + + } + + @Test + public void testFindLocalShardWithShardNotFound(){ + new JavaTestKit(getSystem()) {{ + + new Within(duration("1 seconds")) { + protected void run() { + + ActorRef shardManagerActorRef = getSystem() + .actorOf(MockShardManager.props(false, null)); + + ActorContext actorContext = + new ActorContext(getSystem(), shardManagerActorRef , mock(ClusterWrapper.class), + mock(Configuration.class)); + + Object out = actorContext.findLocalShard("default"); + + assertNull(out); + + + expectNoMsg(); + } + }; + }}; + + } } diff --git a/opendaylight/md-sal/sal-distributed-datastore/src/test/java/org/opendaylight/controller/cluster/datastore/utils/EchoActor.java b/opendaylight/md-sal/sal-distributed-datastore/src/test/java/org/opendaylight/controller/cluster/datastore/utils/EchoActor.java new file mode 100644 index 0000000000..fe88afe1db --- /dev/null +++ b/opendaylight/md-sal/sal-distributed-datastore/src/test/java/org/opendaylight/controller/cluster/datastore/utils/EchoActor.java @@ -0,0 +1,21 @@ +/* + * 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.cluster.datastore.utils; + +import akka.actor.UntypedActor; + +/** + * The EchoActor simply responds back with the same message that it receives + */ +public class EchoActor extends UntypedActor{ + + @Override public void onReceive(Object message) throws Exception { + getSender().tell(message, getSelf()); + } +} diff --git a/opendaylight/md-sal/sal-distributed-datastore/src/test/java/org/opendaylight/controller/cluster/datastore/utils/MockActorContext.java b/opendaylight/md-sal/sal-distributed-datastore/src/test/java/org/opendaylight/controller/cluster/datastore/utils/MockActorContext.java index 1d1e661488..5d3853f311 100644 --- a/opendaylight/md-sal/sal-distributed-datastore/src/test/java/org/opendaylight/controller/cluster/datastore/utils/MockActorContext.java +++ b/opendaylight/md-sal/sal-distributed-datastore/src/test/java/org/opendaylight/controller/cluster/datastore/utils/MockActorContext.java @@ -19,6 +19,7 @@ public class MockActorContext extends ActorContext { private Object executeShardOperationResponse; private Object executeRemoteOperationResponse; private Object executeLocalOperationResponse; + private Object executeLocalShardOperationResponse; public MockActorContext(ActorSystem actorSystem) { super(actorSystem, null, new MockClusterWrapper(), new MockConfiguration()); @@ -56,8 +57,18 @@ public class MockActorContext extends ActorContext { this.executeLocalOperationResponse = executeLocalOperationResponse; } + public void setExecuteLocalShardOperationResponse( + Object executeLocalShardOperationResponse) { + this.executeLocalShardOperationResponse = executeLocalShardOperationResponse; + } + @Override public Object executeLocalOperation(ActorRef actor, Object message, FiniteDuration duration) { return this.executeLocalOperationResponse; } + + @Override public Object executeLocalShardOperation(String shardName, + Object message, FiniteDuration duration) { + return this.executeLocalShardOperationResponse; + } } diff --git a/opendaylight/md-sal/sal-distributed-datastore/src/test/java/org/opendaylight/controller/md/cluster/datastore/model/CarsModel.java b/opendaylight/md-sal/sal-distributed-datastore/src/test/java/org/opendaylight/controller/md/cluster/datastore/model/CarsModel.java index 57df20172d..6860872b75 100644 --- a/opendaylight/md-sal/sal-distributed-datastore/src/test/java/org/opendaylight/controller/md/cluster/datastore/model/CarsModel.java +++ b/opendaylight/md-sal/sal-distributed-datastore/src/test/java/org/opendaylight/controller/md/cluster/datastore/model/CarsModel.java @@ -8,6 +8,7 @@ package org.opendaylight.controller.md.cluster.datastore.model; +import java.math.BigInteger; import org.opendaylight.yangtools.yang.common.QName; import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier; import org.opendaylight.yangtools.yang.data.api.schema.MapEntryNode; @@ -42,14 +43,14 @@ public class CarsModel { MapEntryNode altima = ImmutableNodes.mapEntryBuilder(CAR_QNAME, CAR_NAME_QNAME, "altima") .withChild(ImmutableNodes.leafNode(CAR_NAME_QNAME, "altima")) - .withChild(ImmutableNodes.leafNode(CAR_PRICE_QNAME, 1000)) + .withChild(ImmutableNodes.leafNode(CAR_PRICE_QNAME, new BigInteger("1000"))) .build(); // Create an entry for the car accord MapEntryNode honda = ImmutableNodes.mapEntryBuilder(CAR_QNAME, CAR_NAME_QNAME, "accord") .withChild(ImmutableNodes.leafNode(CAR_NAME_QNAME, "accord")) - .withChild(ImmutableNodes.leafNode(CAR_PRICE_QNAME, 2000)) + .withChild(ImmutableNodes.leafNode(CAR_PRICE_QNAME, new BigInteger("2000"))) .build(); cars.withChild(altima); diff --git a/opendaylight/md-sal/sal-distributed-datastore/src/test/java/org/opendaylight/controller/md/cluster/datastore/model/PeopleModel.java b/opendaylight/md-sal/sal-distributed-datastore/src/test/java/org/opendaylight/controller/md/cluster/datastore/model/PeopleModel.java index 1b4020af43..e637920e78 100644 --- a/opendaylight/md-sal/sal-distributed-datastore/src/test/java/org/opendaylight/controller/md/cluster/datastore/model/PeopleModel.java +++ b/opendaylight/md-sal/sal-distributed-datastore/src/test/java/org/opendaylight/controller/md/cluster/datastore/model/PeopleModel.java @@ -42,14 +42,14 @@ public class PeopleModel { MapEntryNode jack = ImmutableNodes.mapEntryBuilder(PERSON_QNAME, PERSON_NAME_QNAME, "jack") .withChild(ImmutableNodes.leafNode(PERSON_NAME_QNAME, "jack")) - .withChild(ImmutableNodes.leafNode(PERSON_AGE_QNAME, 100)) + .withChild(ImmutableNodes.leafNode(PERSON_AGE_QNAME, 100L)) .build(); // Create an entry for the person jill MapEntryNode jill = ImmutableNodes.mapEntryBuilder(PERSON_QNAME, PERSON_NAME_QNAME, "jill") .withChild(ImmutableNodes.leafNode(PERSON_NAME_QNAME, "jill")) - .withChild(ImmutableNodes.leafNode(PERSON_AGE_QNAME, 200)) + .withChild(ImmutableNodes.leafNode(PERSON_AGE_QNAME, 200L)) .build(); cars.withChild(jack); diff --git a/opendaylight/md-sal/sal-distributed-datastore/src/test/java/org/opendaylight/controller/md/cluster/datastore/model/SampleModelsTest.java b/opendaylight/md-sal/sal-distributed-datastore/src/test/java/org/opendaylight/controller/md/cluster/datastore/model/SampleModelsTest.java index d8fefcd986..be8713c702 100644 --- a/opendaylight/md-sal/sal-distributed-datastore/src/test/java/org/opendaylight/controller/md/cluster/datastore/model/SampleModelsTest.java +++ b/opendaylight/md-sal/sal-distributed-datastore/src/test/java/org/opendaylight/controller/md/cluster/datastore/model/SampleModelsTest.java @@ -18,45 +18,45 @@ import org.opendaylight.yangtools.yang.data.api.schema.NormalizedNode; public class SampleModelsTest { @Test public void testPeopleModel(){ - NormalizedNode expected = PeopleModel.create(); + final NormalizedNode expected = PeopleModel.create(); - NormalizedNodeMessages.Container node = + final NormalizedNodeMessages.Container node = new NormalizedNodeToNodeCodec(SchemaContextHelper.full()) .encode(YangInstanceIdentifier.of(PeopleModel.BASE_QNAME), expected); - NormalizedNodeMessages.Node normalizedNode = + final NormalizedNodeMessages.Node normalizedNode = node.getNormalizedNode(); - NormalizedNode actual = new NormalizedNodeToNodeCodec(SchemaContextHelper.full()).decode(YangInstanceIdentifier.of(PeopleModel.BASE_QNAME), + final NormalizedNode actual = new NormalizedNodeToNodeCodec(SchemaContextHelper.full()).decode(YangInstanceIdentifier.of(PeopleModel.BASE_QNAME), normalizedNode); - Assert.assertEquals(expected.toString(), actual.toString()); + Assert.assertEquals(expected, actual); } @Test public void testCarsModel(){ - NormalizedNode expected = CarsModel.create(); + final NormalizedNode expected = CarsModel.create(); - NormalizedNodeMessages.Container node = + final NormalizedNodeMessages.Container node = new NormalizedNodeToNodeCodec(SchemaContextHelper.full()) .encode(YangInstanceIdentifier.of(CarsModel.BASE_QNAME), expected); - NormalizedNodeMessages.Node normalizedNode = + final NormalizedNodeMessages.Node normalizedNode = node.getNormalizedNode(); - NormalizedNode actual = new NormalizedNodeToNodeCodec(SchemaContextHelper.full()).decode( + final NormalizedNode actual = new NormalizedNodeToNodeCodec(SchemaContextHelper.full()).decode( YangInstanceIdentifier.of(CarsModel.BASE_QNAME), normalizedNode); - Assert.assertEquals(expected.toString(), actual.toString()); + Assert.assertEquals(expected, actual); } } diff --git a/opendaylight/md-sal/sal-distributed-datastore/src/test/java/org/opendaylight/controller/programs/appendentries/Client.java b/opendaylight/md-sal/sal-distributed-datastore/src/test/java/org/opendaylight/controller/programs/appendentries/Client.java new file mode 100644 index 0000000000..2671be80bb --- /dev/null +++ b/opendaylight/md-sal/sal-distributed-datastore/src/test/java/org/opendaylight/controller/programs/appendentries/Client.java @@ -0,0 +1,120 @@ +/* + * 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.programs.appendentries; + +import akka.actor.ActorSelection; +import akka.actor.ActorSystem; +import akka.actor.Props; +import akka.actor.UntypedActor; +import com.typesafe.config.ConfigFactory; +import org.opendaylight.controller.cluster.datastore.CompositeModificationPayload; +import org.opendaylight.controller.cluster.datastore.modification.MutableCompositeModification; +import org.opendaylight.controller.cluster.datastore.modification.WriteModification; +import org.opendaylight.controller.cluster.example.messages.KeyValue; +import org.opendaylight.controller.cluster.raft.ReplicatedLogEntry; +import org.opendaylight.controller.cluster.raft.messages.AppendEntries; +import org.opendaylight.controller.cluster.raft.protobuff.client.messages.Payload; +import org.opendaylight.controller.md.cluster.datastore.model.TestModel; +import org.opendaylight.yangtools.yang.data.impl.schema.ImmutableNodes; + +import java.util.ArrayList; +import java.util.List; + +public class Client { + + private static ActorSystem actorSystem; + + public static class ClientActor extends UntypedActor { + + @Override public void onReceive(Object message) throws Exception { + + } + } + + public static void main(String[] args){ + actorSystem = ActorSystem.create("appendentries", ConfigFactory + .load().getConfig("ODLCluster")); + + ActorSelection actorSelection = actorSystem.actorSelection( + "akka.tcp://appendentries@127.0.0.1:2550/user/server"); + + AppendEntries appendEntries = modificationAppendEntries(); + + Payload data = appendEntries.getEntries().get(0).getData(); + if(data instanceof CompositeModificationPayload) { + System.out.println( + "Sending : " + ((CompositeModificationPayload) data) + .getModification()); + } else { + System.out.println( + "Sending : " + ((KeyValue) data) + .getKey()); + + } + + actorSelection.tell(appendEntries.toSerializable(), null); + + + + + actorSystem.actorOf(Props.create(ClientActor.class), "client"); + } + + public static AppendEntries modificationAppendEntries() { + List modification = new ArrayList<>(); + + modification.add(0, new ReplicatedLogEntry() { + @Override public Payload getData() { + WriteModification writeModification = + new WriteModification(TestModel.TEST_PATH, ImmutableNodes + .containerNode(TestModel.TEST_QNAME), + TestModel.createTestContext() + ); + + MutableCompositeModification compositeModification = + new MutableCompositeModification(); + + compositeModification.addModification(writeModification); + + return new CompositeModificationPayload( + compositeModification.toSerializable()); + } + + @Override public long getTerm() { + return 1; + } + + @Override public long getIndex() { + return 1; + } + }); + + return new AppendEntries(1, "member-1", 0, 100, modification, 1); + } + + public static AppendEntries keyValueAppendEntries() { + List modification = new ArrayList<>(); + + modification.add(0, new ReplicatedLogEntry() { + @Override public Payload getData() { + return new KeyValue("moiz", "test"); + } + + @Override public long getTerm() { + return 1; + } + + @Override public long getIndex() { + return 1; + } + }); + + return new AppendEntries(1, "member-1", 0, 100, modification, 1); + } +} diff --git a/opendaylight/md-sal/sal-distributed-datastore/src/test/java/org/opendaylight/controller/programs/appendentries/Server.java b/opendaylight/md-sal/sal-distributed-datastore/src/test/java/org/opendaylight/controller/programs/appendentries/Server.java new file mode 100644 index 0000000000..0e6d535301 --- /dev/null +++ b/opendaylight/md-sal/sal-distributed-datastore/src/test/java/org/opendaylight/controller/programs/appendentries/Server.java @@ -0,0 +1,53 @@ +/* + * 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.programs.appendentries; + +import akka.actor.ActorSystem; +import akka.actor.Props; +import akka.actor.UntypedActor; +import com.typesafe.config.ConfigFactory; +import org.opendaylight.controller.cluster.datastore.CompositeModificationPayload; +import org.opendaylight.controller.cluster.example.messages.KeyValue; +import org.opendaylight.controller.cluster.raft.messages.AppendEntries; +import org.opendaylight.controller.cluster.raft.protobuff.client.messages.Payload; + +public class Server { + + private static ActorSystem actorSystem; + + public static class ServerActor extends UntypedActor { + + @Override public void onReceive(Object message) throws Exception { + if(AppendEntries.SERIALIZABLE_CLASS.equals(message.getClass())){ + AppendEntries appendEntries = + AppendEntries.fromSerializable(message); + + Payload data = appendEntries.getEntries() + .get(0).getData(); + if(data instanceof KeyValue){ + System.out.println("Received : " + ((KeyValue) appendEntries.getEntries().get(0).getData()).getKey()); + } else { + System.out.println("Received :" + + ((CompositeModificationPayload) appendEntries + .getEntries() + .get(0).getData()).getModification().toString()); + } + } else if(message instanceof String){ + System.out.println(message); + } + } + } + + public static void main(String[] args){ + actorSystem = ActorSystem.create("appendentries", ConfigFactory + .load().getConfig("ODLCluster")); + + actorSystem.actorOf(Props.create(ServerActor.class), "server"); + } +} diff --git a/opendaylight/md-sal/sal-distributed-datastore/src/test/resources/application.conf b/opendaylight/md-sal/sal-distributed-datastore/src/test/resources/application.conf index aebff27c7d..eda1c304e4 100644 --- a/opendaylight/md-sal/sal-distributed-datastore/src/test/resources/application.conf +++ b/opendaylight/md-sal/sal-distributed-datastore/src/test/resources/application.conf @@ -1,4 +1,5 @@ akka { + loggers = [akka.testkit.TestEventListener] actor { serializers { java = "akka.serialization.JavaSerializer" diff --git a/opendaylight/md-sal/sal-distributed-datastore/src/test/resources/modules.conf b/opendaylight/md-sal/sal-distributed-datastore/src/test/resources/modules.conf index 22854cb11a..f4919e7895 100644 --- a/opendaylight/md-sal/sal-distributed-datastore/src/test/resources/modules.conf +++ b/opendaylight/md-sal/sal-distributed-datastore/src/test/resources/modules.conf @@ -15,4 +15,10 @@ modules = [ shard-strategy = "module" } + { + name = "missing" + namespace = "urn:opendaylight:params:xml:ns:yang:controller:md:sal:dom:store:missing" + shard-strategy = "module" + } + ] diff --git a/opendaylight/md-sal/sal-dom-api/src/main/java/org/opendaylight/controller/md/sal/dom/api/DOMDataReadTransaction.java b/opendaylight/md-sal/sal-dom-api/src/main/java/org/opendaylight/controller/md/sal/dom/api/DOMDataReadTransaction.java index afa2286d53..fc251c8445 100644 --- a/opendaylight/md-sal/sal-dom-api/src/main/java/org/opendaylight/controller/md/sal/dom/api/DOMDataReadTransaction.java +++ b/opendaylight/md-sal/sal-dom-api/src/main/java/org/opendaylight/controller/md/sal/dom/api/DOMDataReadTransaction.java @@ -9,11 +9,12 @@ package org.opendaylight.controller.md.sal.dom.api; import org.opendaylight.controller.md.sal.common.api.data.AsyncReadTransaction; import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType; +import org.opendaylight.controller.md.sal.common.api.data.ReadFailedException; import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier; import org.opendaylight.yangtools.yang.data.api.schema.NormalizedNode; import com.google.common.base.Optional; -import com.google.common.util.concurrent.ListenableFuture; +import com.google.common.util.concurrent.CheckedFuture; /** * A transaction that provides read access to a logical data store. @@ -33,14 +34,17 @@ public interface DOMDataReadTransaction extends AsyncReadTransaction - *
      • If data at supplied path exists the - * {@link ListeblaFuture#get()} returns Optional object containing - * data once read is done. - *
      • If data at supplied path does not exists the - * {@link ListenbleFuture#get()} returns {@link Optional#absent()}. + *
      • If the data at the supplied path exists, the Future returns an Optional object + * containing the data.
      • + *
      • If the data at the supplied path does not exist, the Future returns + * Optional#absent().
      • + *
      • If the read of the data fails, the Future will fail with a + * {@link ReadFailedException} or an exception derived from ReadFailedException.
      • *
      */ - ListenableFuture>> read(LogicalDatastoreType store,YangInstanceIdentifier path); + CheckedFuture>, ReadFailedException> read( + LogicalDatastoreType store, YangInstanceIdentifier path); } diff --git a/opendaylight/md-sal/sal-dom-api/src/main/java/org/opendaylight/controller/sal/core/api/model/SchemaService.java b/opendaylight/md-sal/sal-dom-api/src/main/java/org/opendaylight/controller/sal/core/api/model/SchemaService.java index 34e5b1b803..c3e979c536 100644 --- a/opendaylight/md-sal/sal-dom-api/src/main/java/org/opendaylight/controller/sal/core/api/model/SchemaService.java +++ b/opendaylight/md-sal/sal-dom-api/src/main/java/org/opendaylight/controller/sal/core/api/model/SchemaService.java @@ -11,7 +11,7 @@ import org.opendaylight.controller.sal.core.api.BrokerService; import org.opendaylight.yangtools.concepts.ListenerRegistration; import org.opendaylight.yangtools.yang.model.api.Module; import org.opendaylight.yangtools.yang.model.api.SchemaContext; -import org.opendaylight.yangtools.yang.model.api.SchemaServiceListener; +import org.opendaylight.yangtools.yang.model.api.SchemaContextListener; public interface SchemaService extends BrokerService { @@ -42,5 +42,11 @@ public interface SchemaService extends BrokerService { */ SchemaContext getGlobalContext(); - ListenerRegistration registerSchemaServiceListener(SchemaServiceListener listener); + /** + * Register a listener for changes in schema context. + * + * @param listener Listener which should be registered + * @return Listener registration handle + */ + ListenerRegistration registerSchemaContextListener(SchemaContextListener listener); } 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 17b78f4ebd..f1f16cd635 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 @@ -91,7 +91,7 @@ public final class DomBrokerImplModule extends org.opendaylight.controller.confi wrappedStore.changeDelegate(legacyStore); wrappedStore.setValidationEnabled(false); - schemaService.registerSchemaServiceListener(wrappedStore); + schemaService.registerSchemaContextListener(wrappedStore); dataService.registerConfigurationReader(rootPath, wrappedStore); dataService.registerCommitHandler(rootPath, wrappedStore); 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 index 69b17ee3c4..22dad6af23 100644 --- 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 @@ -10,9 +10,11 @@ package org.opendaylight.controller.config.yang.md.sal.dom.impl; import java.util.concurrent.Executors; import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType; +import org.opendaylight.controller.md.sal.common.api.data.TransactionCommitDeadlockException; 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.opendaylight.yangtools.util.concurrent.DeadlockDetectingListeningExecutorService; import com.google.common.collect.ImmutableMap; import com.google.common.util.concurrent.ListeningExecutorService; @@ -50,7 +52,7 @@ public final class DomInmemoryDataBrokerModule extends //we will default to InMemoryDOMDataStore creation operStore = new InMemoryDOMDataStore("DOM-OPER", storeExecutor); //here we will register the SchemaContext listener - getSchemaServiceDependency().registerSchemaServiceListener((InMemoryDOMDataStore)operStore); + getSchemaServiceDependency().registerSchemaContextListener((InMemoryDOMDataStore)operStore); } DOMStore configStore = getConfigDataStoreDependency(); @@ -58,13 +60,15 @@ public final class DomInmemoryDataBrokerModule extends //we will default to InMemoryDOMDataStore creation configStore = new InMemoryDOMDataStore("DOM-CFG", storeExecutor); //here we will register the SchemaContext listener - getSchemaServiceDependency().registerSchemaServiceListener((InMemoryDOMDataStore)configStore); + getSchemaServiceDependency().registerSchemaContextListener((InMemoryDOMDataStore)configStore); } ImmutableMap datastores = ImmutableMap . builder().put(LogicalDatastoreType.OPERATIONAL, operStore) .put(LogicalDatastoreType.CONFIGURATION, configStore).build(); - DOMDataBrokerImpl newDataBroker = new DOMDataBrokerImpl(datastores, MoreExecutors.listeningDecorator(Executors.newSingleThreadExecutor())); + DOMDataBrokerImpl newDataBroker = new DOMDataBrokerImpl(datastores, + new DeadlockDetectingListeningExecutorService(Executors.newSingleThreadExecutor(), + TransactionCommitDeadlockException.DEADLOCK_EXECUTOR_FUNCTION)); return newDataBroker; } diff --git a/opendaylight/md-sal/sal-dom-broker/src/main/java/org/opendaylight/controller/config/yang/md/sal/dom/impl/SchemaServiceImplSingletonModule.java b/opendaylight/md-sal/sal-dom-broker/src/main/java/org/opendaylight/controller/config/yang/md/sal/dom/impl/SchemaServiceImplSingletonModule.java index fbc418dc2a..62b026430a 100644 --- a/opendaylight/md-sal/sal-dom-broker/src/main/java/org/opendaylight/controller/config/yang/md/sal/dom/impl/SchemaServiceImplSingletonModule.java +++ b/opendaylight/md-sal/sal-dom-broker/src/main/java/org/opendaylight/controller/config/yang/md/sal/dom/impl/SchemaServiceImplSingletonModule.java @@ -13,7 +13,7 @@ import org.opendaylight.yangtools.concepts.Delegator; import org.opendaylight.yangtools.concepts.ListenerRegistration; import org.opendaylight.yangtools.yang.model.api.Module; import org.opendaylight.yangtools.yang.model.api.SchemaContext; -import org.opendaylight.yangtools.yang.model.api.SchemaServiceListener; +import org.opendaylight.yangtools.yang.model.api.SchemaContextListener; import org.osgi.framework.BundleContext; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -90,8 +90,8 @@ org.opendaylight.controller.config.yang.md.sal.dom.impl.AbstractSchemaServiceImp } @Override - public ListenerRegistration registerSchemaServiceListener(final SchemaServiceListener arg0) { - return delegate.registerSchemaServiceListener(arg0); + public ListenerRegistration registerSchemaContextListener(final SchemaContextListener arg0) { + return delegate.registerSchemaContextListener(arg0); } @Override diff --git a/opendaylight/md-sal/sal-dom-broker/src/main/java/org/opendaylight/controller/md/sal/dom/broker/impl/DOMDataCommitCoordinatorImpl.java b/opendaylight/md-sal/sal-dom-broker/src/main/java/org/opendaylight/controller/md/sal/dom/broker/impl/DOMDataCommitCoordinatorImpl.java index 8b9eb445fd..9a6d12fb18 100644 --- a/opendaylight/md-sal/sal-dom-broker/src/main/java/org/opendaylight/controller/md/sal/dom/broker/impl/DOMDataCommitCoordinatorImpl.java +++ b/opendaylight/md-sal/sal-dom-broker/src/main/java/org/opendaylight/controller/md/sal/dom/broker/impl/DOMDataCommitCoordinatorImpl.java @@ -15,6 +15,7 @@ import javax.annotation.concurrent.GuardedBy; import org.opendaylight.controller.md.sal.common.api.data.TransactionCommitFailedException; import org.opendaylight.controller.md.sal.dom.api.DOMDataWriteTransaction; import org.opendaylight.controller.sal.core.spi.data.DOMStoreThreePhaseCommitCohort; +import org.opendaylight.yangtools.util.concurrent.MappingCheckedFuture; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -91,7 +92,8 @@ public class DOMDataCommitCoordinatorImpl implements DOMDataCommitExecutor { Futures.addCallback(commitFuture, new DOMDataCommitErrorInvoker(transaction, listener.get())); } - return Futures.makeChecked(commitFuture, TransactionCommitFailedExceptionMapper.COMMIT_ERROR_MAPPER); + return MappingCheckedFuture.create(commitFuture, + TransactionCommitFailedExceptionMapper.COMMIT_ERROR_MAPPER); } /** @@ -285,7 +287,8 @@ public class DOMDataCommitCoordinatorImpl implements DOMDataCommitExecutor { */ @SuppressWarnings({ "unchecked", "rawtypes" }) ListenableFuture compositeResult = (ListenableFuture) Futures.allAsList(ops.build()); - return Futures.makeChecked(compositeResult, TransactionCommitFailedExceptionMapper.PRE_COMMIT_MAPPER); + return MappingCheckedFuture.create(compositeResult, + TransactionCommitFailedExceptionMapper.PRE_COMMIT_MAPPER); } /** @@ -316,7 +319,8 @@ public class DOMDataCommitCoordinatorImpl implements DOMDataCommitExecutor { */ @SuppressWarnings({ "unchecked", "rawtypes" }) ListenableFuture compositeResult = (ListenableFuture) Futures.allAsList(ops.build()); - return Futures.makeChecked(compositeResult, TransactionCommitFailedExceptionMapper.COMMIT_ERROR_MAPPER); + return MappingCheckedFuture.create(compositeResult, + TransactionCommitFailedExceptionMapper.COMMIT_ERROR_MAPPER); } /** @@ -342,8 +346,8 @@ public class DOMDataCommitCoordinatorImpl implements DOMDataCommitExecutor { } ListenableFuture> allCanCommits = Futures.allAsList(canCommitOperations.build()); ListenableFuture allSuccessFuture = Futures.transform(allCanCommits, AND_FUNCTION); - return Futures - .makeChecked(allSuccessFuture, TransactionCommitFailedExceptionMapper.CAN_COMMIT_ERROR_MAPPER); + return MappingCheckedFuture.create(allSuccessFuture, + TransactionCommitFailedExceptionMapper.CAN_COMMIT_ERROR_MAPPER); } diff --git a/opendaylight/md-sal/sal-dom-broker/src/main/java/org/opendaylight/controller/md/sal/dom/broker/impl/DOMForwardedReadOnlyTransaction.java b/opendaylight/md-sal/sal-dom-broker/src/main/java/org/opendaylight/controller/md/sal/dom/broker/impl/DOMForwardedReadOnlyTransaction.java index c8edcbc6e2..b4562cf2ec 100644 --- a/opendaylight/md-sal/sal-dom-broker/src/main/java/org/opendaylight/controller/md/sal/dom/broker/impl/DOMForwardedReadOnlyTransaction.java +++ b/opendaylight/md-sal/sal-dom-broker/src/main/java/org/opendaylight/controller/md/sal/dom/broker/impl/DOMForwardedReadOnlyTransaction.java @@ -8,6 +8,7 @@ package org.opendaylight.controller.md.sal.dom.broker.impl; import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType; +import org.opendaylight.controller.md.sal.common.api.data.ReadFailedException; import org.opendaylight.controller.md.sal.dom.api.DOMDataReadOnlyTransaction; import org.opendaylight.controller.sal.core.spi.data.DOMStoreReadTransaction; import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier; @@ -15,7 +16,7 @@ import org.opendaylight.yangtools.yang.data.api.schema.NormalizedNode; import com.google.common.base.Optional; import com.google.common.collect.ImmutableMap; -import com.google.common.util.concurrent.ListenableFuture; +import com.google.common.util.concurrent.CheckedFuture; /** * @@ -34,8 +35,8 @@ class DOMForwardedReadOnlyTransaction extends } @Override - public ListenableFuture>> read(final LogicalDatastoreType store, - final YangInstanceIdentifier path) { + public CheckedFuture>, ReadFailedException> read( + final LogicalDatastoreType store, final YangInstanceIdentifier path) { return getSubtransaction(store).read(path); } diff --git a/opendaylight/md-sal/sal-dom-broker/src/main/java/org/opendaylight/controller/md/sal/dom/broker/impl/DOMForwardedReadWriteTransaction.java b/opendaylight/md-sal/sal-dom-broker/src/main/java/org/opendaylight/controller/md/sal/dom/broker/impl/DOMForwardedReadWriteTransaction.java index e6521b2377..74a4c52e36 100644 --- a/opendaylight/md-sal/sal-dom-broker/src/main/java/org/opendaylight/controller/md/sal/dom/broker/impl/DOMForwardedReadWriteTransaction.java +++ b/opendaylight/md-sal/sal-dom-broker/src/main/java/org/opendaylight/controller/md/sal/dom/broker/impl/DOMForwardedReadWriteTransaction.java @@ -7,6 +7,7 @@ */package org.opendaylight.controller.md.sal.dom.broker.impl; import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType; +import org.opendaylight.controller.md.sal.common.api.data.ReadFailedException; import org.opendaylight.controller.md.sal.dom.api.DOMDataReadWriteTransaction; import org.opendaylight.controller.sal.core.spi.data.DOMStoreReadWriteTransaction; import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier; @@ -14,7 +15,7 @@ import org.opendaylight.yangtools.yang.data.api.schema.NormalizedNode; import com.google.common.base.Optional; import com.google.common.collect.ImmutableMap; -import com.google.common.util.concurrent.ListenableFuture; +import com.google.common.util.concurrent.CheckedFuture; /** * @@ -45,8 +46,8 @@ class DOMForwardedReadWriteTransaction extends DOMForwardedWriteTransaction>> read(final LogicalDatastoreType store, - final YangInstanceIdentifier path) { + public CheckedFuture>, ReadFailedException> read( + final LogicalDatastoreType store, final YangInstanceIdentifier path) { return getSubtransaction(store).read(path); } } \ No newline at end of file diff --git a/opendaylight/md-sal/sal-dom-broker/src/main/java/org/opendaylight/controller/md/sal/dom/broker/impl/TransactionCommitFailedExceptionMapper.java b/opendaylight/md-sal/sal-dom-broker/src/main/java/org/opendaylight/controller/md/sal/dom/broker/impl/TransactionCommitFailedExceptionMapper.java index 258b068929..799a8a09ed 100644 --- a/opendaylight/md-sal/sal-dom-broker/src/main/java/org/opendaylight/controller/md/sal/dom/broker/impl/TransactionCommitFailedExceptionMapper.java +++ b/opendaylight/md-sal/sal-dom-broker/src/main/java/org/opendaylight/controller/md/sal/dom/broker/impl/TransactionCommitFailedExceptionMapper.java @@ -7,29 +7,16 @@ */ package org.opendaylight.controller.md.sal.dom.broker.impl; -import java.util.concurrent.ExecutionException; - import org.opendaylight.controller.md.sal.common.api.data.TransactionCommitFailedException; - -import com.google.common.base.Function; -import com.google.common.base.Preconditions; +import org.opendaylight.yangtools.util.concurrent.ExceptionMapper; /** + * Utility exception mapper which translates Exception to {@link TransactionCommitFailedException}. * - * Utility exception mapper which translates {@link Exception} - * to {@link TransactionCommitFailedException}. - * - * This mapper is intended to be used with {@link com.google.common.util.concurrent.Futures#makeChecked(com.google.common.util.concurrent.ListenableFuture, Function)} - *
        - *
      • if exception is {@link TransactionCommitFailedException} or one of its subclasses returns original exception. - *
      • if exception is {@link ExecutionException} and cause is {@link TransactionCommitFailedException} return cause - *
      • otherwise returns {@link TransactionCommitFailedException} with original exception as a cause. - *
      - * + * @see ExceptionMapper */ - -final class TransactionCommitFailedExceptionMapper implements - Function { +final class TransactionCommitFailedExceptionMapper + extends ExceptionMapper { static final TransactionCommitFailedExceptionMapper PRE_COMMIT_MAPPER = create("canCommit"); @@ -37,10 +24,8 @@ final class TransactionCommitFailedExceptionMapper implements static final TransactionCommitFailedExceptionMapper COMMIT_ERROR_MAPPER = create("commit"); - private final String opName; - private TransactionCommitFailedExceptionMapper(final String opName) { - this.opName = Preconditions.checkNotNull(opName); + super( opName, TransactionCommitFailedException.class ); } public static final TransactionCommitFailedExceptionMapper create(final String opName) { @@ -48,22 +33,7 @@ final class TransactionCommitFailedExceptionMapper implements } @Override - public TransactionCommitFailedException apply(final Exception e) { - // If excetion is TransactionCommitFailedException - // we reuse it directly. - if (e instanceof TransactionCommitFailedException) { - return (TransactionCommitFailedException) e; - } - // If error is ExecutionException which was caused by cause of - // TransactionCommitFailedException - // we reuse original cause - if (e instanceof ExecutionException && e.getCause() instanceof TransactionCommitFailedException) { - return (TransactionCommitFailedException) e.getCause(); - } - if (e instanceof InterruptedException) { - return new TransactionCommitFailedException(opName + " failed - DOMStore was interupted.", e); - } - // Otherwise we are using new exception, with original cause - return new TransactionCommitFailedException(opName + " failed", e); + protected TransactionCommitFailedException newWithCause( String message, Throwable cause ) { + return new TransactionCommitFailedException( message, cause ); } } \ No newline at end of file diff --git a/opendaylight/md-sal/sal-dom-broker/src/main/java/org/opendaylight/controller/md/sal/dom/broker/impl/compat/BackwardsCompatibleDataBroker.java b/opendaylight/md-sal/sal-dom-broker/src/main/java/org/opendaylight/controller/md/sal/dom/broker/impl/compat/BackwardsCompatibleDataBroker.java index e8f8da53c9..dc122cfdc2 100644 --- a/opendaylight/md-sal/sal-dom-broker/src/main/java/org/opendaylight/controller/md/sal/dom/broker/impl/compat/BackwardsCompatibleDataBroker.java +++ b/opendaylight/md-sal/sal-dom-broker/src/main/java/org/opendaylight/controller/md/sal/dom/broker/impl/compat/BackwardsCompatibleDataBroker.java @@ -1,3 +1,10 @@ +/* + * Copyright (c) 2014 Cisco Systems, Inc. and others. All rights reserved. + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License v1.0 which accompanies this distribution, + * and is available at http://www.eclipse.org/legal/epl-v10.html. + */ package org.opendaylight.controller.md.sal.dom.broker.impl.compat; import javax.annotation.concurrent.ThreadSafe; @@ -21,18 +28,17 @@ import org.opendaylight.yangtools.yang.data.api.CompositeNode; import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier; import org.opendaylight.yangtools.yang.model.api.SchemaContext; import org.opendaylight.yangtools.yang.model.api.SchemaContextListener; -import org.opendaylight.yangtools.yang.model.api.SchemaServiceListener; @ThreadSafe public class BackwardsCompatibleDataBroker implements DataProviderService { private final DOMDataBroker backingBroker; private volatile DataNormalizer normalizer; - private final ListenerRegistration schemaReg; + private final ListenerRegistration schemaReg; public BackwardsCompatibleDataBroker(final DOMDataBroker newBiDataImpl, final SchemaService schemaService) { backingBroker = newBiDataImpl; - schemaReg = schemaService.registerSchemaServiceListener(new SchemaListener()); + schemaReg = schemaService.registerSchemaContextListener(new SchemaListener()); } @Override diff --git a/opendaylight/md-sal/sal-dom-broker/src/main/java/org/opendaylight/controller/sal/dom/broker/BackwardsCompatibleMountPoint.java b/opendaylight/md-sal/sal-dom-broker/src/main/java/org/opendaylight/controller/sal/dom/broker/BackwardsCompatibleMountPoint.java index d837d75ddc..5bd8a7bc02 100644 --- a/opendaylight/md-sal/sal-dom-broker/src/main/java/org/opendaylight/controller/sal/dom/broker/BackwardsCompatibleMountPoint.java +++ b/opendaylight/md-sal/sal-dom-broker/src/main/java/org/opendaylight/controller/sal/dom/broker/BackwardsCompatibleMountPoint.java @@ -15,16 +15,20 @@ 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.ReadFailedException; 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; @@ -72,7 +76,7 @@ import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier.PathArgum 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; +import org.opendaylight.yangtools.yang.model.api.SchemaContextListener; public class BackwardsCompatibleMountPoint implements MountProvisionInstance, SchemaContextProvider, SchemaService { @@ -83,7 +87,7 @@ public class BackwardsCompatibleMountPoint implements MountProvisionInstance, Sc private final NotificationPublishService notificationPublishService; private final RpcProvisionRegistry rpcs; - private final ListenerRegistry schemaListenerRegistry = new ListenerRegistry<>(); + private final ListenerRegistry schemaListenerRegistry = new ListenerRegistry<>(); private SchemaContext schemaContext; @@ -154,7 +158,7 @@ public class BackwardsCompatibleMountPoint implements MountProvisionInstance, Sc } @Override - public ListenerRegistration registerSchemaServiceListener(final SchemaServiceListener listener) { + public ListenerRegistration registerSchemaContextListener(final SchemaContextListener listener) { return schemaListenerRegistry.register(listener); } @@ -275,7 +279,7 @@ public class BackwardsCompatibleMountPoint implements MountProvisionInstance, Sc @Override public void setSchemaContext(final SchemaContext schemaContext) { this.schemaContext = schemaContext; - for (ListenerRegistration schemaServiceListenerListenerRegistration : schemaListenerRegistry.getListeners()) { + for (ListenerRegistration schemaServiceListenerListenerRegistration : schemaListenerRegistry.getListeners()) { schemaServiceListenerListenerRegistration.getInstance().onGlobalContextUpdated(schemaContext); } } @@ -380,7 +384,8 @@ public class BackwardsCompatibleMountPoint implements MountProvisionInstance, Sc } @Override - public ListenableFuture>> read(final LogicalDatastoreType store, final YangInstanceIdentifier path) { + public CheckedFuture>, ReadFailedException> read( + final LogicalDatastoreType store, final YangInstanceIdentifier path) { CompositeNode rawData = null; @@ -398,7 +403,7 @@ public class BackwardsCompatibleMountPoint implements MountProvisionInstance, Sc final Map.Entry> normalized = normalizer.toNormalized(path, rawData); final Optional> normalizedNodeOptional = Optional.>fromNullable(normalized.getValue()); - return com.google.common.util.concurrent.Futures.immediateFuture(normalizedNodeOptional); + return Futures.immediateCheckedFuture(normalizedNodeOptional); } } @@ -508,7 +513,8 @@ public class BackwardsCompatibleMountPoint implements MountProvisionInstance, Sc } @Override - public ListenableFuture>> read(final LogicalDatastoreType store, final YangInstanceIdentifier path) { + public CheckedFuture>, ReadFailedException> read( + final LogicalDatastoreType store, final YangInstanceIdentifier path) { return new BackwardsCompatibleReadTransaction(dataReader, dataNormalizer).read(store, path); } 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 d8174c312a..82637327f6 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 @@ -23,7 +23,7 @@ import org.opendaylight.yangtools.concepts.Registration; import org.opendaylight.yangtools.concepts.util.ListenerRegistry; import org.opendaylight.yangtools.yang.model.api.Module; import org.opendaylight.yangtools.yang.model.api.SchemaContext; -import org.opendaylight.yangtools.yang.model.api.SchemaServiceListener; +import org.opendaylight.yangtools.yang.model.api.SchemaContextListener; import org.opendaylight.yangtools.yang.parser.impl.util.URLSchemaContextResolver; import org.osgi.framework.Bundle; import org.osgi.framework.BundleContext; @@ -40,15 +40,15 @@ import com.google.common.base.Optional; import com.google.common.base.Preconditions; import com.google.common.collect.ImmutableList; -public class GlobalBundleScanningSchemaServiceImpl implements SchemaContextProvider, SchemaService, ServiceTrackerCustomizer, AutoCloseable { +public class GlobalBundleScanningSchemaServiceImpl implements SchemaContextProvider, SchemaService, ServiceTrackerCustomizer, AutoCloseable { private static final Logger LOG = LoggerFactory.getLogger(GlobalBundleScanningSchemaServiceImpl.class); - private final ListenerRegistry listeners = new ListenerRegistry<>(); + private final ListenerRegistry listeners = new ListenerRegistry<>(); private final URLSchemaContextResolver contextResolver = new URLSchemaContextResolver(); private final BundleScanner scanner = new BundleScanner(); private final BundleContext context; - private ServiceTracker listenerTracker; + private ServiceTracker listenerTracker; private BundleTracker> bundleTracker; private boolean starting = true; private static GlobalBundleScanningSchemaServiceImpl instance; @@ -81,7 +81,7 @@ public class GlobalBundleScanningSchemaServiceImpl implements SchemaContextProvi public void start() { checkState(context != null); - listenerTracker = new ServiceTracker<>(context, SchemaServiceListener.class, GlobalBundleScanningSchemaServiceImpl.this); + listenerTracker = new ServiceTracker<>(context, SchemaContextListener.class, GlobalBundleScanningSchemaServiceImpl.this); bundleTracker = new BundleTracker<>(context, BundleEvent.RESOLVED | BundleEvent.UNRESOLVED, scanner); bundleTracker.open(); listenerTracker.open(); @@ -115,7 +115,7 @@ public class GlobalBundleScanningSchemaServiceImpl implements SchemaContextProvi } @Override - public synchronized ListenerRegistration registerSchemaServiceListener(final SchemaServiceListener listener) { + public synchronized ListenerRegistration registerSchemaContextListener(final SchemaContextListener listener) { Optional potentialCtx = contextResolver.getSchemaContext(); if(potentialCtx.isPresent()) { listener.onGlobalContextUpdated(potentialCtx.get()); @@ -137,7 +137,7 @@ public class GlobalBundleScanningSchemaServiceImpl implements SchemaContextProvi private synchronized void updateContext(final SchemaContext snapshot) { Object[] services = listenerTracker.getServices(); - for (ListenerRegistration listener : listeners) { + for (ListenerRegistration listener : listeners) { try { listener.getInstance().onGlobalContextUpdated(snapshot); } catch (Exception e) { @@ -146,7 +146,7 @@ public class GlobalBundleScanningSchemaServiceImpl implements SchemaContextProvi } if (services != null) { for (Object rawListener : services) { - SchemaServiceListener listener = (SchemaServiceListener) rawListener; + final SchemaContextListener listener = (SchemaContextListener) rawListener; try { listener.onGlobalContextUpdated(snapshot); } catch (Exception e) { @@ -213,9 +213,9 @@ public class GlobalBundleScanningSchemaServiceImpl implements SchemaContextProvi } @Override - public synchronized SchemaServiceListener addingService(final ServiceReference reference) { + public synchronized SchemaContextListener addingService(final ServiceReference reference) { - SchemaServiceListener listener = context.getService(reference); + SchemaContextListener listener = context.getService(reference); SchemaContext _ctxContext = getGlobalContext(); if (getContext() != null && _ctxContext != null) { listener.onGlobalContextUpdated(_ctxContext); @@ -234,12 +234,12 @@ public class GlobalBundleScanningSchemaServiceImpl implements SchemaContextProvi } @Override - public void modifiedService(final ServiceReference reference, final SchemaServiceListener service) { + public void modifiedService(final ServiceReference reference, final SchemaContextListener service) { // NOOP } @Override - public void removedService(final ServiceReference reference, final SchemaServiceListener service) { + public void removedService(final ServiceReference reference, final SchemaContextListener service) { context.ungetService(reference); } } diff --git a/opendaylight/md-sal/sal-dom-broker/src/main/java/org/opendaylight/controller/sal/dom/broker/osgi/SchemaServiceProxy.java b/opendaylight/md-sal/sal-dom-broker/src/main/java/org/opendaylight/controller/sal/dom/broker/osgi/SchemaServiceProxy.java index 1d864eec5b..d8d2346a8c 100644 --- a/opendaylight/md-sal/sal-dom-broker/src/main/java/org/opendaylight/controller/sal/dom/broker/osgi/SchemaServiceProxy.java +++ b/opendaylight/md-sal/sal-dom-broker/src/main/java/org/opendaylight/controller/sal/dom/broker/osgi/SchemaServiceProxy.java @@ -8,10 +8,10 @@ package org.opendaylight.controller.sal.dom.broker.osgi; import org.opendaylight.controller.sal.core.api.model.SchemaService; -import org.opendaylight.yangtools.yang.model.api.SchemaServiceListener; import org.opendaylight.yangtools.concepts.ListenerRegistration; 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.osgi.framework.ServiceReference; public class SchemaServiceProxy extends AbstractBrokerServiceProxy implements SchemaService { @@ -41,12 +41,9 @@ public class SchemaServiceProxy extends AbstractBrokerServiceProxy registerSchemaServiceListener(SchemaServiceListener listener) { - ListenerRegistration registration = getDelegate().registerSchemaServiceListener(listener); + public ListenerRegistration registerSchemaContextListener(SchemaContextListener listener) { + ListenerRegistration registration = getDelegate().registerSchemaContextListener(listener); addRegistration(registration); return registration; } - - - } diff --git a/opendaylight/md-sal/sal-dom-broker/src/test/java/org/opendaylight/controller/md/sal/dom/broker/impl/DOMBrokerTest.java b/opendaylight/md-sal/sal-dom-broker/src/test/java/org/opendaylight/controller/md/sal/dom/broker/impl/DOMBrokerTest.java index b006ca94e5..0bb16a39b9 100644 --- a/opendaylight/md-sal/sal-dom-broker/src/test/java/org/opendaylight/controller/md/sal/dom/broker/impl/DOMBrokerTest.java +++ b/opendaylight/md-sal/sal-dom-broker/src/test/java/org/opendaylight/controller/md/sal/dom/broker/impl/DOMBrokerTest.java @@ -3,26 +3,40 @@ package org.opendaylight.controller.md.sal.dom.broker.impl; import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertNotNull; import static org.junit.Assert.assertTrue; +import static org.junit.Assert.assertEquals; import static org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType.CONFIGURATION; import static org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType.OPERATIONAL; +import java.util.concurrent.CountDownLatch; import java.util.concurrent.ExecutionException; import java.util.concurrent.Executors; +import java.util.concurrent.TimeUnit; +import java.util.concurrent.atomic.AtomicReference; +import org.junit.After; import org.junit.Before; import org.junit.Test; +import org.opendaylight.controller.md.sal.common.api.data.AsyncDataBroker.DataChangeScope; +import org.opendaylight.controller.md.sal.common.api.data.AsyncDataChangeEvent; import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType; +import org.opendaylight.controller.md.sal.common.api.data.TransactionCommitDeadlockException; +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.md.sal.dom.store.impl.InMemoryDOMDataStore; import org.opendaylight.controller.md.sal.dom.store.impl.TestModel; import org.opendaylight.controller.sal.core.spi.data.DOMStore; +import org.opendaylight.yangtools.util.concurrent.DeadlockDetectingListeningExecutorService; +import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier; import org.opendaylight.yangtools.yang.data.api.schema.NormalizedNode; import org.opendaylight.yangtools.yang.data.impl.schema.ImmutableNodes; import org.opendaylight.yangtools.yang.model.api.SchemaContext; import com.google.common.base.Optional; import com.google.common.collect.ImmutableMap; +import com.google.common.util.concurrent.FutureCallback; +import com.google.common.util.concurrent.Futures; import com.google.common.util.concurrent.ListenableFuture; import com.google.common.util.concurrent.ListeningExecutorService; import com.google.common.util.concurrent.MoreExecutors; @@ -31,6 +45,7 @@ public class DOMBrokerTest { private SchemaContext schemaContext; private DOMDataBrokerImpl domBroker; + private ListeningExecutorService executor; @Before public void setupStore() { @@ -46,11 +61,19 @@ public class DOMBrokerTest { .put(OPERATIONAL, operStore) // .build(); - ListeningExecutorService executor = MoreExecutors.listeningDecorator(Executors.newSingleThreadExecutor()); + executor = new DeadlockDetectingListeningExecutorService(Executors.newSingleThreadExecutor(), + TransactionCommitDeadlockException.DEADLOCK_EXECUTOR_FUNCTION); domBroker = new DOMDataBrokerImpl(stores, executor); } - @Test + @After + public void tearDown() { + if( executor != null ) { + executor.shutdownNow(); + } + } + + @Test(timeout=10000) public void testTransactionIsolation() throws InterruptedException, ExecutionException { assertNotNull(domBroker); @@ -86,7 +109,7 @@ public class DOMBrokerTest { assertFalse(readTxContainer.get().isPresent()); } - @Test + @Test(timeout=10000) public void testTransactionCommit() throws InterruptedException, ExecutionException { DOMDataReadWriteTransaction writeTx = domBroker.newReadWriteTransaction(); @@ -114,6 +137,173 @@ public class DOMBrokerTest { assertTrue(afterCommitRead.isPresent()); } + /** + * Tests a simple DataChangeListener notification after a write. + */ + @Test + public void testDataChangeListener() throws Throwable { + + final NormalizedNode testNode = ImmutableNodes.containerNode( TestModel.TEST_QNAME ); + + TestDOMDataChangeListener dcListener = new TestDOMDataChangeListener(); + + domBroker.registerDataChangeListener( OPERATIONAL, TestModel.TEST_PATH, + dcListener, DataChangeScope.BASE ); + + final DOMDataWriteTransaction writeTx = domBroker.newWriteOnlyTransaction(); + assertNotNull( writeTx ); + + writeTx.put( OPERATIONAL, TestModel.TEST_PATH, testNode ); + + AtomicReference caughtEx = submitTxAsync( writeTx ); + + dcListener.waitForChange(); + + if( caughtEx.get() != null ) { + throw caughtEx.get(); + } + + NormalizedNode actualNode = dcListener.change.getCreatedData().get( TestModel.TEST_PATH ); + assertEquals( "Created node", testNode, actualNode ); + } + + /** + * Tests a DataChangeListener that does an async submit of a write Tx in its onDataChanged method. + * This should succeed without deadlock. + */ + @Test + public void testDataChangeListenerDoingAsyncWriteTxSubmit() throws Throwable { + + final AtomicReference caughtCommitEx = new AtomicReference<>(); + final CountDownLatch commitCompletedLatch = new CountDownLatch( 1 ); + + TestDOMDataChangeListener dcListener = new TestDOMDataChangeListener() { + @Override + public void onDataChanged( AsyncDataChangeEvent> change ) { + + DOMDataWriteTransaction writeTx = domBroker.newWriteOnlyTransaction(); + writeTx.put( OPERATIONAL, TestModel.TEST2_PATH, + ImmutableNodes.containerNode( TestModel.TEST2_QNAME ) ); + Futures.addCallback( writeTx.submit(), new FutureCallback() { + @Override + public void onSuccess( Void result ) { + commitCompletedLatch.countDown(); + } + + @Override + public void onFailure( Throwable t ) { + caughtCommitEx.set( t ); + commitCompletedLatch.countDown(); + } + } ); + + super.onDataChanged( change ); + } + }; + + domBroker.registerDataChangeListener( OPERATIONAL, TestModel.TEST_PATH, + dcListener, DataChangeScope.BASE ); + + final DOMDataWriteTransaction writeTx = domBroker.newWriteOnlyTransaction(); + assertNotNull( writeTx ); + + writeTx.put( OPERATIONAL, TestModel.TEST_PATH, ImmutableNodes.containerNode( TestModel.TEST_QNAME ) ); + + AtomicReference caughtEx = submitTxAsync( writeTx ); + + dcListener.waitForChange(); + + if( caughtEx.get() != null ) { + throw caughtEx.get(); + } + + assertTrue( "Commit Future was not invoked", commitCompletedLatch.await( 5, TimeUnit.SECONDS ) ); + + if( caughtCommitEx.get() != null ) { + throw caughtCommitEx.get(); + } + } + + /** + * Tests a DataChangeListener that does a blocking submit of a write Tx in its onDataChanged method. + * This should throw an exception and not deadlock. + */ + @Test(expected=TransactionCommitDeadlockException.class) + public void testDataChangeListenerDoingBlockingWriteTxSubmit() throws Throwable { + + final AtomicReference caughtCommitEx = new AtomicReference<>(); + + TestDOMDataChangeListener dcListener = new TestDOMDataChangeListener() { + @Override + public void onDataChanged( AsyncDataChangeEvent> change ) { + DOMDataWriteTransaction writeTx = domBroker.newWriteOnlyTransaction(); + writeTx.put( OPERATIONAL, TestModel.TEST2_PATH, + ImmutableNodes.containerNode( TestModel.TEST2_QNAME ) ); + try { + writeTx.submit().get(); + } catch( ExecutionException e ) { + caughtCommitEx.set( e.getCause() ); + } catch( Exception e ) { + caughtCommitEx.set( e ); + } + finally { + super.onDataChanged( change ); + } + } + }; + + domBroker.registerDataChangeListener( OPERATIONAL, TestModel.TEST_PATH, + dcListener, DataChangeScope.BASE ); + + final DOMDataWriteTransaction writeTx = domBroker.newWriteOnlyTransaction(); + assertNotNull( writeTx ); + + writeTx.put( OPERATIONAL, TestModel.TEST_PATH, ImmutableNodes.containerNode( TestModel.TEST_QNAME ) ); + + AtomicReference caughtEx = submitTxAsync( writeTx ); + dcListener.waitForChange(); + if( caughtEx.get() != null ) { + throw caughtEx.get(); + } + + if( caughtCommitEx.get() != null ) { + throw caughtCommitEx.get(); + } + } + + AtomicReference submitTxAsync( final DOMDataWriteTransaction writeTx ) { + final AtomicReference caughtEx = new AtomicReference<>(); + new Thread() { + @Override + public void run() { + + try { + writeTx.submit(); + } catch( Throwable e ) { + caughtEx.set( e ); + } + } + + }.start(); + + return caughtEx; + } + + static class TestDOMDataChangeListener implements DOMDataChangeListener { + + volatile AsyncDataChangeEvent> change; + private final CountDownLatch latch = new CountDownLatch( 1 ); + + @Override + public void onDataChanged( AsyncDataChangeEvent> change ) { + this.change = change; + latch.countDown(); + } + + void waitForChange() throws InterruptedException { + assertTrue( "onDataChanged was not called", latch.await( 5, TimeUnit.SECONDS ) ); + } + } } 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 d5ba2a2b9a..09835ec5e3 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 @@ -21,6 +21,8 @@ public class TestModel { public static final QName TEST_QNAME = QName.create("urn:opendaylight:params:xml:ns:yang:controller:md:sal:dom:store:test", "2014-03-13", "test"); + public static final QName TEST2_QNAME = QName.create("urn:opendaylight:params:xml:ns:yang:controller:md:sal:dom:store:test", "2014-03-13", + "test2"); public static final QName OUTER_LIST_QNAME = QName.create(TEST_QNAME, "outer-list"); public static final QName INNER_LIST_QNAME = QName.create(TEST_QNAME, "inner-list"); public static final QName OUTER_CHOICE_QNAME = QName.create(TEST_QNAME, "outer-choice"); @@ -30,6 +32,7 @@ public class TestModel { private static final String DATASTORE_TEST_YANG = "/odl-datastore-test.yang"; public static final YangInstanceIdentifier TEST_PATH = YangInstanceIdentifier.of(TEST_QNAME); + public static final YangInstanceIdentifier TEST2_PATH = YangInstanceIdentifier.of(TEST2_QNAME); public static final YangInstanceIdentifier OUTER_LIST_PATH = YangInstanceIdentifier.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"); diff --git a/opendaylight/md-sal/sal-dom-broker/src/test/resources/odl-datastore-test.yang b/opendaylight/md-sal/sal-dom-broker/src/test/resources/odl-datastore-test.yang index 17541fecab..5fbf470f09 100644 --- a/opendaylight/md-sal/sal-dom-broker/src/test/resources/odl-datastore-test.yang +++ b/opendaylight/md-sal/sal-dom-broker/src/test/resources/odl-datastore-test.yang @@ -39,4 +39,7 @@ module odl-datastore-test { } } } + + container test2 { + } } \ No newline at end of file diff --git a/opendaylight/md-sal/sal-dom-spi/src/main/java/org/opendaylight/controller/sal/core/spi/data/DOMStoreReadTransaction.java b/opendaylight/md-sal/sal-dom-spi/src/main/java/org/opendaylight/controller/sal/core/spi/data/DOMStoreReadTransaction.java index ae1b3ee2aa..84d09c7cb0 100644 --- a/opendaylight/md-sal/sal-dom-spi/src/main/java/org/opendaylight/controller/sal/core/spi/data/DOMStoreReadTransaction.java +++ b/opendaylight/md-sal/sal-dom-spi/src/main/java/org/opendaylight/controller/sal/core/spi/data/DOMStoreReadTransaction.java @@ -7,29 +7,31 @@ */ package org.opendaylight.controller.sal.core.spi.data; +import org.opendaylight.controller.md.sal.common.api.data.ReadFailedException; import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier; import org.opendaylight.yangtools.yang.data.api.schema.NormalizedNode; import com.google.common.base.Optional; -import com.google.common.util.concurrent.ListenableFuture; +import com.google.common.util.concurrent.CheckedFuture; public interface DOMStoreReadTransaction extends DOMStoreTransaction { /** - * * Reads data from provided logical data store located at provided path * - * * @param path * Path which uniquely identifies subtree which client want to * read - * @return Listenable Future which contains read result + * @return a CheckFuture containing the result of the read. The Future blocks until the + * commit operation is complete. Once complete: *
        - *
      • If data at supplied path exists the {@link java.util.concurrent.Future#get()} - * returns Optional object containing data - *
      • If data at supplied path does not exists the - * {@link java.util.concurrent.Future#get()} returns {@link Optional#absent()}. + *
      • If the data at the supplied path exists, the Future returns an Optional object + * containing the data.
      • + *
      • If the data at the supplied path does not exist, the Future returns + * Optional#absent().
      • + *
      • If the read of the data fails, the Future will fail with a + * {@link ReadFailedException} or an exception derived from ReadFailedException.
      • *
      */ - ListenableFuture>> read(YangInstanceIdentifier path); + CheckedFuture>, ReadFailedException> read(YangInstanceIdentifier path); } diff --git a/opendaylight/md-sal/sal-dom-xsql/src/main/java/org/opendaylight/yang/gen/v1/http/netconfcentral/org/ns/xsql/rev140626/XSQLModule.java b/opendaylight/md-sal/sal-dom-xsql/src/main/java/org/opendaylight/yang/gen/v1/http/netconfcentral/org/ns/xsql/rev140626/XSQLModule.java index 399f49bd6b..59cdc76e7a 100644 --- a/opendaylight/md-sal/sal-dom-xsql/src/main/java/org/opendaylight/yang/gen/v1/http/netconfcentral/org/ns/xsql/rev140626/XSQLModule.java +++ b/opendaylight/md-sal/sal-dom-xsql/src/main/java/org/opendaylight/yang/gen/v1/http/netconfcentral/org/ns/xsql/rev140626/XSQLModule.java @@ -20,7 +20,7 @@ public class XSQLModule extends org.opendaylight.yang.gen.v1.http.netconfcentral @Override public java.lang.AutoCloseable createInstance() { XSQLAdapter xsqlAdapter = XSQLAdapter.getInstance(); - getSchemaServiceDependency().registerSchemaServiceListener(xsqlAdapter); + getSchemaServiceDependency().registerSchemaContextListener(xsqlAdapter); xsqlAdapter.setDataBroker(getAsyncDataBrokerDependency()); XSQLProvider p = new XSQLProvider(); p.buildXSQL(getDataBrokerDependency()); diff --git a/opendaylight/md-sal/sal-inmemory-datastore/pom.xml b/opendaylight/md-sal/sal-inmemory-datastore/pom.xml index 906847426c..725b24cd9e 100644 --- a/opendaylight/md-sal/sal-inmemory-datastore/pom.xml +++ b/opendaylight/md-sal/sal-inmemory-datastore/pom.xml @@ -112,12 +112,16 @@ binding-generator-impl test + + org.opendaylight.yangtools + mockito-configuration + test + org.opendaylight.controller sal-test-model test - ${project.version} - + diff --git a/opendaylight/md-sal/sal-inmemory-datastore/src/main/java/org/opendaylight/controller/config/yang/inmemory_datastore_provider/InMemoryConfigDataStoreProviderModule.java b/opendaylight/md-sal/sal-inmemory-datastore/src/main/java/org/opendaylight/controller/config/yang/inmemory_datastore_provider/InMemoryConfigDataStoreProviderModule.java index 01a5989dcd..805608d479 100644 --- a/opendaylight/md-sal/sal-inmemory-datastore/src/main/java/org/opendaylight/controller/config/yang/inmemory_datastore_provider/InMemoryConfigDataStoreProviderModule.java +++ b/opendaylight/md-sal/sal-inmemory-datastore/src/main/java/org/opendaylight/controller/config/yang/inmemory_datastore_provider/InMemoryConfigDataStoreProviderModule.java @@ -23,7 +23,7 @@ public class InMemoryConfigDataStoreProviderModule extends org.opendaylight.cont @Override public java.lang.AutoCloseable createInstance() { InMemoryDOMDataStore ids = new InMemoryDOMDataStore("DOM-CFG", MoreExecutors.listeningDecorator(Executors.newSingleThreadExecutor())); - getSchemaServiceDependency().registerSchemaServiceListener(ids); + getSchemaServiceDependency().registerSchemaContextListener(ids); return ids; } diff --git a/opendaylight/md-sal/sal-inmemory-datastore/src/main/java/org/opendaylight/controller/config/yang/inmemory_datastore_provider/InMemoryOperationalDataStoreProviderModule.java b/opendaylight/md-sal/sal-inmemory-datastore/src/main/java/org/opendaylight/controller/config/yang/inmemory_datastore_provider/InMemoryOperationalDataStoreProviderModule.java index b39c9bbbd8..f4795588ab 100644 --- a/opendaylight/md-sal/sal-inmemory-datastore/src/main/java/org/opendaylight/controller/config/yang/inmemory_datastore_provider/InMemoryOperationalDataStoreProviderModule.java +++ b/opendaylight/md-sal/sal-inmemory-datastore/src/main/java/org/opendaylight/controller/config/yang/inmemory_datastore_provider/InMemoryOperationalDataStoreProviderModule.java @@ -23,7 +23,7 @@ public class InMemoryOperationalDataStoreProviderModule extends org.opendaylight @Override public java.lang.AutoCloseable createInstance() { InMemoryDOMDataStore ids = new InMemoryDOMDataStore("DOM-OPER", MoreExecutors.listeningDecorator(Executors.newSingleThreadExecutor())); - getOperationalSchemaServiceDependency().registerSchemaServiceListener(ids); + getOperationalSchemaServiceDependency().registerSchemaContextListener(ids); return ids; } diff --git a/opendaylight/md-sal/sal-inmemory-datastore/src/main/java/org/opendaylight/controller/md/sal/dom/store/impl/ResolveDataChangeEventsTask.java b/opendaylight/md-sal/sal-inmemory-datastore/src/main/java/org/opendaylight/controller/md/sal/dom/store/impl/ResolveDataChangeEventsTask.java index ff64cd64c4..3ddf0b60fa 100644 --- a/opendaylight/md-sal/sal-inmemory-datastore/src/main/java/org/opendaylight/controller/md/sal/dom/store/impl/ResolveDataChangeEventsTask.java +++ b/opendaylight/md-sal/sal-inmemory-datastore/src/main/java/org/opendaylight/controller/md/sal/dom/store/impl/ResolveDataChangeEventsTask.java @@ -9,9 +9,15 @@ package org.opendaylight.controller.md.sal.dom.store.impl; import static org.opendaylight.controller.md.sal.dom.store.impl.DOMImmutableDataChangeEvent.builder; +import com.google.common.base.Optional; +import com.google.common.base.Preconditions; +import com.google.common.collect.HashMultimap; +import com.google.common.collect.ImmutableList; +import com.google.common.collect.Iterables; +import com.google.common.collect.Multimap; + import java.util.Collection; import java.util.Collections; -import java.util.HashSet; import java.util.LinkedList; import java.util.List; import java.util.Map.Entry; @@ -37,13 +43,6 @@ import org.opendaylight.yangtools.yang.data.api.schema.tree.ModificationType; 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.HashMultimap; -import com.google.common.collect.ImmutableList; -import com.google.common.collect.Iterables; -import com.google.common.collect.Multimap; - /** * Resolve Data Change Events based on modifications and listeners * @@ -278,6 +277,11 @@ final class ResolveDataChangeEventsTask implements Callable listeners, final NormalizedNode beforeData, final NormalizedNode afterData) { + // FIXME: BUG-1493: check the listeners to prune unneeded changes: + // for subtrees, we have to do all + // for one, we need to expand children + // for base, we just report replacement + if (beforeData instanceof NormalizedNodeContainer) { // Node is container (contains child) and we have interested // listeners registered for it, that means we need to do @@ -306,14 +310,12 @@ final class ResolveDataChangeEventsTask implements Callable listeners, final NormalizedNodeContainer> beforeCont, final NormalizedNodeContainer> afterCont) { - final Set alreadyProcessed = new HashSet<>(); final List childChanges = new LinkedList<>(); - DataChangeScope potentialScope = DataChangeScope.BASE; // We look at all children from before and compare it with after state. for (NormalizedNode beforeChild : beforeCont.getValue()) { - PathArgument childId = beforeChild.getIdentifier(); - alreadyProcessed.add(childId); + final PathArgument childId = beforeChild.getIdentifier(); + YangInstanceIdentifier childPath = path.node(childId); Collection childListeners = getListenerChildrenWildcarded(listeners, childId); Optional> afterChild = afterCont.getChild(childId); @@ -323,15 +325,17 @@ final class ResolveDataChangeEventsTask implements Callable afterChild : afterCont.getValue()) { - PathArgument childId = afterChild.getIdentifier(); - if (!alreadyProcessed.contains(childId)) { - // We did not processed that child already - // and it was not present in previous loop, that means it is - // created. + final PathArgument childId = afterChild.getIdentifier(); + + /* + * We have already iterated of the before-children, so have already + * emitted modify/delete events. This means the child has been + * created. + */ + if (!beforeCont.getChild(childId).isPresent()) { Collection childListeners = getListenerChildrenWildcarded(listeners, childId); YangInstanceIdentifier childPath = path.node(childId); childChanges.add(resolveSameEventRecursivelly(childPath , childListeners, afterChild, @@ -342,7 +346,7 @@ final class ResolveDataChangeEventsTask implements Callable>> read(final YangInstanceIdentifier path) { + public CheckedFuture>, ReadFailedException> read(final YangInstanceIdentifier path) { + LOG.debug("Tx: {} Read: {}", getIdentifier(), path); checkNotNull(path, "Path must not be null."); - checkState(stableSnapshot != null, "Transaction is closed"); - return Futures.immediateFuture(stableSnapshot.readNode(path)); + + if(stableSnapshot == null) { + return Futures.immediateFailedCheckedFuture(new ReadFailedException("Transaction is closed")); + } + + try { + return Futures.immediateCheckedFuture(stableSnapshot.readNode(path)); + } catch (Exception e) { + LOG.error("Tx: {} Failed Read of {}", getIdentifier(), path, e); + return Futures.immediateFailedCheckedFuture(new ReadFailedException("Read failed",e)); + } } } \ No newline at end of file diff --git a/opendaylight/md-sal/sal-inmemory-datastore/src/main/java/org/opendaylight/controller/md/sal/dom/store/impl/SnapshotBackedReadWriteTransaction.java b/opendaylight/md-sal/sal-inmemory-datastore/src/main/java/org/opendaylight/controller/md/sal/dom/store/impl/SnapshotBackedReadWriteTransaction.java index ec17d7a3f7..5c5e9c6b6d 100644 --- a/opendaylight/md-sal/sal-inmemory-datastore/src/main/java/org/opendaylight/controller/md/sal/dom/store/impl/SnapshotBackedReadWriteTransaction.java +++ b/opendaylight/md-sal/sal-inmemory-datastore/src/main/java/org/opendaylight/controller/md/sal/dom/store/impl/SnapshotBackedReadWriteTransaction.java @@ -7,7 +7,11 @@ */ package org.opendaylight.controller.md.sal.dom.store.impl; +import static com.google.common.base.Preconditions.checkNotNull; + +import org.opendaylight.yangtools.yang.data.api.schema.tree.DataTreeModification; import org.opendaylight.yangtools.yang.data.api.schema.tree.DataTreeSnapshot; +import org.opendaylight.controller.md.sal.common.api.data.ReadFailedException; import org.opendaylight.controller.sal.core.spi.data.DOMStoreReadWriteTransaction; import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier; import org.opendaylight.yangtools.yang.data.api.schema.NormalizedNode; @@ -15,16 +19,16 @@ import org.slf4j.Logger; import org.slf4j.LoggerFactory; import com.google.common.base.Optional; +import com.google.common.util.concurrent.CheckedFuture; import com.google.common.util.concurrent.Futures; -import com.google.common.util.concurrent.ListenableFuture; /** * Implementation of Read-Write transaction which is backed by {@link DataTreeSnapshot} * and executed according to {@link TransactionReadyPrototype}. * */ -class SnapshotBackedReadWriteTransaction extends SnapshotBackedWriteTransaction implements -DOMStoreReadWriteTransaction { +class SnapshotBackedReadWriteTransaction extends SnapshotBackedWriteTransaction + implements DOMStoreReadWriteTransaction { private static final Logger LOG = LoggerFactory.getLogger(SnapshotBackedReadWriteTransaction.class); @@ -41,13 +45,20 @@ DOMStoreReadWriteTransaction { } @Override - public ListenableFuture>> read(final YangInstanceIdentifier path) { + public CheckedFuture>, ReadFailedException> read(final YangInstanceIdentifier path) { LOG.debug("Tx: {} Read: {}", getIdentifier(), path); + checkNotNull(path, "Path must not be null."); + + DataTreeModification dataView = getMutatedView(); + if(dataView == null) { + return Futures.immediateFailedCheckedFuture(new ReadFailedException("Transaction is closed")); + } + try { - return Futures.immediateFuture(getMutatedView().readNode(path)); + return Futures.immediateCheckedFuture(dataView.readNode(path)); } catch (Exception e) { LOG.error("Tx: {} Failed Read of {}", getIdentifier(), path, e); - throw e; + return Futures.immediateFailedCheckedFuture(new ReadFailedException("Read failed",e)); } } } \ No newline at end of file diff --git a/opendaylight/md-sal/sal-inmemory-datastore/src/test/java/org/opendaylight/controller/md/sal/dom/store/impl/InMemoryDataStoreTest.java b/opendaylight/md-sal/sal-inmemory-datastore/src/test/java/org/opendaylight/controller/md/sal/dom/store/impl/InMemoryDataStoreTest.java index 96369dea5f..9b105aa306 100644 --- a/opendaylight/md-sal/sal-inmemory-datastore/src/test/java/org/opendaylight/controller/md/sal/dom/store/impl/InMemoryDataStoreTest.java +++ b/opendaylight/md-sal/sal-inmemory-datastore/src/test/java/org/opendaylight/controller/md/sal/dom/store/impl/InMemoryDataStoreTest.java @@ -7,6 +7,7 @@ */ package org.opendaylight.controller.md.sal.dom.store.impl; +import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertNotNull; import static org.junit.Assert.assertTrue; @@ -16,12 +17,22 @@ import java.util.concurrent.ExecutionException; import org.junit.Before; import org.junit.Ignore; import org.junit.Test; +import org.mockito.Mockito; +import org.opendaylight.controller.md.sal.common.api.data.ReadFailedException; +import org.opendaylight.controller.md.sal.dom.store.impl.SnapshotBackedWriteTransaction.TransactionReadyPrototype; import org.opendaylight.controller.sal.core.spi.data.DOMStoreReadTransaction; import org.opendaylight.controller.sal.core.spi.data.DOMStoreReadWriteTransaction; import org.opendaylight.controller.sal.core.spi.data.DOMStoreThreePhaseCommitCohort; import org.opendaylight.controller.sal.core.spi.data.DOMStoreTransactionChain; +import org.opendaylight.controller.sal.core.spi.data.DOMStoreWriteTransaction; +import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier; +import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier.NodeIdentifier; +import org.opendaylight.yangtools.yang.data.api.schema.ContainerNode; import org.opendaylight.yangtools.yang.data.api.schema.NormalizedNode; +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.impl.schema.ImmutableNodes; +import org.opendaylight.yangtools.yang.data.impl.schema.builder.impl.ImmutableContainerNodeBuilder; import org.opendaylight.yangtools.yang.model.api.SchemaContext; import com.google.common.base.Optional; @@ -31,226 +42,373 @@ import com.google.common.util.concurrent.MoreExecutors; public class InMemoryDataStoreTest { - private SchemaContext schemaContext; - private InMemoryDOMDataStore domStore; + private SchemaContext schemaContext; + private InMemoryDOMDataStore domStore; - @Before - public void setupStore() { - domStore = new InMemoryDOMDataStore("TEST", MoreExecutors.sameThreadExecutor()); - schemaContext = TestModel.createTestContext(); - domStore.onGlobalContextUpdated(schemaContext); + @Before + public void setupStore() { + domStore = new InMemoryDOMDataStore("TEST", MoreExecutors.sameThreadExecutor()); + schemaContext = TestModel.createTestContext(); + domStore.onGlobalContextUpdated(schemaContext); + } - } + @Test + public void testTransactionIsolation() throws InterruptedException, ExecutionException { - @Test - public void testTransactionIsolation() throws InterruptedException, ExecutionException { + assertNotNull(domStore); - assertNotNull(domStore); + DOMStoreReadTransaction readTx = domStore.newReadOnlyTransaction(); + assertNotNull(readTx); - DOMStoreReadTransaction readTx = domStore.newReadOnlyTransaction(); - assertNotNull(readTx); + DOMStoreReadWriteTransaction writeTx = domStore.newReadWriteTransaction(); + assertNotNull(writeTx); - DOMStoreReadWriteTransaction writeTx = domStore.newReadWriteTransaction(); - assertNotNull(writeTx); - /** - * - * Writes /test in writeTx - * - */ - writeTx.write(TestModel.TEST_PATH, ImmutableNodes.containerNode(TestModel.TEST_QNAME)); + /** + * Writes /test in writeTx + */ + NormalizedNode testNode = ImmutableNodes.containerNode(TestModel.TEST_QNAME); + writeTx.write(TestModel.TEST_PATH, testNode); - /** - * - * Reads /test from writeTx Read should return container. - * - */ - ListenableFuture>> writeTxContainer = writeTx.read(TestModel.TEST_PATH); - assertTrue(writeTxContainer.get().isPresent()); + /** + * Reads /test from writeTx Read should return container. + */ + ListenableFuture>> writeTxContainer = writeTx.read(TestModel.TEST_PATH); + assertEquals("read: isPresent", true, writeTxContainer.get().isPresent()); + assertEquals("read: data", testNode, writeTxContainer.get().get()); - /** - * - * Reads /test from readTx Read should return Absent. - * - */ - ListenableFuture>> readTxContainer = readTx.read(TestModel.TEST_PATH); - assertFalse(readTxContainer.get().isPresent()); - } + /** + * Reads /test from readTx Read should return Absent. + */ + ListenableFuture>> readTxContainer = readTx.read(TestModel.TEST_PATH); + assertEquals("read: isPresent", false, readTxContainer.get().isPresent()); + } - @Test - public void testTransactionCommit() throws InterruptedException, ExecutionException { + @Test + public void testTransactionCommit() throws InterruptedException, ExecutionException { - DOMStoreReadWriteTransaction writeTx = domStore.newReadWriteTransaction(); - assertNotNull(writeTx); - /** - * - * Writes /test in writeTx - * - */ - writeTx.write(TestModel.TEST_PATH, ImmutableNodes.containerNode(TestModel.TEST_QNAME)); + DOMStoreReadWriteTransaction writeTx = domStore.newReadWriteTransaction(); + assertNotNull(writeTx); - /** - * - * Reads /test from writeTx Read should return container. - * - */ - ListenableFuture>> writeTxContainer = writeTx.read(TestModel.TEST_PATH); - assertTrue(writeTxContainer.get().isPresent()); + /** + * Writes /test in writeTx + */ + NormalizedNode testNode = ImmutableNodes.containerNode(TestModel.TEST_QNAME); + writeTx.write(TestModel.TEST_PATH, testNode); - DOMStoreThreePhaseCommitCohort cohort = writeTx.ready(); + /** + * Reads /test from writeTx Read should return container. + */ + ListenableFuture>> writeTxContainer = writeTx.read(TestModel.TEST_PATH); + assertEquals("read: isPresent", true, writeTxContainer.get().isPresent()); + assertEquals("read: data", testNode, writeTxContainer.get().get()); - assertThreePhaseCommit(cohort); + DOMStoreThreePhaseCommitCohort cohort = writeTx.ready(); - Optional> afterCommitRead = domStore.newReadOnlyTransaction().read(TestModel.TEST_PATH) - .get(); - assertTrue(afterCommitRead.isPresent()); - } + assertThreePhaseCommit(cohort); - @Test - public void testTransactionAbort() throws InterruptedException, ExecutionException { + Optional> afterCommitRead = domStore.newReadOnlyTransaction().read(TestModel.TEST_PATH) + .get(); + assertEquals("After commit read: isPresent", true, afterCommitRead.isPresent()); + assertEquals("After commit read: data", testNode, afterCommitRead.get()); + } - DOMStoreReadWriteTransaction writeTx = domStore.newReadWriteTransaction(); - assertNotNull(writeTx); + @Test + public void testDelete() throws Exception { - assertTestContainerWrite(writeTx); + DOMStoreWriteTransaction writeTx = domStore.newWriteOnlyTransaction(); + assertNotNull( writeTx ); - DOMStoreThreePhaseCommitCohort cohort = writeTx.ready(); + // Write /test and commit - assertTrue(cohort.canCommit().get().booleanValue()); - cohort.preCommit().get(); - cohort.abort().get(); + writeTx.write( TestModel.TEST_PATH, ImmutableNodes.containerNode( TestModel.TEST_QNAME ) ); - Optional> afterCommitRead = domStore.newReadOnlyTransaction().read(TestModel.TEST_PATH) - .get(); - assertFalse(afterCommitRead.isPresent()); - } + assertThreePhaseCommit( writeTx.ready() ); - @Test - public void testTransactionChain() throws InterruptedException, ExecutionException { - DOMStoreTransactionChain txChain = domStore.createTransactionChain(); - assertNotNull(txChain); + Optional> afterCommitRead = domStore.newReadOnlyTransaction(). + read(TestModel.TEST_PATH ).get(); + assertEquals( "After commit read: isPresent", true, afterCommitRead.isPresent() ); - /** - * We alocate new read-write transaction and write /test - * - * - */ - DOMStoreReadWriteTransaction firstTx = txChain.newReadWriteTransaction(); - assertTestContainerWrite(firstTx); + // Delete /test and verify - /** - * First transaction is marked as ready, we are able to allocate chained - * transactions - */ - DOMStoreThreePhaseCommitCohort firstWriteTxCohort = firstTx.ready(); + writeTx = domStore.newWriteOnlyTransaction(); - /** - * We alocate chained transaction - read transaction, note first one is - * still not commited to datastore. - */ - DOMStoreReadTransaction secondReadTx = txChain.newReadOnlyTransaction(); + writeTx.delete( TestModel.TEST_PATH ); - /** - * - * We test if we are able to read data from tx, read should not fail - * since we are using chained transaction. - * - * - */ - assertTestContainerExists(secondReadTx); + assertThreePhaseCommit( writeTx.ready() ); - /** - * - * We alocate next transaction, which is still based on first one, but - * is read-write. - * - */ - DOMStoreReadWriteTransaction thirdDeleteTx = txChain.newReadWriteTransaction(); + afterCommitRead = domStore.newReadOnlyTransaction(). + read(TestModel.TEST_PATH ).get(); + assertEquals( "After commit read: isPresent", false, afterCommitRead.isPresent() ); + } - /** - * We test existence of /test in third transaction container should - * still be visible from first one (which is still uncommmited). - * - * - */ - assertTestContainerExists(thirdDeleteTx); + @Test + public void testMerge() throws Exception { - /** - * We delete node in third transaction - */ - thirdDeleteTx.delete(TestModel.TEST_PATH); + DOMStoreWriteTransaction writeTx = domStore.newWriteOnlyTransaction(); + assertNotNull( writeTx ); - /** - * third transaction is sealed. - */ - DOMStoreThreePhaseCommitCohort thirdDeleteTxCohort = thirdDeleteTx.ready(); + ContainerNode containerNode = ImmutableContainerNodeBuilder.create() + .withNodeIdentifier( new NodeIdentifier( TestModel.TEST_QNAME ) ) + .addChild( ImmutableNodes.mapNodeBuilder( TestModel.OUTER_LIST_QNAME ) + .addChild( ImmutableNodes.mapEntry( TestModel.OUTER_LIST_QNAME, + TestModel.ID_QNAME, 1 ) ).build() ).build(); - /** - * We commit first transaction - * - */ - assertThreePhaseCommit(firstWriteTxCohort); + writeTx.merge( TestModel.TEST_PATH, containerNode ); - // Alocates store transacion - DOMStoreReadTransaction storeReadTx = domStore.newReadOnlyTransaction(); - /** - * We verify transaction is commited to store, container should exists - * in datastore. - */ - assertTestContainerExists(storeReadTx); - /** - * We commit third transaction - * - */ - assertThreePhaseCommit(thirdDeleteTxCohort); - } + assertThreePhaseCommit( writeTx.ready() ); - @Test - @Ignore - public void testTransactionConflict() throws InterruptedException, ExecutionException { - DOMStoreReadWriteTransaction txOne = domStore.newReadWriteTransaction(); - DOMStoreReadWriteTransaction txTwo = domStore.newReadWriteTransaction(); - assertTestContainerWrite(txOne); - assertTestContainerWrite(txTwo); + Optional> afterCommitRead = domStore.newReadOnlyTransaction(). + read(TestModel.TEST_PATH ).get(); + assertEquals( "After commit read: isPresent", true, afterCommitRead.isPresent() ); + assertEquals( "After commit read: data", containerNode, afterCommitRead.get() ); - /** - * Commits transaction - */ - assertThreePhaseCommit(txOne.ready()); + // Merge a new list entry node - /** - * Asserts that txTwo could not be commited - */ - assertFalse(txTwo.ready().canCommit().get()); - } - - private static void assertThreePhaseCommit(final DOMStoreThreePhaseCommitCohort cohort) - throws InterruptedException, ExecutionException { - assertTrue(cohort.canCommit().get().booleanValue()); - cohort.preCommit().get(); - cohort.commit().get(); - } - - private static Optional> assertTestContainerWrite(final DOMStoreReadWriteTransaction writeTx) - throws InterruptedException, ExecutionException { - /** - * - * Writes /test in writeTx - * - */ - writeTx.write(TestModel.TEST_PATH, ImmutableNodes.containerNode(TestModel.TEST_QNAME)); + writeTx = domStore.newWriteOnlyTransaction(); + assertNotNull( writeTx ); + + containerNode = ImmutableContainerNodeBuilder.create() + .withNodeIdentifier( new NodeIdentifier( TestModel.TEST_QNAME ) ) + .addChild( ImmutableNodes.mapNodeBuilder( TestModel.OUTER_LIST_QNAME ) + .addChild( ImmutableNodes.mapEntry( TestModel.OUTER_LIST_QNAME, + TestModel.ID_QNAME, 1 ) ) + .addChild( ImmutableNodes.mapEntry( TestModel.OUTER_LIST_QNAME, + TestModel.ID_QNAME, 2 ) ).build() ).build(); + + writeTx.merge( TestModel.TEST_PATH, containerNode ); + + assertThreePhaseCommit( writeTx.ready() ); + + afterCommitRead = domStore.newReadOnlyTransaction().read(TestModel.TEST_PATH ).get(); + assertEquals( "After commit read: isPresent", true, afterCommitRead.isPresent() ); + assertEquals( "After commit read: data", containerNode, afterCommitRead.get() ); + } + + @Test(expected=ReadFailedException.class) + public void testReadWithReadOnlyTransactionClosed() throws Throwable { + + DOMStoreReadTransaction readTx = domStore.newReadOnlyTransaction(); + assertNotNull( readTx ); + + readTx.close(); + + doReadAndThrowEx( readTx ); + } + + @Test(expected=ReadFailedException.class) + public void testReadWithReadOnlyTransactionFailure() throws Throwable { + + DataTreeSnapshot mockSnapshot = Mockito.mock( DataTreeSnapshot.class ); + Mockito.doThrow( new RuntimeException( "mock ex" ) ).when( mockSnapshot ) + .readNode( Mockito.any( YangInstanceIdentifier.class ) ); + + DOMStoreReadTransaction readTx = new SnapshotBackedReadTransaction( "1", mockSnapshot ); + + doReadAndThrowEx( readTx ); + } - return assertTestContainerExists(writeTx); - } + @Test(expected=ReadFailedException.class) + public void testReadWithReadWriteTransactionClosed() throws Throwable { - /** - * Reads /test from readTx Read should return container. - */ - private static Optional> assertTestContainerExists(final DOMStoreReadTransaction readTx) - throws InterruptedException, ExecutionException { + DOMStoreReadTransaction readTx = domStore.newReadWriteTransaction(); + assertNotNull( readTx ); + + readTx.close(); + + doReadAndThrowEx( readTx ); + } + + @Test(expected=ReadFailedException.class) + public void testReadWithReadWriteTransactionFailure() throws Throwable { + + DataTreeSnapshot mockSnapshot = Mockito.mock( DataTreeSnapshot.class ); + DataTreeModification mockModification = Mockito.mock( DataTreeModification.class ); + Mockito.doThrow( new RuntimeException( "mock ex" ) ).when( mockModification ) + .readNode( Mockito.any( YangInstanceIdentifier.class ) ); + Mockito.doReturn( mockModification ).when( mockSnapshot ).newModification(); + TransactionReadyPrototype mockReady = Mockito.mock( TransactionReadyPrototype.class ); + DOMStoreReadTransaction readTx = new SnapshotBackedReadWriteTransaction( "1", mockSnapshot, mockReady ); + + doReadAndThrowEx( readTx ); + } + + private void doReadAndThrowEx( DOMStoreReadTransaction readTx ) throws Throwable { + + try { + readTx.read(TestModel.TEST_PATH).get(); + } catch( ExecutionException e ) { + throw e.getCause(); + } + } + + @Test(expected=IllegalStateException.class) + public void testWriteWithTransactionReady() throws Exception { + + DOMStoreWriteTransaction writeTx = domStore.newWriteOnlyTransaction(); + + writeTx.ready(); + + // Should throw ex + writeTx.write( TestModel.TEST_PATH, ImmutableNodes.containerNode( TestModel.TEST_QNAME ) ); + } + + @Test(expected=IllegalStateException.class) + public void testReadyWithTransactionAlreadyReady() throws Exception { + + DOMStoreWriteTransaction writeTx = domStore.newWriteOnlyTransaction(); + + writeTx.ready(); + + // Should throw ex + writeTx.ready(); + } + + @Test + public void testTransactionAbort() throws InterruptedException, ExecutionException { + + DOMStoreReadWriteTransaction writeTx = domStore.newReadWriteTransaction(); + assertNotNull(writeTx); + + assertTestContainerWrite(writeTx); + + DOMStoreThreePhaseCommitCohort cohort = writeTx.ready(); + + assertTrue(cohort.canCommit().get().booleanValue()); + cohort.preCommit().get(); + cohort.abort().get(); + + Optional> afterCommitRead = domStore.newReadOnlyTransaction().read(TestModel.TEST_PATH) + .get(); + assertFalse(afterCommitRead.isPresent()); + } + + @Test + public void testTransactionChain() throws InterruptedException, ExecutionException { + DOMStoreTransactionChain txChain = domStore.createTransactionChain(); + assertNotNull(txChain); + + /** + * We alocate new read-write transaction and write /test + * + * + */ + DOMStoreReadWriteTransaction firstTx = txChain.newReadWriteTransaction(); + assertTestContainerWrite(firstTx); + + /** + * First transaction is marked as ready, we are able to allocate chained + * transactions + */ + DOMStoreThreePhaseCommitCohort firstWriteTxCohort = firstTx.ready(); + + /** + * We alocate chained transaction - read transaction, note first one is + * still not commited to datastore. + */ + DOMStoreReadTransaction secondReadTx = txChain.newReadOnlyTransaction(); + + /** + * + * We test if we are able to read data from tx, read should not fail + * since we are using chained transaction. + * + * + */ + assertTestContainerExists(secondReadTx); + + /** + * + * We alocate next transaction, which is still based on first one, but + * is read-write. + * + */ + DOMStoreReadWriteTransaction thirdDeleteTx = txChain.newReadWriteTransaction(); + + /** + * We test existence of /test in third transaction container should + * still be visible from first one (which is still uncommmited). + * + * + */ + assertTestContainerExists(thirdDeleteTx); + + /** + * We delete node in third transaction + */ + thirdDeleteTx.delete(TestModel.TEST_PATH); + + /** + * third transaction is sealed. + */ + DOMStoreThreePhaseCommitCohort thirdDeleteTxCohort = thirdDeleteTx.ready(); + + /** + * We commit first transaction + * + */ + assertThreePhaseCommit(firstWriteTxCohort); + + // Alocates store transacion + DOMStoreReadTransaction storeReadTx = domStore.newReadOnlyTransaction(); + /** + * We verify transaction is commited to store, container should exists + * in datastore. + */ + assertTestContainerExists(storeReadTx); + /** + * We commit third transaction + * + */ + assertThreePhaseCommit(thirdDeleteTxCohort); + } + + @Test + @Ignore + public void testTransactionConflict() throws InterruptedException, ExecutionException { + DOMStoreReadWriteTransaction txOne = domStore.newReadWriteTransaction(); + DOMStoreReadWriteTransaction txTwo = domStore.newReadWriteTransaction(); + assertTestContainerWrite(txOne); + assertTestContainerWrite(txTwo); + + /** + * Commits transaction + */ + assertThreePhaseCommit(txOne.ready()); + + /** + * Asserts that txTwo could not be commited + */ + assertFalse(txTwo.ready().canCommit().get()); + } + + private static void assertThreePhaseCommit(final DOMStoreThreePhaseCommitCohort cohort) + throws InterruptedException, ExecutionException { + assertTrue(cohort.canCommit().get().booleanValue()); + cohort.preCommit().get(); + cohort.commit().get(); + } + + private static Optional> assertTestContainerWrite(final DOMStoreReadWriteTransaction writeTx) + throws InterruptedException, ExecutionException { + /** + * + * Writes /test in writeTx + * + */ + writeTx.write(TestModel.TEST_PATH, ImmutableNodes.containerNode(TestModel.TEST_QNAME)); + + return assertTestContainerExists(writeTx); + } + + /** + * Reads /test from readTx Read should return container. + */ + private static Optional> assertTestContainerExists(final DOMStoreReadTransaction readTx) + throws InterruptedException, ExecutionException { - ListenableFuture>> writeTxContainer = readTx.read(TestModel.TEST_PATH); - assertTrue(writeTxContainer.get().isPresent()); - return writeTxContainer.get(); - } + ListenableFuture>> writeTxContainer = readTx.read(TestModel.TEST_PATH); + assertTrue(writeTxContainer.get().isPresent()); + return writeTxContainer.get(); + } } diff --git a/opendaylight/md-sal/sal-netconf-connector/pom.xml b/opendaylight/md-sal/sal-netconf-connector/pom.xml index 10fe4a587a..049f8c2e3c 100644 --- a/opendaylight/md-sal/sal-netconf-connector/pom.xml +++ b/opendaylight/md-sal/sal-netconf-connector/pom.xml @@ -153,11 +153,6 @@ logback-config test - - org.opendaylight.controller - sal-binding-broker-impl - test - org.opendaylight.controller sal-binding-broker-impl diff --git a/opendaylight/md-sal/sal-netconf-connector/src/main/java/org/opendaylight/controller/config/yang/md/sal/connector/netconf/NetconfConnectorModule.java b/opendaylight/md-sal/sal-netconf-connector/src/main/java/org/opendaylight/controller/config/yang/md/sal/connector/netconf/NetconfConnectorModule.java index 037bfb4a82..b75df80f4e 100644 --- a/opendaylight/md-sal/sal-netconf-connector/src/main/java/org/opendaylight/controller/config/yang/md/sal/connector/netconf/NetconfConnectorModule.java +++ b/opendaylight/md-sal/sal-netconf-connector/src/main/java/org/opendaylight/controller/config/yang/md/sal/connector/netconf/NetconfConnectorModule.java @@ -13,8 +13,10 @@ import static org.opendaylight.controller.config.api.JmxAttributeValidationExcep import java.io.File; import java.io.InputStream; import java.net.InetSocketAddress; +import java.util.List; import java.util.concurrent.ExecutorService; +import org.opendaylight.controller.config.api.JmxAttributeValidationException; import org.opendaylight.controller.netconf.client.NetconfClientDispatcher; import org.opendaylight.controller.netconf.client.conf.NetconfClientConfiguration; import org.opendaylight.controller.netconf.client.conf.NetconfReconnectingClientConfiguration; @@ -24,6 +26,7 @@ import org.opendaylight.controller.sal.binding.api.BindingAwareBroker; import org.opendaylight.controller.sal.connect.api.RemoteDeviceHandler; import org.opendaylight.controller.sal.connect.netconf.NetconfDevice; import org.opendaylight.controller.sal.connect.netconf.listener.NetconfDeviceCommunicator; +import org.opendaylight.controller.sal.connect.netconf.listener.NetconfSessionCapabilities; import org.opendaylight.controller.sal.connect.netconf.sal.NetconfDeviceSalFacade; import org.opendaylight.controller.sal.connect.util.RemoteDeviceId; import org.opendaylight.controller.sal.core.api.Broker; @@ -40,6 +43,8 @@ import org.osgi.framework.BundleContext; import org.slf4j.Logger; import org.slf4j.LoggerFactory; +import com.google.common.base.Optional; + /** * */ @@ -49,6 +54,7 @@ public final class NetconfConnectorModule extends org.opendaylight.controller.co private static AbstractCachingSchemaSourceProvider GLOBAL_NETCONF_SOURCE_PROVIDER = null; private BundleContext bundleContext; + private Optional userCapabilities; public NetconfConnectorModule(final org.opendaylight.controller.config.api.ModuleIdentifier identifier, final org.opendaylight.controller.config.api.DependencyResolver dependencyResolver) { super(identifier, dependencyResolver); @@ -82,9 +88,11 @@ public final class NetconfConnectorModule extends org.opendaylight.controller.co checkNotNull(getPassword(), passwordJmxAttribute); } + userCapabilities = getUserCapabilities(); + } - private boolean isHostAddressPresent(Host address) { + private boolean isHostAddressPresent(final Host address) { return address.getDomainName() != null || address.getIpAddress() != null && (address.getIpAddress().getIpv4Address() != null || address.getIpAddress().getIpv6Address() != null); } @@ -98,10 +106,14 @@ public final class NetconfConnectorModule extends org.opendaylight.controller.co final Broker domBroker = getDomRegistryDependency(); final BindingAwareBroker bindingBroker = getBindingRegistryDependency(); - final RemoteDeviceHandler salFacade = new NetconfDeviceSalFacade(id, domBroker, bindingBroker, bundleContext, globalProcessingExecutor); + final RemoteDeviceHandler salFacade + = new NetconfDeviceSalFacade(id, domBroker, bindingBroker, bundleContext, globalProcessingExecutor); final NetconfDevice device = NetconfDevice.createNetconfDevice(id, getGlobalNetconfSchemaProvider(), globalProcessingExecutor, salFacade); - final NetconfDeviceCommunicator listener = new NetconfDeviceCommunicator(id, device); + + final NetconfDeviceCommunicator listener = userCapabilities.isPresent() ? + new NetconfDeviceCommunicator(id, device, userCapabilities.get()) : new NetconfDeviceCommunicator(id, device); + final NetconfReconnectingClientConfiguration clientConfig = getClientConfig(listener); final NetconfClientDispatcher dispatcher = getClientDispatcherDependency(); @@ -116,6 +128,26 @@ public final class NetconfConnectorModule extends org.opendaylight.controller.co }; } + private Optional getUserCapabilities() { + if(getYangModuleCapabilities() == null) { + return Optional.absent(); + } + + final List capabilities = getYangModuleCapabilities().getCapability(); + if(capabilities == null || capabilities.isEmpty()) { + return Optional.absent(); + } + + final NetconfSessionCapabilities parsedOverrideCapabilities = NetconfSessionCapabilities.fromStrings(capabilities); + JmxAttributeValidationException.checkCondition( + parsedOverrideCapabilities.getNonModuleCaps().isEmpty(), + "Capabilities to override can only contain module based capabilities, non-module capabilities will be retrieved from the device," + + " configured non-module capabilities: " + parsedOverrideCapabilities.getNonModuleCaps(), + yangModuleCapabilitiesJmxAttribute); + + return Optional.of(parsedOverrideCapabilities); + } + private synchronized AbstractCachingSchemaSourceProvider getGlobalNetconfSchemaProvider() { if(GLOBAL_NETCONF_SOURCE_PROVIDER == null) { final String storageFile = "cache/schema"; @@ -175,8 +207,8 @@ public final class NetconfConnectorModule extends org.opendaylight.controller.co if(getAddress().getDomainName() != null) { return new InetSocketAddress(getAddress().getDomainName().getValue(), getPort().getValue()); } else { - IpAddress ipAddress = getAddress().getIpAddress(); - String ip = ipAddress.getIpv4Address() != null ? ipAddress.getIpv4Address().getValue() : ipAddress.getIpv6Address().getValue(); + final IpAddress ipAddress = getAddress().getIpAddress(); + final String ip = ipAddress.getIpv4Address() != null ? ipAddress.getIpv4Address().getValue() : ipAddress.getIpv6Address().getValue(); return new InetSocketAddress(ip, getPort().getValue()); } } diff --git a/opendaylight/md-sal/sal-netconf-connector/src/main/java/org/opendaylight/controller/sal/connect/netconf/NetconfDevice.java b/opendaylight/md-sal/sal-netconf-connector/src/main/java/org/opendaylight/controller/sal/connect/netconf/NetconfDevice.java index de4ac7ac18..07d3c08774 100644 --- a/opendaylight/md-sal/sal-netconf-connector/src/main/java/org/opendaylight/controller/sal/connect/netconf/NetconfDevice.java +++ b/opendaylight/md-sal/sal-netconf-connector/src/main/java/org/opendaylight/controller/sal/connect/netconf/NetconfDevice.java @@ -118,6 +118,7 @@ public final class NetconfDevice implements RemoteDevice { private static final Logger logger = LoggerFactory.getLogger(NetconfDeviceCommunicator.class); private final RemoteDevice remoteDevice; + private final Optional overrideNetconfCapabilities; private final RemoteDeviceId id; private final Lock sessionLock = new ReentrantLock(); + private final Queue requests = new ArrayDeque<>(); + private NetconfClientSession session; + + public NetconfDeviceCommunicator(final RemoteDeviceId id, final RemoteDevice remoteDevice, + final NetconfSessionCapabilities netconfSessionCapabilities) { + this(id, remoteDevice, Optional.of(netconfSessionCapabilities)); + } + public NetconfDeviceCommunicator(final RemoteDeviceId id, - final RemoteDevice remoteDevice) { + final RemoteDevice remoteDevice) { + this(id, remoteDevice, Optional.absent()); + } + + private NetconfDeviceCommunicator(final RemoteDeviceId id, final RemoteDevice remoteDevice, + final Optional overrideNetconfCapabilities) { this.id = id; this.remoteDevice = remoteDevice; + this.overrideNetconfCapabilities = overrideNetconfCapabilities; } - private final Queue requests = new ArrayDeque<>(); - private NetconfClientSession session; - @Override public void onSessionUp(final NetconfClientSession session) { sessionLock.lock(); @@ -68,10 +78,15 @@ public class NetconfDeviceCommunicator implements NetconfClientSessionListener, logger.debug("{}: Session established", id); this.session = session; - final NetconfSessionCapabilities netconfSessionCapabilities = + NetconfSessionCapabilities netconfSessionCapabilities = NetconfSessionCapabilities.fromNetconfSession(session); logger.trace("{}: Session advertised capabilities: {}", id, netconfSessionCapabilities); + if(overrideNetconfCapabilities.isPresent()) { + netconfSessionCapabilities = netconfSessionCapabilities.replaceModuleCaps(overrideNetconfCapabilities.get()); + logger.debug("{}: Session capabilities overridden, capabilities that will be used: {}", id, netconfSessionCapabilities); + } + remoteDevice.onRemoteSessionUp(netconfSessionCapabilities, this); } finally { @@ -223,7 +238,7 @@ public class NetconfDeviceCommunicator implements NetconfClientSessionListener, return; } - request.future.set( RpcResultBuilder.success( message ).build() ); + request.future.set( RpcResultBuilder.success( message ).build() ); } } diff --git a/opendaylight/md-sal/sal-netconf-connector/src/main/java/org/opendaylight/controller/sal/connect/netconf/listener/NetconfSessionCapabilities.java b/opendaylight/md-sal/sal-netconf-connector/src/main/java/org/opendaylight/controller/sal/connect/netconf/listener/NetconfSessionCapabilities.java index 8964a80228..1a7d90e9c0 100644 --- a/opendaylight/md-sal/sal-netconf-connector/src/main/java/org/opendaylight/controller/sal/connect/netconf/listener/NetconfSessionCapabilities.java +++ b/opendaylight/md-sal/sal-netconf-connector/src/main/java/org/opendaylight/controller/sal/connect/netconf/listener/NetconfSessionCapabilities.java @@ -8,6 +8,7 @@ import com.google.common.base.Splitter; import com.google.common.collect.ImmutableSet; import com.google.common.collect.Iterables; +import com.google.common.collect.Sets; import java.util.Collection; import java.util.HashSet; import java.util.Set; @@ -19,6 +20,7 @@ import org.slf4j.Logger; import org.slf4j.LoggerFactory; public final class NetconfSessionCapabilities { + private static final class ParameterMatcher { private final Predicate predicate; private final int skipLength; @@ -57,10 +59,10 @@ public final class NetconfSessionCapabilities { }; private final Set moduleBasedCaps; - private final Set capabilities; + private final Set nonModuleCaps; - private NetconfSessionCapabilities(final Set capabilities, final Set moduleBasedCaps) { - this.capabilities = Preconditions.checkNotNull(capabilities); + private NetconfSessionCapabilities(final Set nonModuleCaps, final Set moduleBasedCaps) { + this.nonModuleCaps = Preconditions.checkNotNull(nonModuleCaps); this.moduleBasedCaps = Preconditions.checkNotNull(moduleBasedCaps); } @@ -68,30 +70,49 @@ public final class NetconfSessionCapabilities { return moduleBasedCaps; } - public boolean containsCapability(final String capability) { - return capabilities.contains(capability); + public Set getNonModuleCaps() { + return nonModuleCaps; + } + + public boolean containsNonModuleCapability(final String capability) { + return nonModuleCaps.contains(capability); } - public boolean containsCapability(final QName capability) { + public boolean containsModuleCapability(final QName capability) { return moduleBasedCaps.contains(capability); } @Override public String toString() { return Objects.toStringHelper(this) - .add("capabilities", capabilities) + .add("capabilities", nonModuleCaps) + .add("moduleBasedCapabilities", moduleBasedCaps) .add("rollback", isRollbackSupported()) .add("monitoring", isMonitoringSupported()) .toString(); } public boolean isRollbackSupported() { - return containsCapability(NetconfMessageTransformUtil.NETCONF_ROLLBACK_ON_ERROR_URI.toString()); + return containsNonModuleCapability(NetconfMessageTransformUtil.NETCONF_ROLLBACK_ON_ERROR_URI.toString()); + } + + public boolean isCandidateSupported() { + return containsNonModuleCapability(NetconfMessageTransformUtil.NETCONF_CANDIDATE_URI.toString()); } public boolean isMonitoringSupported() { - return containsCapability(NetconfMessageTransformUtil.IETF_NETCONF_MONITORING) - || containsCapability(NetconfMessageTransformUtil.IETF_NETCONF_MONITORING.getNamespace().toString()); + return containsModuleCapability(NetconfMessageTransformUtil.IETF_NETCONF_MONITORING) + || containsNonModuleCapability(NetconfMessageTransformUtil.IETF_NETCONF_MONITORING.getNamespace().toString()); + } + + public NetconfSessionCapabilities replaceModuleCaps(final NetconfSessionCapabilities netconfSessionModuleCapabilities) { + final Set moduleBasedCaps = Sets.newHashSet(netconfSessionModuleCapabilities.getModuleBasedCaps()); + + // Preserve monitoring module, since it indicates support for ietf-netconf-monitoring + if(containsModuleCapability(NetconfMessageTransformUtil.IETF_NETCONF_MONITORING)) { + moduleBasedCaps.add(NetconfMessageTransformUtil.IETF_NETCONF_MONITORING); + } + return new NetconfSessionCapabilities(getNonModuleCaps(), moduleBasedCaps); } public static NetconfSessionCapabilities fromNetconfSession(final NetconfClientSession session) { @@ -100,6 +121,7 @@ public final class NetconfSessionCapabilities { public static NetconfSessionCapabilities fromStrings(final Collection capabilities) { final Set moduleBasedCaps = new HashSet<>(); + final Set nonModuleCaps = Sets.newHashSet(capabilities); for (final String capability : capabilities) { final int qmark = capability.indexOf('?'); @@ -117,6 +139,7 @@ public final class NetconfSessionCapabilities { String revision = REVISION_PARAM.from(queryParams); if (revision != null) { moduleBasedCaps.add(QName.create(namespace, revision, moduleName)); + nonModuleCaps.remove(capability); continue; } @@ -136,8 +159,9 @@ public final class NetconfSessionCapabilities { // FIXME: do we really want to continue here? moduleBasedCaps.add(QName.create(namespace, revision, moduleName)); + nonModuleCaps.remove(capability); } - return new NetconfSessionCapabilities(ImmutableSet.copyOf(capabilities), ImmutableSet.copyOf(moduleBasedCaps)); + return new NetconfSessionCapabilities(ImmutableSet.copyOf(nonModuleCaps), ImmutableSet.copyOf(moduleBasedCaps)); } } diff --git a/opendaylight/md-sal/sal-netconf-connector/src/main/java/org/opendaylight/controller/sal/connect/netconf/sal/NetconfDeviceDataBroker.java b/opendaylight/md-sal/sal-netconf-connector/src/main/java/org/opendaylight/controller/sal/connect/netconf/sal/NetconfDeviceDataBroker.java index ee0c8b7217..f3a9acd630 100644 --- a/opendaylight/md-sal/sal-netconf-connector/src/main/java/org/opendaylight/controller/sal/connect/netconf/sal/NetconfDeviceDataBroker.java +++ b/opendaylight/md-sal/sal-netconf-connector/src/main/java/org/opendaylight/controller/sal/connect/netconf/sal/NetconfDeviceDataBroker.java @@ -42,7 +42,7 @@ final class NetconfDeviceDataBroker implements DOMDataBroker { @Override public DOMDataReadOnlyTransaction newReadOnlyTransaction() { - return new NetconfDeviceReadOnlyTx(rpc, normalizer); + return new NetconfDeviceReadOnlyTx(rpc, normalizer, id); } @Override @@ -52,8 +52,7 @@ final class NetconfDeviceDataBroker implements DOMDataBroker { @Override public DOMDataWriteTransaction newWriteOnlyTransaction() { - // FIXME detect if candidate is supported, true is hardcoded - return new NetconfDeviceWriteOnlyTx(id, rpc, normalizer, true, netconfSessionPreferences.isRollbackSupported()); + return new NetconfDeviceWriteOnlyTx(id, rpc, normalizer, netconfSessionPreferences.isCandidateSupported(), netconfSessionPreferences.isRollbackSupported()); } @Override diff --git a/opendaylight/md-sal/sal-netconf-connector/src/main/java/org/opendaylight/controller/sal/connect/netconf/sal/tx/NetconfDeviceReadOnlyTx.java b/opendaylight/md-sal/sal-netconf-connector/src/main/java/org/opendaylight/controller/sal/connect/netconf/sal/tx/NetconfDeviceReadOnlyTx.java index 3248453baf..533df9cce7 100644 --- a/opendaylight/md-sal/sal-netconf-connector/src/main/java/org/opendaylight/controller/sal/connect/netconf/sal/tx/NetconfDeviceReadOnlyTx.java +++ b/opendaylight/md-sal/sal-netconf-connector/src/main/java/org/opendaylight/controller/sal/connect/netconf/sal/tx/NetconfDeviceReadOnlyTx.java @@ -15,42 +15,53 @@ import static org.opendaylight.controller.sal.connect.netconf.util.NetconfMessag 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.ListenableFuture; import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType; +import org.opendaylight.controller.md.sal.common.api.data.ReadFailedException; 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.DOMDataReadOnlyTransaction; import org.opendaylight.controller.sal.connect.netconf.util.NetconfMessageTransformUtil; +import org.opendaylight.controller.sal.connect.util.RemoteDeviceId; import org.opendaylight.controller.sal.core.api.RpcImplementation; +import org.opendaylight.yangtools.util.concurrent.MappingCheckedFuture; import org.opendaylight.yangtools.yang.common.RpcResult; import org.opendaylight.yangtools.yang.data.api.CompositeNode; -import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier; import org.opendaylight.yangtools.yang.data.api.Node; import org.opendaylight.yangtools.yang.data.api.SimpleNode; +import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier; import org.opendaylight.yangtools.yang.data.api.schema.NormalizedNode; import org.slf4j.Logger; import org.slf4j.LoggerFactory; + public final class NetconfDeviceReadOnlyTx implements DOMDataReadOnlyTransaction { private static final Logger LOG = LoggerFactory.getLogger(NetconfDeviceReadOnlyTx.class); private final RpcImplementation rpc; private final DataNormalizer normalizer; + private final RemoteDeviceId id; - public NetconfDeviceReadOnlyTx(final RpcImplementation rpc, final DataNormalizer normalizer) { + public NetconfDeviceReadOnlyTx(final RpcImplementation rpc, final DataNormalizer normalizer, final RemoteDeviceId id) { this.rpc = rpc; this.normalizer = normalizer; + this.id = id; } - public ListenableFuture>> readConfigurationData(final YangInstanceIdentifier path) { + private CheckedFuture>, ReadFailedException> readConfigurationData( + final YangInstanceIdentifier path) { final ListenableFuture> future = rpc.invokeRpc(NETCONF_GET_CONFIG_QNAME, NetconfMessageTransformUtil.wrap(NETCONF_GET_CONFIG_QNAME, CONFIG_SOURCE_RUNNING, toFilterStructure(path))); - return Futures.transform(future, new Function, Optional>>() { + ListenableFuture>> transformedFuture = Futures.transform(future, new Function, Optional>>() { @Override public Optional> apply(final RpcResult result) { + checkReadSuccess(result, path); + final CompositeNode data = result.getResult().getFirstCompositeByName(NETCONF_DATA_QNAME); final CompositeNode node = (CompositeNode) findNode(data, path); @@ -59,6 +70,17 @@ public final class NetconfDeviceReadOnlyTx implements DOMDataReadOnlyTransaction transform(path, node); } }); + + return MappingCheckedFuture.create(transformedFuture, ReadFailedException.MAPPER); + } + + private void checkReadSuccess(final RpcResult result, final YangInstanceIdentifier path) { + try { + Preconditions.checkArgument(result.isSuccessful(), "%s: Unable to read data: %s, errors: %s", id, path, result.getErrors()); + } catch (IllegalArgumentException e) { + LOG.warn("{}: Unable to read data: {}, errors: {}", id, path, result.getErrors()); + throw e; + } } private Optional> transform(final YangInstanceIdentifier path, final CompositeNode node) { @@ -68,17 +90,20 @@ public final class NetconfDeviceReadOnlyTx implements DOMDataReadOnlyTransaction try { return Optional.>of(normalizer.toNormalized(path, node).getValue()); } catch (final Exception e) { - LOG.error("Unable to normalize data for {}, data: {}", path, node, e); + LOG.error("{}: Unable to normalize data for {}, data: {}", id, path, node, e); throw e; } } - public ListenableFuture>> readOperationalData(final YangInstanceIdentifier path) { + private CheckedFuture>, ReadFailedException> readOperationalData( + final YangInstanceIdentifier path) { final ListenableFuture> future = rpc.invokeRpc(NETCONF_GET_QNAME, NetconfMessageTransformUtil.wrap(NETCONF_GET_QNAME, toFilterStructure(path))); - return Futures.transform(future, new Function, Optional>>() { + ListenableFuture>> transformedFuture = Futures.transform(future, new Function, Optional>>() { @Override public Optional> apply(final RpcResult result) { + checkReadSuccess(result, path); + final CompositeNode data = result.getResult().getFirstCompositeByName(NETCONF_DATA_QNAME); final CompositeNode node = (CompositeNode) findNode(data, path); @@ -87,6 +112,8 @@ public final class NetconfDeviceReadOnlyTx implements DOMDataReadOnlyTransaction transform(path, node); } }); + + return MappingCheckedFuture.create(transformedFuture, ReadFailedException.MAPPER); } private static Node findNode(final CompositeNode node, final YangInstanceIdentifier identifier) { @@ -122,8 +149,9 @@ public final class NetconfDeviceReadOnlyTx implements DOMDataReadOnlyTransaction } @Override - public ListenableFuture>> read(final LogicalDatastoreType store, final YangInstanceIdentifier path) { - final YangInstanceIdentifier legacyPath = toLegacyPath(normalizer, path); + public CheckedFuture>, ReadFailedException> read( + final LogicalDatastoreType store, final YangInstanceIdentifier path) { + final YangInstanceIdentifier legacyPath = toLegacyPath(normalizer, path, id); switch (store) { case CONFIGURATION : { @@ -134,14 +162,14 @@ public final class NetconfDeviceReadOnlyTx implements DOMDataReadOnlyTransaction } } - throw new IllegalArgumentException(String.format("Cannot read data %s for %s datastore, unknown datastore type", path, store)); + throw new IllegalArgumentException(String.format("%s, Cannot read data %s for %s datastore, unknown datastore type", id, path, store)); } - static YangInstanceIdentifier toLegacyPath(final DataNormalizer normalizer, final YangInstanceIdentifier path) { + static YangInstanceIdentifier toLegacyPath(final DataNormalizer normalizer, final YangInstanceIdentifier path, final RemoteDeviceId id) { try { return normalizer.toLegacy(path); } catch (final DataNormalizationException e) { - throw new IllegalArgumentException("Cannot normalize path " + path, e); + throw new IllegalArgumentException(id + ": Cannot normalize path " + path, e); } } diff --git a/opendaylight/md-sal/sal-netconf-connector/src/main/java/org/opendaylight/controller/sal/connect/netconf/sal/tx/NetconfDeviceReadWriteTx.java b/opendaylight/md-sal/sal-netconf-connector/src/main/java/org/opendaylight/controller/sal/connect/netconf/sal/tx/NetconfDeviceReadWriteTx.java index 4054cf9403..3d2c3b9d44 100644 --- a/opendaylight/md-sal/sal-netconf-connector/src/main/java/org/opendaylight/controller/sal/connect/netconf/sal/tx/NetconfDeviceReadWriteTx.java +++ b/opendaylight/md-sal/sal-netconf-connector/src/main/java/org/opendaylight/controller/sal/connect/netconf/sal/tx/NetconfDeviceReadWriteTx.java @@ -11,8 +11,10 @@ package org.opendaylight.controller.sal.connect.netconf.sal.tx; import com.google.common.base.Optional; import com.google.common.util.concurrent.CheckedFuture; import com.google.common.util.concurrent.ListenableFuture; + 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.api.data.ReadFailedException; import org.opendaylight.controller.md.sal.common.api.data.TransactionCommitFailedException; import org.opendaylight.controller.md.sal.dom.api.DOMDataReadTransaction; import org.opendaylight.controller.md.sal.dom.api.DOMDataReadWriteTransaction; @@ -62,7 +64,8 @@ public class NetconfDeviceReadWriteTx implements DOMDataReadWriteTransaction { } @Override - public ListenableFuture>> read(final LogicalDatastoreType store, final YangInstanceIdentifier path) { + public CheckedFuture>, ReadFailedException> read( + final LogicalDatastoreType store, final YangInstanceIdentifier path) { return delegateReadTx.read(store, path); } diff --git a/opendaylight/md-sal/sal-netconf-connector/src/main/java/org/opendaylight/controller/sal/connect/netconf/sal/tx/NetconfDeviceWriteOnlyTx.java b/opendaylight/md-sal/sal-netconf-connector/src/main/java/org/opendaylight/controller/sal/connect/netconf/sal/tx/NetconfDeviceWriteOnlyTx.java index c8d9028210..87f5477d35 100644 --- a/opendaylight/md-sal/sal-netconf-connector/src/main/java/org/opendaylight/controller/sal/connect/netconf/sal/tx/NetconfDeviceWriteOnlyTx.java +++ b/opendaylight/md-sal/sal-netconf-connector/src/main/java/org/opendaylight/controller/sal/connect/netconf/sal/tx/NetconfDeviceWriteOnlyTx.java @@ -8,10 +8,11 @@ package org.opendaylight.controller.sal.connect.netconf.sal.tx; +import static org.opendaylight.controller.sal.connect.netconf.util.NetconfMessageTransformUtil.DISCARD_CHANGES_RPC_CONTENT; import static org.opendaylight.controller.sal.connect.netconf.util.NetconfMessageTransformUtil.NETCONF_CANDIDATE_QNAME; -import static org.opendaylight.controller.sal.connect.netconf.util.NetconfMessageTransformUtil.NETCONF_COMMIT_QNAME; import static org.opendaylight.controller.sal.connect.netconf.util.NetconfMessageTransformUtil.NETCONF_CONFIG_QNAME; import static org.opendaylight.controller.sal.connect.netconf.util.NetconfMessageTransformUtil.NETCONF_DEFAULT_OPERATION_QNAME; +import static org.opendaylight.controller.sal.connect.netconf.util.NetconfMessageTransformUtil.NETCONF_DISCARD_CHANGES_QNAME; import static org.opendaylight.controller.sal.connect.netconf.util.NetconfMessageTransformUtil.NETCONF_EDIT_CONFIG_QNAME; import static org.opendaylight.controller.sal.connect.netconf.util.NetconfMessageTransformUtil.NETCONF_ERROR_OPTION_QNAME; import static org.opendaylight.controller.sal.connect.netconf.util.NetconfMessageTransformUtil.NETCONF_OPERATION_QNAME; @@ -26,13 +27,14 @@ import com.google.common.collect.ImmutableList; import com.google.common.collect.Iterables; import com.google.common.collect.Lists; import com.google.common.util.concurrent.CheckedFuture; +import com.google.common.util.concurrent.FutureCallback; import com.google.common.util.concurrent.Futures; import com.google.common.util.concurrent.ListenableFuture; import java.util.Collections; import java.util.List; import java.util.Map; import java.util.concurrent.ExecutionException; -import javax.annotation.Nullable; +import java.util.concurrent.atomic.AtomicBoolean; 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.api.data.TransactionCommitFailedException; @@ -57,97 +59,114 @@ import org.opendaylight.yangtools.yang.data.impl.util.CompositeNodeBuilder; import org.slf4j.Logger; import org.slf4j.LoggerFactory; -public class NetconfDeviceWriteOnlyTx implements DOMDataWriteTransaction { +public class NetconfDeviceWriteOnlyTx implements DOMDataWriteTransaction, FutureCallback> { private static final Logger LOG = LoggerFactory.getLogger(NetconfDeviceWriteOnlyTx.class); private final RemoteDeviceId id; private final RpcImplementation rpc; private final DataNormalizer normalizer; + private final boolean rollbackSupported; + private final boolean candidateSupported; private final CompositeNode targetNode; + // Allow commit to be called only once + private final AtomicBoolean finished = new AtomicBoolean(false); + public NetconfDeviceWriteOnlyTx(final RemoteDeviceId id, final RpcImplementation rpc, final DataNormalizer normalizer, final boolean candidateSupported, final boolean rollbackOnErrorSupported) { this.id = id; this.rpc = rpc; this.normalizer = normalizer; - this.targetNode = getTargetNode(candidateSupported); + + this.candidateSupported = candidateSupported; + this.targetNode = getTargetNode(this.candidateSupported); this.rollbackSupported = rollbackOnErrorSupported; } - // FIXME add logging - @Override public boolean cancel() { - if(isCommitted()) { + if(isFinished()) { return false; } return discardChanges(); } - private boolean isCommitted() { - // TODO 732 - return true; + private boolean isFinished() { + return finished.get(); } private boolean discardChanges() { - // TODO 732 + finished.set(true); + + if(candidateSupported) { + sendDiscardChanges(); + } return true; } // TODO should the edit operations be blocking ? + // TODO should the discard-changes operations be blocking ? @Override public void put(final LogicalDatastoreType store, final YangInstanceIdentifier path, final NormalizedNode data) { + checkNotFinished(); Preconditions.checkArgument(store == LogicalDatastoreType.CONFIGURATION, "Can merge only configuration, not %s", store); try { - final YangInstanceIdentifier legacyPath = NetconfDeviceReadOnlyTx.toLegacyPath(normalizer, path); + final YangInstanceIdentifier legacyPath = NetconfDeviceReadOnlyTx.toLegacyPath(normalizer, path, id); final CompositeNode legacyData = normalizer.toLegacy(path, data); - sendEditRpc(createEditConfigStructure(legacyPath, Optional.of(ModifyAction.REPLACE), Optional.fromNullable(legacyData)), Optional.of(ModifyAction.NONE)); + sendEditRpc( + createEditConfigStructure(legacyPath, Optional.of(ModifyAction.REPLACE), Optional.fromNullable(legacyData)), Optional.of(ModifyAction.NONE)); } catch (final ExecutionException e) { - LOG.warn("Error putting data to {}, data: {}, discarding changes", path, data, e); + LOG.warn("{}: Error putting data to {}, data: {}, discarding changes", id, path, data, e); discardChanges(); - throw new RuntimeException("Error while replacing " + path, e); + throw new RuntimeException(id + ": Error while replacing " + path, e); } } + private void checkNotFinished() { + Preconditions.checkState(isFinished() == false, "%s: Transaction %s already finished", id, getIdentifier()); + } + @Override public void merge(final LogicalDatastoreType store, final YangInstanceIdentifier path, final NormalizedNode data) { - Preconditions.checkArgument(store == LogicalDatastoreType.CONFIGURATION, "Can merge only configuration, not %s", store); + checkNotFinished(); + Preconditions.checkArgument(store == LogicalDatastoreType.CONFIGURATION, "%s: Can merge only configuration, not %s", id, store); try { - final YangInstanceIdentifier legacyPath = NetconfDeviceReadOnlyTx.toLegacyPath(normalizer, path); + final YangInstanceIdentifier legacyPath = NetconfDeviceReadOnlyTx.toLegacyPath(normalizer, path, id); final CompositeNode legacyData = normalizer.toLegacy(path, data); sendEditRpc( createEditConfigStructure(legacyPath, Optional. absent(), Optional.fromNullable(legacyData)), Optional. absent()); } catch (final ExecutionException e) { - LOG.warn("Error merging data to {}, data: {}, discarding changes", path, data, e); + LOG.warn("{}: Error merging data to {}, data: {}, discarding changes", id, path, data, e); discardChanges(); - throw new RuntimeException("Error while merging " + path, e); + throw new RuntimeException(id + ": Error while merging " + path, e); } } @Override public void delete(final LogicalDatastoreType store, final YangInstanceIdentifier path) { - Preconditions.checkArgument(store == LogicalDatastoreType.CONFIGURATION, "Can merge only configuration, not %s", store); + checkNotFinished(); + Preconditions.checkArgument(store == LogicalDatastoreType.CONFIGURATION, "%s: Can merge only configuration, not %s", id, store); try { - sendEditRpc(createEditConfigStructure(NetconfDeviceReadOnlyTx.toLegacyPath(normalizer, path), Optional.of(ModifyAction.DELETE), Optional.absent()), Optional.of(ModifyAction.NONE)); + sendEditRpc( + createEditConfigStructure(NetconfDeviceReadOnlyTx.toLegacyPath(normalizer, path, id), Optional.of(ModifyAction.DELETE), Optional.absent()), Optional.of(ModifyAction.NONE)); } catch (final ExecutionException e) { - LOG.warn("Error deleting data {}, discarding changes", path, e); + LOG.warn("{}: Error deleting data {}, discarding changes", id, path, e); discardChanges(); - throw new RuntimeException("Error while deleting " + path, e); + throw new RuntimeException(id + ": Error while deleting " + path, e); } } @Override public CheckedFuture submit() { final ListenableFuture commmitFutureAsVoid = Futures.transform(commit(), new Function, Void>() { - @Nullable @Override - public Void apply(@Nullable final RpcResult input) { + public Void apply(final RpcResult input) { return null; } }); @@ -162,25 +181,46 @@ public class NetconfDeviceWriteOnlyTx implements DOMDataWriteTransaction { @Override public ListenableFuture> commit() { - // FIXME do not allow commit if closed or failed + checkNotFinished(); + finished.set(true); - final ListenableFuture> rpcResult = rpc.invokeRpc(NetconfMessageTransformUtil.NETCONF_COMMIT_QNAME, getCommitRequest()); - return Futures.transform(rpcResult, new Function, RpcResult>() { - @Override - public RpcResult apply(@Nullable final RpcResult input) { - if(input.isSuccessful()) { - return RpcResultBuilder.success(TransactionStatus.COMMITED).build(); - } else { - final RpcResultBuilder failed = RpcResultBuilder.failed(); - for (final RpcError rpcError : input.getErrors()) { - failed.withError(rpcError.getErrorType(), rpcError.getTag(), rpcError.getMessage(), rpcError.getApplicationTag(), rpcError.getInfo(), rpcError.getCause()); + if(candidateSupported == false) { + return Futures.immediateFuture(RpcResultBuilder.success(TransactionStatus.COMMITED).build()); + } + + final ListenableFuture> rpcResult = rpc.invokeRpc( + NetconfMessageTransformUtil.NETCONF_COMMIT_QNAME, NetconfMessageTransformUtil.COMMIT_RPC_CONTENT); + + final ListenableFuture> transformed = Futures.transform(rpcResult, + new Function, RpcResult>() { + @Override + public RpcResult apply(final RpcResult input) { + if (input.isSuccessful()) { + return RpcResultBuilder.success(TransactionStatus.COMMITED).build(); + } else { + final RpcResultBuilder failed = RpcResultBuilder.failed(); + for (final RpcError rpcError : input.getErrors()) { + failed.withError(rpcError.getErrorType(), rpcError.getTag(), rpcError.getMessage(), + rpcError.getApplicationTag(), rpcError.getInfo(), rpcError.getCause()); + } + return failed.build(); + } } - return failed.build(); - } - } - }); + }); - // FIXME 732 detect commit failure + Futures.addCallback(transformed, this); + return transformed; + } + + @Override + public void onSuccess(final RpcResult result) { + LOG.debug("{}: Write successful, transaction: {}", id, getIdentifier()); + } + + @Override + public void onFailure(final Throwable t) { + LOG.warn("{}: Write failed, transaction {}, discarding changes", id, getIdentifier(), t); + discardChanges(); } private void sendEditRpc(final CompositeNode editStructure, final Optional defaultOperation) throws ExecutionException { @@ -200,6 +240,22 @@ public class NetconfDeviceWriteOnlyTx implements DOMDataWriteTransaction { } } + private void sendDiscardChanges() { + final ListenableFuture> discardFuture = rpc.invokeRpc(NETCONF_DISCARD_CHANGES_QNAME, DISCARD_CHANGES_RPC_CONTENT); + Futures.addCallback(discardFuture, new FutureCallback>() { + @Override + public void onSuccess(final RpcResult result) { + LOG.debug("{}: Discarding transaction: {}", id, getIdentifier()); + } + + @Override + public void onFailure(final Throwable t) { + LOG.error("{}: Discarding changes failed, transaction: {}. Device configuration might be corrupted", id, getIdentifier(), t); + throw new RuntimeException(id + ": Discarding changes failed, transaction " + getIdentifier(), t); + } + }); + } + private CompositeNode createEditConfigStructure(final YangInstanceIdentifier dataPath, final Optional operation, final Optional lastChildOverride) { Preconditions.checkArgument(Iterables.isEmpty(dataPath.getPathArguments()) == false, "Instance identifier with empty path %s", dataPath); @@ -298,13 +354,6 @@ public class NetconfDeviceWriteOnlyTx implements DOMDataWriteTransaction { } } - private ImmutableCompositeNode getCommitRequest() { - final CompositeNodeBuilder commitInput = ImmutableCompositeNode.builder(); - commitInput.setQName(NETCONF_COMMIT_QNAME); - return commitInput.toInstance(); - } - - @Override public Object getIdentifier() { return this; diff --git a/opendaylight/md-sal/sal-netconf-connector/src/main/java/org/opendaylight/controller/sal/connect/netconf/schema/mapping/NetconfMessageTransformer.java b/opendaylight/md-sal/sal-netconf-connector/src/main/java/org/opendaylight/controller/sal/connect/netconf/schema/mapping/NetconfMessageTransformer.java index 80d0f67ac4..47ef9039d1 100644 --- a/opendaylight/md-sal/sal-netconf-connector/src/main/java/org/opendaylight/controller/sal/connect/netconf/schema/mapping/NetconfMessageTransformer.java +++ b/opendaylight/md-sal/sal-netconf-connector/src/main/java/org/opendaylight/controller/sal/connect/netconf/schema/mapping/NetconfMessageTransformer.java @@ -70,10 +70,15 @@ public class NetconfMessageTransformer implements MessageTransformer toRpcResult(final NetconfMessage message, final QName rpc, final SchemaContext context) { final CompositeNode compositeNode; - if (NetconfMessageTransformUtil.isDataRetrievalOperation(rpc)) { - final Element xmlData = NetconfMessageTransformUtil.getDataSubtree(message.getDocument()); - final List> dataNodes = XmlDocumentUtils.toDomNodes(xmlData, Optional.of(context.getDataDefinitions()), context); final CompositeNodeBuilder it = ImmutableCompositeNode.builder(); it.setQName(NetconfMessageTransformUtil.NETCONF_RPC_REPLY_QNAME); it.add(ImmutableCompositeNode.create(NetconfMessageTransformUtil.NETCONF_DATA_QNAME, dataNodes)); - compositeNode = it.toInstance(); } else { - // TODO map rpc with schema - compositeNode = (CompositeNode) XmlDocumentUtils.toDomNode(message.getDocument()); + final CompositeNode rpcReply = XmlDocumentUtils.rpcReplyToDomNodes(message.getDocument(), rpc, context); + if (rpcReply != null) { + compositeNode = rpcReply; + } else { + compositeNode = (CompositeNode) XmlDocumentUtils.toDomNode(message.getDocument()); + } } - return RpcResultBuilder.success( compositeNode ).build(); } diff --git a/opendaylight/md-sal/sal-netconf-connector/src/main/java/org/opendaylight/controller/sal/connect/netconf/util/NetconfMessageTransformUtil.java b/opendaylight/md-sal/sal-netconf-connector/src/main/java/org/opendaylight/controller/sal/connect/netconf/util/NetconfMessageTransformUtil.java index a6924d9d37..4f792a0a71 100644 --- a/opendaylight/md-sal/sal-netconf-connector/src/main/java/org/opendaylight/controller/sal/connect/netconf/util/NetconfMessageTransformUtil.java +++ b/opendaylight/md-sal/sal-netconf-connector/src/main/java/org/opendaylight/controller/sal/connect/netconf/util/NetconfMessageTransformUtil.java @@ -7,6 +7,7 @@ */ package org.opendaylight.controller.sal.connect.netconf.util; +import com.google.common.base.Preconditions; import com.google.common.base.Predicate; import com.google.common.collect.Collections2; import com.google.common.collect.ImmutableList; @@ -35,6 +36,7 @@ import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier; import org.opendaylight.yangtools.yang.data.api.Node; import org.opendaylight.yangtools.yang.data.impl.CompositeNodeTOImpl; import org.opendaylight.yangtools.yang.data.impl.ImmutableCompositeNode; +import org.opendaylight.yangtools.yang.data.impl.NodeFactory; import org.opendaylight.yangtools.yang.data.impl.SimpleNodeTOImpl; import org.opendaylight.yangtools.yang.data.impl.util.CompositeNodeBuilder; import org.opendaylight.yangtools.yang.model.api.DataNodeContainer; @@ -45,8 +47,7 @@ import org.w3c.dom.Element; public class NetconfMessageTransformUtil { - private NetconfMessageTransformUtil() { - } + private NetconfMessageTransformUtil() {} public static final QName IETF_NETCONF_MONITORING = QName.create("urn:ietf:params:xml:ns:yang:ietf-netconf-monitoring", "2010-10-04", "ietf-netconf-monitoring"); public static URI NETCONF_URI = URI.create("urn:ietf:params:xml:ns:netconf:base:1.0"); @@ -66,14 +67,27 @@ public class NetconfMessageTransformUtil { public static QName NETCONF_DEFAULT_OPERATION_QNAME = QName.create(NETCONF_OPERATION_QNAME, "default-operation"); public static QName NETCONF_EDIT_CONFIG_QNAME = QName.create(NETCONF_QNAME, "edit-config"); public static QName NETCONF_GET_CONFIG_QNAME = QName.create(NETCONF_QNAME, "get-config"); + public static QName NETCONF_DISCARD_CHANGES_QNAME = QName.create(NETCONF_QNAME, "discard-changes"); public static QName NETCONF_TYPE_QNAME = QName.create(NETCONF_QNAME, "type"); public static QName NETCONF_FILTER_QNAME = QName.create(NETCONF_QNAME, "filter"); public static QName NETCONF_GET_QNAME = QName.create(NETCONF_QNAME, "get"); public static QName NETCONF_RPC_QNAME = QName.create(NETCONF_QNAME, "rpc"); + public static URI NETCONF_ROLLBACK_ON_ERROR_URI = URI .create("urn:ietf:params:netconf:capability:rollback-on-error:1.0"); public static String ROLLBACK_ON_ERROR_OPTION = "rollback-on-error"; + public static URI NETCONF_CANDIDATE_URI = URI + .create("urn:ietf:params:netconf:capability:candidate:1.0"); + + // Discard changes message + public static final CompositeNode DISCARD_CHANGES_RPC_CONTENT = + NodeFactory.createImmutableCompositeNode(NETCONF_DISCARD_CHANGES_QNAME, null, Collections.>emptyList()); + + // Commit changes message + public static final CompositeNode COMMIT_RPC_CONTENT = + NodeFactory.createImmutableCompositeNode(NETCONF_COMMIT_QNAME, null, Collections.>emptyList()); + public static Node toFilterStructure(final YangInstanceIdentifier identifier) { Node previous = null; if (Iterables.isEmpty(identifier.getPathArguments())) { @@ -213,6 +227,14 @@ public class NetconfMessageTransformUtil { NETCONF_GET_QNAME.getLocalName())); } + public static boolean isGetOperation(final QName rpc) { + return NETCONF_URI.equals(rpc.getNamespace()) && rpc.getLocalName().equals(NETCONF_GET_QNAME.getLocalName()); + } + + public static boolean isGetConfigOperation(final QName rpc) { + return NETCONF_URI.equals(rpc.getNamespace()) && rpc.getLocalName().equals(NETCONF_GET_CONFIG_QNAME.getLocalName()); + } + public static boolean isDataEditOperation(final QName rpc) { return NETCONF_URI.equals(rpc.getNamespace()) && rpc.getLocalName().equals(NETCONF_EDIT_CONFIG_QNAME.getLocalName()); @@ -243,6 +265,80 @@ public class NetconfMessageTransformUtil { return new NodeContainerProxy(NETCONF_RPC_QNAME, Sets.newHashSet(editConfigProxy)); } + /** + * Creates artificial schema node for edit-config rpc. This artificial schema looks like: + *
      +     * {@code
      +     * rpc
      +     *   get
      +     *     filter
      +     *         // All schema nodes from remote schema
      +     *     filter
      +     *   get
      +     * rpc
      +     * }
      +     * 
      + * + * This makes the translation of rpc get request(especially the config node) + * to xml use schema which is crucial for some types of nodes e.g. identity-ref. + */ + public static DataNodeContainer createSchemaForGet(final SchemaContext schemaContext) { + final QName filter = QName.create(NETCONF_GET_QNAME, "filter"); + final QName get = QName.create(NETCONF_GET_QNAME, "get"); + final NodeContainerProxy configProxy = new NodeContainerProxy(filter, schemaContext.getChildNodes()); + final NodeContainerProxy editConfigProxy = new NodeContainerProxy(get, Sets.newHashSet(configProxy)); + return new NodeContainerProxy(NETCONF_RPC_QNAME, Sets.newHashSet(editConfigProxy)); + } + + /** + * Creates artificial schema node for get rpc. This artificial schema looks like: + *
      +     * {@code
      +     * rpc
      +     *   get-config
      +     *     filter
      +     *         // All schema nodes from remote schema
      +     *     filter
      +     *   get-config
      +     * rpc
      +     * }
      +     * 
      + * + * This makes the translation of rpc get-config request(especially the config node) + * to xml use schema which is crucial for some types of nodes e.g. identity-ref. + */ + public static DataNodeContainer createSchemaForGetConfig(final SchemaContext schemaContext) { + final QName filter = QName.create(NETCONF_GET_CONFIG_QNAME, "filter"); + final QName getConfig = QName.create(NETCONF_GET_CONFIG_QNAME, "get-config"); + final NodeContainerProxy configProxy = new NodeContainerProxy(filter, schemaContext.getChildNodes()); + final NodeContainerProxy editConfigProxy = new NodeContainerProxy(getConfig, Sets.newHashSet(configProxy)); + return new NodeContainerProxy(NETCONF_RPC_QNAME, Sets.newHashSet(editConfigProxy)); + } + + /** + * Creates artificial schema node for schema defined rpc. This artificial schema looks like: + *
      +     * {@code
      +     * rpc
      +     *   rpc-name
      +     *      // All schema nodes from remote schema
      +     *   rpc-name
      +     * rpc
      +     * }
      +     * 
      + * + * This makes the translation of schema defined rpc request + * to xml use schema which is crucial for some types of nodes e.g. identity-ref. + */ + public static DataNodeContainer createSchemaForRpc(final QName rpcName, final SchemaContext schemaContext) { + Preconditions.checkNotNull(rpcName); + Preconditions.checkNotNull(schemaContext); + + final NodeContainerProxy rpcBodyProxy = new NodeContainerProxy(rpcName, schemaContext.getChildNodes()); + return new NodeContainerProxy(NETCONF_RPC_QNAME, Sets.newHashSet(rpcBodyProxy)); + + } + public static CompositeNodeTOImpl wrap(final QName name, final Node node) { if (node != null) { return new CompositeNodeTOImpl(name, null, Collections.> singletonList(node)); @@ -269,5 +365,4 @@ public class NetconfMessageTransformUtil { return it.toInstance(); } } - } diff --git a/opendaylight/md-sal/sal-netconf-connector/src/main/yang/odl-sal-netconf-connector-cfg.yang b/opendaylight/md-sal/sal-netconf-connector/src/main/yang/odl-sal-netconf-connector-cfg.yang index 6bad4798c2..e13398b1df 100644 --- a/opendaylight/md-sal/sal-netconf-connector/src/main/yang/odl-sal-netconf-connector-cfg.yang +++ b/opendaylight/md-sal/sal-netconf-connector/src/main/yang/odl-sal-netconf-connector-cfg.yang @@ -58,6 +58,14 @@ module odl-sal-netconf-connector-cfg { type string; } + container yang-module-capabilities { + leaf-list capability { + type string; + description "Set a list of capabilities to override capabilities provided in device's hello message. + Can be used for devices that do not report any yang modules in their hello message"; + } + } + container dom-registry { uses config:service-ref { refine type { diff --git a/opendaylight/md-sal/sal-netconf-connector/src/test/java/org/opendaylight/controller/sal/connect/netconf/NetconfToNotificationTest.java b/opendaylight/md-sal/sal-netconf-connector/src/test/java/org/opendaylight/controller/sal/connect/netconf/NetconfToNotificationTest.java index 521a55df68..127b0cbfcd 100644 --- a/opendaylight/md-sal/sal-netconf-connector/src/test/java/org/opendaylight/controller/sal/connect/netconf/NetconfToNotificationTest.java +++ b/opendaylight/md-sal/sal-netconf-connector/src/test/java/org/opendaylight/controller/sal/connect/netconf/NetconfToNotificationTest.java @@ -31,6 +31,7 @@ public class NetconfToNotificationTest { NetconfMessage userNotification; + @SuppressWarnings("deprecation") @Before public void setup() throws Exception { final List modelsToParse = Collections.singletonList(getClass().getResourceAsStream("/schemas/user-notification.yang")); diff --git a/opendaylight/md-sal/sal-netconf-connector/src/test/java/org/opendaylight/controller/sal/connect/netconf/NetconfToRpcRequestTest.java b/opendaylight/md-sal/sal-netconf-connector/src/test/java/org/opendaylight/controller/sal/connect/netconf/NetconfToRpcRequestTest.java index 18a3b9f0ff..e744e11bc9 100644 --- a/opendaylight/md-sal/sal-netconf-connector/src/test/java/org/opendaylight/controller/sal/connect/netconf/NetconfToRpcRequestTest.java +++ b/opendaylight/md-sal/sal-netconf-connector/src/test/java/org/opendaylight/controller/sal/connect/netconf/NetconfToRpcRequestTest.java @@ -9,7 +9,7 @@ import java.util.Collections; import java.util.List; import java.util.Set; -import org.junit.Before; +import org.junit.BeforeClass; import org.junit.Test; import org.opendaylight.controller.netconf.api.NetconfMessage; import org.opendaylight.controller.sal.connect.netconf.schema.mapping.NetconfMessageTransformer; @@ -22,6 +22,8 @@ import org.opendaylight.yangtools.yang.model.api.Module; import org.opendaylight.yangtools.yang.model.api.SchemaContext; import org.opendaylight.yangtools.yang.model.parser.api.YangContextParser; import org.opendaylight.yangtools.yang.parser.impl.YangParserImpl; +import org.w3c.dom.Document; + /** * Test case for reported bug 1355 @@ -32,33 +34,195 @@ import org.opendaylight.yangtools.yang.parser.impl.YangParserImpl; */ public class NetconfToRpcRequestTest { - private String TEST_MODEL_NAMESPACE = "urn:opendaylight:params:xml:ns:yang:controller:md:sal:rpc-test"; - private String REVISION = "2014-07-14"; - private QName INPUT_QNAME = QName.create(TEST_MODEL_NAMESPACE, REVISION, "input"); - private QName STREAM_NAME = QName.create(TEST_MODEL_NAMESPACE, REVISION, "stream-name"); - private QName RPC_NAME = QName.create(TEST_MODEL_NAMESPACE, REVISION, "subscribe"); + private final static String TEST_MODEL_NAMESPACE = "urn:opendaylight:params:xml:ns:yang:controller:md:sal:rpc-test"; + private final static String REVISION = "2014-07-14"; + private final static QName INPUT_QNAME = QName.create(TEST_MODEL_NAMESPACE, REVISION, "input"); + private final static QName STREAM_NAME = QName.create(TEST_MODEL_NAMESPACE, REVISION, "stream-name"); + private final static QName SUBSCRIBE_RPC_NAME = QName.create(TEST_MODEL_NAMESPACE, REVISION, "subscribe"); + + private final static String CONFIG_TEST_NAMESPACE = "urn:opendaylight:params:xml:ns:yang:controller:md:sal:test:rpc:config:defs"; + private final static String CONFIG_TEST_REVISION = "2014-07-21"; + private final static QName EDIT_CONFIG_QNAME = QName.create(CONFIG_TEST_NAMESPACE, CONFIG_TEST_REVISION, "edit-config"); + private final static QName GET_QNAME = QName.create(CONFIG_TEST_NAMESPACE, CONFIG_TEST_REVISION, "get"); + private final static QName GET_CONFIG_QNAME = QName.create(CONFIG_TEST_NAMESPACE, CONFIG_TEST_REVISION, "get-config"); - NetconfMessageTransformer messageTransformer; + static SchemaContext notifCtx; + static SchemaContext cfgCtx; + static NetconfMessageTransformer messageTransformer; @SuppressWarnings("deprecation") - @Before - public void setup() throws Exception { - final List modelsToParse = Collections - .singletonList(getClass().getResourceAsStream("/schemas/rpc-notification-subscription.yang")); - final YangContextParser parser = new YangParserImpl(); - final Set modules = parser.parseYangModelsFromStreams(modelsToParse); - assertTrue(!modules.isEmpty()); - final SchemaContext schemaContext = parser.resolveSchemaContext(modules); - assertNotNull(schemaContext); + @BeforeClass + public static void setup() throws Exception { + List modelsToParse = Collections + .singletonList(NetconfToRpcRequestTest.class.getResourceAsStream("/schemas/rpc-notification-subscription.yang")); + YangContextParser parser = new YangParserImpl(); + final Set notifModules = parser.parseYangModelsFromStreams(modelsToParse); + assertTrue(!notifModules.isEmpty()); + + notifCtx = parser.resolveSchemaContext(notifModules); + assertNotNull(notifCtx); + + modelsToParse = Collections + .singletonList(NetconfToRpcRequestTest.class.getResourceAsStream("/schemas/config-test-rpc.yang")); + parser = new YangParserImpl(); + final Set configModules = parser.parseYangModelsFromStreams(modelsToParse); + cfgCtx = parser.resolveSchemaContext(configModules); + assertNotNull(cfgCtx); messageTransformer = new NetconfMessageTransformer(); - messageTransformer.onGlobalContextUpdated(schemaContext); } @Test - public void test() throws Exception { + public void testIsDataEditOperation() throws Exception { + messageTransformer.onGlobalContextUpdated(cfgCtx); + final CompositeNodeBuilder rootBuilder = ImmutableCompositeNode.builder(); - rootBuilder.setQName(RPC_NAME); + rootBuilder.setQName(EDIT_CONFIG_QNAME); + + final CompositeNodeBuilder inputBuilder = ImmutableCompositeNode.builder(); + inputBuilder.setQName(QName.create(CONFIG_TEST_NAMESPACE, CONFIG_TEST_REVISION, "input")); + + final CompositeNodeBuilder targetBuilder = ImmutableCompositeNode.builder(); + targetBuilder.setQName(QName.create(CONFIG_TEST_NAMESPACE, CONFIG_TEST_REVISION, "target")); + targetBuilder.addLeaf(QName.create(CONFIG_TEST_NAMESPACE, CONFIG_TEST_REVISION, "running"), null); + + final CompositeNodeBuilder configBuilder = ImmutableCompositeNode.builder(); + configBuilder.setQName(QName.create(CONFIG_TEST_NAMESPACE, CONFIG_TEST_REVISION, "config")); + + final CompositeNodeBuilder anyxmlTopBuilder = ImmutableCompositeNode.builder(); + anyxmlTopBuilder.setQName(QName.create(CONFIG_TEST_NAMESPACE, CONFIG_TEST_REVISION, "top")); + + final CompositeNodeBuilder anyxmlInterfBuilder = ImmutableCompositeNode.builder(); + anyxmlInterfBuilder.setQName(QName.create(CONFIG_TEST_NAMESPACE, CONFIG_TEST_REVISION, "interface")); + + anyxmlInterfBuilder.addLeaf(QName.create(CONFIG_TEST_NAMESPACE, CONFIG_TEST_REVISION, "name"), "Ethernet0/0"); + anyxmlInterfBuilder.addLeaf(QName.create(CONFIG_TEST_NAMESPACE, CONFIG_TEST_REVISION, "mtu"), "1500"); + + anyxmlTopBuilder.add(anyxmlInterfBuilder.toInstance()); + configBuilder.add(anyxmlTopBuilder.toInstance()); + + inputBuilder.add(targetBuilder.toInstance()); + inputBuilder.add(configBuilder.toInstance()); + + rootBuilder.add(inputBuilder.toInstance()); + final ImmutableCompositeNode root = rootBuilder.toInstance(); + + final NetconfMessage message = messageTransformer.toRpcRequest(EDIT_CONFIG_QNAME, root); + assertNotNull(message); + + final Document xmlDoc = message.getDocument(); + org.w3c.dom.Node rpcChild = xmlDoc.getFirstChild(); + assertEquals(rpcChild.getLocalName(), "rpc"); + + final org.w3c.dom.Node editConfigNode = rpcChild.getFirstChild(); + assertEquals(editConfigNode.getLocalName(), "edit-config"); + + final org.w3c.dom.Node targetNode = editConfigNode.getFirstChild(); + assertEquals(targetNode.getLocalName(), "target"); + + final org.w3c.dom.Node runningNode = targetNode.getFirstChild(); + assertEquals(runningNode.getLocalName(), "running"); + + final org.w3c.dom.Node configNode = targetNode.getNextSibling(); + assertEquals(configNode.getLocalName(), "config"); + + final org.w3c.dom.Node topNode = configNode.getFirstChild(); + assertEquals(topNode.getLocalName(), "top"); + + final org.w3c.dom.Node interfaceNode = topNode.getFirstChild(); + assertEquals(interfaceNode.getLocalName(), "interface"); + + final org.w3c.dom.Node nameNode = interfaceNode.getFirstChild(); + assertEquals(nameNode.getLocalName(), "name"); + + final org.w3c.dom.Node mtuNode = nameNode.getNextSibling(); + assertEquals(mtuNode.getLocalName(), "mtu"); + } + + @Test + public void testIsGetOperation() throws Exception { + messageTransformer.onGlobalContextUpdated(cfgCtx); + + final CompositeNodeBuilder rootBuilder = ImmutableCompositeNode.builder(); + rootBuilder.setQName(GET_QNAME); + + final CompositeNodeBuilder inputBuilder = ImmutableCompositeNode.builder(); + inputBuilder.setQName(QName.create(CONFIG_TEST_NAMESPACE, CONFIG_TEST_REVISION, "input")); + + rootBuilder.add(inputBuilder.toInstance()); + final ImmutableCompositeNode root = rootBuilder.toInstance(); + + final NetconfMessage message = messageTransformer.toRpcRequest(GET_QNAME, root); + assertNotNull(message); + + final Document xmlDoc = message.getDocument(); + final org.w3c.dom.Node rpcChild = xmlDoc.getFirstChild(); + assertEquals(rpcChild.getLocalName(), "rpc"); + + final org.w3c.dom.Node get = rpcChild.getFirstChild(); + assertEquals(get.getLocalName(), "get"); + } + + @Test + public void testIsGetConfigOperation() throws Exception { + messageTransformer.onGlobalContextUpdated(cfgCtx); + + final CompositeNodeBuilder rootBuilder = ImmutableCompositeNode.builder(); + rootBuilder.setQName(GET_CONFIG_QNAME); + + final CompositeNodeBuilder inputBuilder = ImmutableCompositeNode.builder(); + inputBuilder.setQName(QName.create(CONFIG_TEST_NAMESPACE, CONFIG_TEST_REVISION, "input")); + + final CompositeNodeBuilder sourceBuilder = ImmutableCompositeNode.builder(); + sourceBuilder.setQName(QName.create(CONFIG_TEST_NAMESPACE, CONFIG_TEST_REVISION, "source")); + sourceBuilder.addLeaf(QName.create(CONFIG_TEST_NAMESPACE, CONFIG_TEST_REVISION, "running"), null); + + final CompositeNodeBuilder anyxmlFilterBuilder = ImmutableCompositeNode.builder(); + anyxmlFilterBuilder.setQName(QName.create(CONFIG_TEST_NAMESPACE, CONFIG_TEST_REVISION, "filter")); + + final CompositeNodeBuilder anyxmlTopBuilder = ImmutableCompositeNode.builder(); + anyxmlTopBuilder.setQName(QName.create(CONFIG_TEST_NAMESPACE, CONFIG_TEST_REVISION, "top")); + anyxmlTopBuilder.addLeaf(QName.create(CONFIG_TEST_NAMESPACE, CONFIG_TEST_REVISION, "users"), null); + + anyxmlFilterBuilder.add(anyxmlTopBuilder.toInstance()); + + inputBuilder.add(sourceBuilder.toInstance()); + inputBuilder.add(anyxmlFilterBuilder.toInstance()); + rootBuilder.add(inputBuilder.toInstance()); + final ImmutableCompositeNode root = rootBuilder.toInstance(); + + final NetconfMessage message = messageTransformer.toRpcRequest(GET_CONFIG_QNAME, root); + assertNotNull(message); + + final Document xmlDoc = message.getDocument(); + final org.w3c.dom.Node rpcChild = xmlDoc.getFirstChild(); + assertEquals(rpcChild.getLocalName(), "rpc"); + + final org.w3c.dom.Node getConfig = rpcChild.getFirstChild(); + assertEquals(getConfig.getLocalName(), "get-config"); + + final org.w3c.dom.Node sourceNode = getConfig.getFirstChild(); + assertEquals(sourceNode.getLocalName(), "source"); + + final org.w3c.dom.Node runningNode = sourceNode.getFirstChild(); + assertEquals(runningNode.getLocalName(), "running"); + + final org.w3c.dom.Node filterNode = sourceNode.getNextSibling(); + assertEquals(filterNode.getLocalName(), "filter"); + + final org.w3c.dom.Node topNode = filterNode.getFirstChild(); + assertEquals(topNode.getLocalName(), "top"); + + final org.w3c.dom.Node usersNode = topNode.getFirstChild(); + assertEquals(usersNode.getLocalName(), "users"); + } + + @Test + public void testUserDefinedRpcCall() throws Exception { + messageTransformer.onGlobalContextUpdated(notifCtx); + + final CompositeNodeBuilder rootBuilder = ImmutableCompositeNode.builder(); + rootBuilder.setQName(SUBSCRIBE_RPC_NAME); final CompositeNodeBuilder inputBuilder = ImmutableCompositeNode.builder(); inputBuilder.setQName(INPUT_QNAME); @@ -75,7 +239,51 @@ public class NetconfToRpcRequestTest { assertNotNull(inputNode); assertTrue(inputNode.isEmpty()); - final NetconfMessage message = messageTransformer.toRpcRequest(RPC_NAME, root); + final NetconfMessage message = messageTransformer.toRpcRequest(SUBSCRIBE_RPC_NAME, root); + assertNotNull(message); + + final Document xmlDoc = message.getDocument(); + final org.w3c.dom.Node rpcChild = xmlDoc.getFirstChild(); + assertEquals(rpcChild.getLocalName(), "rpc"); + + final org.w3c.dom.Node subscribeName = rpcChild.getFirstChild(); + assertEquals(subscribeName.getLocalName(), "subscribe"); + + final org.w3c.dom.Node streamName = subscribeName.getFirstChild(); + assertEquals(streamName.getLocalName(), "stream-name"); + } + + @Test + public void testNoSchemaContextToRpcRequest() throws Exception { + final String exampleNamespace = "http://example.net/me/my-own/1.0"; + final String exampleRevision = "2014-07-22"; + final QName myOwnMethodRpcQName = QName.create(exampleNamespace, exampleRevision, "my-own-method"); + + final CompositeNodeBuilder rootBuilder = ImmutableCompositeNode.builder(); + rootBuilder.setQName(myOwnMethodRpcQName); + + final CompositeNodeBuilder inputBuilder = ImmutableCompositeNode.builder(); + inputBuilder.setQName(QName.create(exampleNamespace, exampleRevision, "input")); + inputBuilder.addLeaf(QName.create(exampleNamespace, exampleRevision, "my-first-parameter"), "14"); + inputBuilder.addLeaf(QName.create(exampleNamespace, exampleRevision, "another-parameter"), "fred"); + + rootBuilder.add(inputBuilder.toInstance()); + final ImmutableCompositeNode root = rootBuilder.toInstance(); + + final NetconfMessage message = messageTransformer.toRpcRequest(myOwnMethodRpcQName, root); assertNotNull(message); + + final Document xmlDoc = message.getDocument(); + final org.w3c.dom.Node rpcChild = xmlDoc.getFirstChild(); + assertEquals(rpcChild.getLocalName(), "rpc"); + + final org.w3c.dom.Node myOwnMethodNode = rpcChild.getFirstChild(); + assertEquals(myOwnMethodNode.getLocalName(), "my-own-method"); + + final org.w3c.dom.Node firstParamNode = myOwnMethodNode.getFirstChild(); + assertEquals(firstParamNode.getLocalName(), "my-first-parameter"); + + final org.w3c.dom.Node secParamNode = firstParamNode.getNextSibling(); + assertEquals(secParamNode.getLocalName(), "another-parameter"); } } diff --git a/opendaylight/md-sal/sal-netconf-connector/src/test/java/org/opendaylight/controller/sal/connect/netconf/listener/NetconfDeviceCommunicatorTest.java b/opendaylight/md-sal/sal-netconf-connector/src/test/java/org/opendaylight/controller/sal/connect/netconf/listener/NetconfDeviceCommunicatorTest.java index 391bf9c6a4..001b9a8d3a 100644 --- a/opendaylight/md-sal/sal-netconf-connector/src/test/java/org/opendaylight/controller/sal/connect/netconf/listener/NetconfDeviceCommunicatorTest.java +++ b/opendaylight/md-sal/sal-netconf-connector/src/test/java/org/opendaylight/controller/sal/connect/netconf/listener/NetconfDeviceCommunicatorTest.java @@ -8,35 +8,35 @@ package org.opendaylight.controller.sal.connect.netconf.listener; +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertNotNull; +import static org.junit.Assert.assertTrue; +import static org.mockito.Matchers.any; +import static org.mockito.Matchers.eq; +import static org.mockito.Matchers.same; +import static org.mockito.Mockito.doNothing; +import static org.mockito.Mockito.doReturn; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.never; +import static org.mockito.Mockito.reset; +import static org.mockito.Mockito.verify; +import static org.opendaylight.controller.netconf.api.xml.XmlNetconfConstants.RPC_REPLY_KEY; +import static org.opendaylight.controller.netconf.api.xml.XmlNetconfConstants.URN_IETF_PARAMS_XML_NS_NETCONF_BASE_1_0; + +import com.google.common.base.Strings; +import com.google.common.collect.Sets; +import com.google.common.util.concurrent.ListenableFuture; import io.netty.channel.ChannelFuture; import io.netty.util.concurrent.Future; import io.netty.util.concurrent.GenericFutureListener; - import java.io.ByteArrayInputStream; import java.util.Collection; import java.util.Collections; import java.util.UUID; import java.util.concurrent.TimeUnit; import java.util.concurrent.TimeoutException; - import javax.xml.parsers.DocumentBuilderFactory; import javax.xml.parsers.ParserConfigurationException; - -import static org.mockito.Mockito.doNothing; -import static org.mockito.Mockito.doReturn; -import static org.mockito.Mockito.never; -import static org.mockito.Mockito.reset; -import static org.mockito.Mockito.mock; -import static org.mockito.Mockito.verify; -import static org.mockito.Matchers.any; -import static org.mockito.Matchers.eq; -import static org.mockito.Matchers.same; -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertNotNull; -import static org.junit.Assert.assertTrue; -import static org.opendaylight.controller.netconf.api.xml.XmlNetconfConstants.RPC_REPLY_KEY; -import static org.opendaylight.controller.netconf.api.xml.XmlNetconfConstants.URN_IETF_PARAMS_XML_NS_NETCONF_BASE_1_0; - import org.apache.commons.lang3.StringUtils; import org.junit.Before; import org.junit.Test; @@ -56,10 +56,6 @@ import org.opendaylight.yangtools.yang.common.RpcResult; import org.w3c.dom.Document; import org.w3c.dom.Element; -import com.google.common.base.Strings; -import com.google.common.collect.Sets; -import com.google.common.util.concurrent.ListenableFuture; - public class NetconfDeviceCommunicatorTest { @Mock @@ -129,9 +125,9 @@ public class NetconfDeviceCommunicatorTest { verify( mockDevice ).onRemoteSessionUp( netconfSessionCapabilities.capture(), eq( communicator ) ); NetconfSessionCapabilities actualCapabilites = netconfSessionCapabilities.getValue(); - assertEquals( "containsCapability", true, actualCapabilites.containsCapability( - NetconfMessageTransformUtil.NETCONF_ROLLBACK_ON_ERROR_URI.toString() ) ); - assertEquals( "containsCapability", true, actualCapabilites.containsCapability( testCapability ) ); + assertEquals( "containsModuleCapability", true, actualCapabilites.containsNonModuleCapability( + NetconfMessageTransformUtil.NETCONF_ROLLBACK_ON_ERROR_URI.toString()) ); + assertEquals( "containsModuleCapability", false, actualCapabilites.containsNonModuleCapability(testCapability) ); assertEquals( "getModuleBasedCaps", Sets.newHashSet( QName.create( "urn:opendaylight:params:xml:ns:test", "2014-06-02", "test-module" )), actualCapabilites.getModuleBasedCaps() ); diff --git a/opendaylight/md-sal/sal-netconf-connector/src/test/java/org/opendaylight/controller/sal/connect/netconf/listener/NetconfSessionCapabilitiesTest.java b/opendaylight/md-sal/sal-netconf-connector/src/test/java/org/opendaylight/controller/sal/connect/netconf/listener/NetconfSessionCapabilitiesTest.java new file mode 100644 index 0000000000..87947b57fa --- /dev/null +++ b/opendaylight/md-sal/sal-netconf-connector/src/test/java/org/opendaylight/controller/sal/connect/netconf/listener/NetconfSessionCapabilitiesTest.java @@ -0,0 +1,50 @@ +package org.opendaylight.controller.sal.connect.netconf.listener; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertThat; + +import com.google.common.collect.Lists; +import java.util.List; +import org.junit.Test; +import org.junit.matchers.JUnitMatchers; +import org.opendaylight.controller.sal.connect.netconf.util.NetconfMessageTransformUtil; +import org.opendaylight.yangtools.yang.common.QName; + +public class NetconfSessionCapabilitiesTest { + + @Test + public void testMerge() throws Exception { + final List caps1 = Lists.newArrayList( + "namespace:1?module=module1&revision=2012-12-12", + "namespace:2?module=module2&revision=2012-12-12", + "urn:ietf:params:xml:ns:yang:ietf-netconf-monitoring?module=ietf-netconf-monitoring&revision=2010-10-04", + "urn:ietf:params:netconf:base:1.0", + "urn:ietf:params:netconf:capability:rollback-on-error:1.0" + ); + final NetconfSessionCapabilities sessionCaps1 = NetconfSessionCapabilities.fromStrings(caps1); + assertCaps(sessionCaps1, 2, 3); + + final List caps2 = Lists.newArrayList( + "namespace:3?module=module3&revision=2012-12-12", + "namespace:4?module=module4&revision=2012-12-12", + "randomNonModuleCap" + ); + final NetconfSessionCapabilities sessionCaps2 = NetconfSessionCapabilities.fromStrings(caps2); + assertCaps(sessionCaps2, 1, 2); + + final NetconfSessionCapabilities merged = sessionCaps1.replaceModuleCaps(sessionCaps2); + assertCaps(merged, 2, 2 + 1 /*Preserved monitoring*/); + for (final QName qName : sessionCaps2.getModuleBasedCaps()) { + assertThat(merged.getModuleBasedCaps(), JUnitMatchers.hasItem(qName)); + } + assertThat(merged.getModuleBasedCaps(), JUnitMatchers.hasItem(NetconfMessageTransformUtil.IETF_NETCONF_MONITORING)); + + assertThat(merged.getNonModuleCaps(), JUnitMatchers.hasItem("urn:ietf:params:netconf:base:1.0")); + assertThat(merged.getNonModuleCaps(), JUnitMatchers.hasItem("urn:ietf:params:netconf:capability:rollback-on-error:1.0")); + } + + private void assertCaps(final NetconfSessionCapabilities sessionCaps1, final int nonModuleCaps, final int moduleCaps) { + assertEquals(nonModuleCaps, sessionCaps1.getNonModuleCaps().size()); + assertEquals(moduleCaps, sessionCaps1.getModuleBasedCaps().size()); + } +} diff --git a/opendaylight/md-sal/sal-netconf-connector/src/test/java/org/opendaylight/controller/sal/connect/netconf/sal/tx/NetconfDeviceWriteOnlyTxTest.java b/opendaylight/md-sal/sal-netconf-connector/src/test/java/org/opendaylight/controller/sal/connect/netconf/sal/tx/NetconfDeviceWriteOnlyTxTest.java new file mode 100644 index 0000000000..a65e426d59 --- /dev/null +++ b/opendaylight/md-sal/sal-netconf-connector/src/test/java/org/opendaylight/controller/sal/connect/netconf/sal/tx/NetconfDeviceWriteOnlyTxTest.java @@ -0,0 +1,79 @@ +package org.opendaylight.controller.sal.connect.netconf.sal.tx; + +import static junit.framework.Assert.fail; +import static org.mockito.Matchers.any; +import static org.mockito.Matchers.eq; +import static org.mockito.Mockito.doReturn; +import static org.mockito.Mockito.verify; +import static org.mockito.Mockito.verifyNoMoreInteractions; +import static org.opendaylight.controller.sal.connect.netconf.util.NetconfMessageTransformUtil.DISCARD_CHANGES_RPC_CONTENT; + +import com.google.common.util.concurrent.CheckedFuture; +import com.google.common.util.concurrent.Futures; +import org.junit.Before; +import org.junit.Test; +import org.mockito.Mock; +import org.mockito.MockitoAnnotations; +import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType; +import org.opendaylight.controller.md.sal.common.api.data.TransactionCommitFailedException; +import org.opendaylight.controller.md.sal.common.impl.util.compat.DataNormalizer; +import org.opendaylight.controller.sal.connect.netconf.util.NetconfMessageTransformUtil; +import org.opendaylight.controller.sal.connect.util.RemoteDeviceId; +import org.opendaylight.controller.sal.core.api.RpcImplementation; +import org.opendaylight.yangtools.yang.common.QName; +import org.opendaylight.yangtools.yang.common.RpcResult; +import org.opendaylight.yangtools.yang.common.RpcResultBuilder; +import org.opendaylight.yangtools.yang.data.api.CompositeNode; +import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier; + +public class NetconfDeviceWriteOnlyTxTest { + + private final RemoteDeviceId id = new RemoteDeviceId("test-mount"); + + @Mock + private RpcImplementation rpc; + @Mock + private DataNormalizer normalizer; + private YangInstanceIdentifier yangIId; + + @Before + public void setUp() throws Exception { + MockitoAnnotations.initMocks(this); + + doReturn(Futures.>immediateFailedFuture(new IllegalStateException("Failed tx"))) + .doReturn(Futures.immediateFuture(RpcResultBuilder.success().build())) + .when(rpc).invokeRpc(any(QName.class), any(CompositeNode.class)); + + yangIId = YangInstanceIdentifier.builder().node(QName.create("namespace", "2012-12-12", "name")).build(); + doReturn(yangIId).when(normalizer).toLegacy(yangIId); + } + + @Test + public void testDiscardCahnges() { + final NetconfDeviceWriteOnlyTx tx = new NetconfDeviceWriteOnlyTx(id, rpc, normalizer, true, true); + final CheckedFuture submitFuture = tx.submit(); + try { + submitFuture.checkedGet(); + } catch (final TransactionCommitFailedException e) { + // verify discard changes was sent + verify(rpc).invokeRpc(NetconfMessageTransformUtil.NETCONF_DISCARD_CHANGES_QNAME, DISCARD_CHANGES_RPC_CONTENT); + return; + } + + fail("Submit should fail"); + } + + + @Test + public void testDiscardCahngesNotSentWithoutCandidate() { + doReturn(Futures.immediateFuture(RpcResultBuilder.success().build())) + .doReturn(Futures.>immediateFailedFuture(new IllegalStateException("Failed tx"))) + .when(rpc).invokeRpc(any(QName.class), any(CompositeNode.class)); + + final NetconfDeviceWriteOnlyTx tx = new NetconfDeviceWriteOnlyTx(id, rpc, normalizer, false, true); + tx.delete(LogicalDatastoreType.CONFIGURATION, yangIId); + verify(rpc).invokeRpc(eq(NetconfMessageTransformUtil.NETCONF_EDIT_CONFIG_QNAME), any(CompositeNode.class)); + verifyNoMoreInteractions(rpc); + } + +} diff --git a/opendaylight/md-sal/sal-netconf-connector/src/test/resources/schemas/config-test-rpc.yang b/opendaylight/md-sal/sal-netconf-connector/src/test/resources/schemas/config-test-rpc.yang new file mode 100644 index 0000000000..f67c2df256 --- /dev/null +++ b/opendaylight/md-sal/sal-netconf-connector/src/test/resources/schemas/config-test-rpc.yang @@ -0,0 +1,167 @@ +module config-test-rpc { + namespace "urn:opendaylight:params:xml:ns:yang:controller:md:sal:test:rpc:config:defs"; + prefix "rpc"; + + organization + "Cisco Systems, Inc."; + + contact + "lsedlak@cisco.com"; + + description "Test model containing hacked definition of rpc edit-config and definitions for + get and get-config rpc operations. + The rpc definition is copied from rfc 6241 Appendix C: http://tools.ietf.org/html/rfc6241#appendix-C"; + + revision 2014-07-21 { + description "Initial revision."; + } + + extension get-filter-element-attributes { + description + "If this extension is present within an 'anyxml' + statement named 'filter', which must be conceptually + defined within the RPC input section for the + and protocol operations, then the + following unqualified XML attribute is supported + within the element, within a or + protocol operation: + + type : optional attribute with allowed + value strings 'subtree' and 'xpath'. + If missing, the default value is 'subtree'. + + If the 'xpath' feature is supported, then the + following unqualified XML attribute is + also supported: + + select: optional attribute containing a + string representing an XPath expression. + The 'type' attribute must be equal to 'xpath' + if this attribute is present."; + } + + rpc edit-config { + description "The operation loads all or part of a specified + configuration to the specified target configuration."; + + reference "RFC 6241, Section 7.2"; + + input { + container target { + description "Particular configuration to edit."; + + choice config-target { + mandatory true; + description "The configuration target."; + + leaf candidate { + if-feature candidate; + type empty; + description "The candidate configuration is the config target."; + } + + leaf running { + if-feature writable-running; + type empty; + description "The running configuration is the config source."; + } + } + } + + choice edit-content { + mandatory true; + description "The content for the edit operation."; + + anyxml config { + description + "Inline Config content."; + } + + leaf url { + if-feature url; + type string; + description + "URL-based config content."; + } + } + } + } + + rpc get-config { + description + "Retrieve all or part of a specified configuration."; + + reference "RFC 6241, Section 7.1"; + + input { + container source { + description "Particular configuration to retrieve."; + + choice config-source { + mandatory true; + description + "The configuration to retrieve."; + leaf candidate { + if-feature candidate; + type empty; + description + "The candidate configuration is the config source."; + } + leaf running { + type empty; + description + "The running configuration is the config source."; + } + leaf startup { + if-feature startup; + type empty; + description + "The startup configuration is the config source. + This is optional-to-implement on the server because + not all servers will support filtering for this + datastore."; + } + } + } + + anyxml filter { + description "Subtree or XPath filter to use."; + get-filter-element-attributes; + } + } + + output { + anyxml data { + description + "Copy of the source datastore subset that matched + the filter criteria (if any). An empty data container + indicates that the request did not produce any results."; + } + } + } + + rpc get { + description "Retrieve running configuration and device state information."; + + reference "RFC 6241, Section 7.7"; + + input { + anyxml filter { + description + "This parameter specifies the portion of the system + configuration and state data to retrieve."; + get-filter-element-attributes; + } + } + + output { + anyxml data { + description + "Copy of the running datastore subset and/or state + data that matched the filter criteria (if any). + An empty data container indicates that the request did not + produce any results."; + } + } + } +} diff --git a/opendaylight/md-sal/sal-protocolbuffer-encoding/src/main/java/org/opendaylight/controller/cluster/datastore/node/utils/NormalizedNodeVisitor.java b/opendaylight/md-sal/sal-protocolbuffer-encoding/src/main/java/org/opendaylight/controller/cluster/datastore/node/utils/NormalizedNodeVisitor.java deleted file mode 100644 index 69b00bef92..0000000000 --- a/opendaylight/md-sal/sal-protocolbuffer-encoding/src/main/java/org/opendaylight/controller/cluster/datastore/node/utils/NormalizedNodeVisitor.java +++ /dev/null @@ -1,7 +0,0 @@ -package org.opendaylight.controller.cluster.datastore.node.utils; - -import org.opendaylight.yangtools.yang.data.api.schema.NormalizedNode; - -public interface NormalizedNodeVisitor { - public void visitNode(int level, String parentPath, NormalizedNode normalizedNode); -} diff --git a/opendaylight/md-sal/sal-protocolbuffer-encoding/src/test/java/org/opendaylight/controller/cluster/datastore/node/NormalizedNodeToNodeCodecTest.java b/opendaylight/md-sal/sal-protocolbuffer-encoding/src/test/java/org/opendaylight/controller/cluster/datastore/node/NormalizedNodeToNodeCodecTest.java deleted file mode 100644 index 4ccbc97f35..0000000000 --- a/opendaylight/md-sal/sal-protocolbuffer-encoding/src/test/java/org/opendaylight/controller/cluster/datastore/node/NormalizedNodeToNodeCodecTest.java +++ /dev/null @@ -1,158 +0,0 @@ -/* - * 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.cluster.datastore.node; - -import junit.framework.Assert; -import org.junit.Before; -import org.junit.Test; -import org.opendaylight.controller.cluster.datastore.node.utils.NodeIdentifierFactory; -import org.opendaylight.controller.cluster.datastore.node.utils.NormalizedNodeGetter; -import org.opendaylight.controller.cluster.datastore.node.utils.NormalizedNodeNavigator; -import org.opendaylight.controller.cluster.datastore.util.TestModel; -import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier; -import org.opendaylight.controller.protobuff.messages.common.NormalizedNodeMessages.Container; -import org.opendaylight.controller.protobuff.messages.common.NormalizedNodeMessages.Node; -import org.opendaylight.yangtools.yang.data.api.schema.MapEntryNode; -import org.opendaylight.yangtools.yang.data.api.schema.NormalizedNode; -import org.opendaylight.yangtools.yang.model.api.SchemaContext; - -import java.util.ArrayList; -import java.util.List; - -import static junit.framework.Assert.assertEquals; -import static junit.framework.Assert.assertNotNull; - -public class NormalizedNodeToNodeCodecTest { - - - - private SchemaContext schemaContext; - - @Before - public void setUp(){ - schemaContext = TestModel.createTestContext(); - assertNotNull("Schema context must not be null.", schemaContext); - } - - private YangInstanceIdentifier instanceIdentifierFromString(String s){ - - String[] ids = s.split("/"); - - List pathArguments = new ArrayList<>(); - for(String nodeId : ids){ - if(!"".equals(nodeId)) { - pathArguments.add(NodeIdentifierFactory.getArgument(nodeId)); - } - } - final YangInstanceIdentifier instanceIdentifier = YangInstanceIdentifier.create(pathArguments); - return instanceIdentifier; - } - - - @Test - public void testNormalizeNodeAttributesToProtoBuffNode(){ - final NormalizedNode documentOne = TestModel.createTestContainer(); - String id = "/(urn:opendaylight:params:xml:ns:yang:controller:md:sal:dom:store:test?revision=2014-03-13)test" + - "/(urn:opendaylight:params:xml:ns:yang:controller:md:sal:dom:store:test?revision=2014-03-13)outer-list" + - "/(urn:opendaylight:params:xml:ns:yang:controller:md:sal:dom:store:test?revision=2014-03-13)outer-list[{(urn:opendaylight:params:xml:ns:yang:controller:md:sal:dom:store:test?revision=2014-03-13)id=2}]" + - "/(urn:opendaylight:params:xml:ns:yang:controller:md:sal:dom:store:test?revision=2014-03-13)id"; - - NormalizedNodeGetter normalizedNodeGetter = new NormalizedNodeGetter(id); - new NormalizedNodeNavigator(normalizedNodeGetter).navigate( - YangInstanceIdentifier.builder().build().toString(), documentOne); - - // Validate the value of id can be retrieved from the normalized node - NormalizedNode output = normalizedNodeGetter.getOutput(); - assertNotNull(output); - - - NormalizedNodeToNodeCodec codec = new NormalizedNodeToNodeCodec(schemaContext); - Container container = codec.encode(instanceIdentifierFromString(id),output); - - assertNotNull(container); - assertEquals(id, container.getParentPath()+"/"+container.getNormalizedNode().getPath()) ; - - // Decode the normalized node from the ProtocolBuffer form - //first get the node representation of normalized node - final Node node = container.getNormalizedNode(); - - NormalizedNode normalizedNode = codec.decode(instanceIdentifierFromString(id),node); - - assertEquals(normalizedNode.getValue().toString(),output.getValue().toString()); - } - - @Test - public void testThatANormalizedNodeToProtoBuffNodeEncodeDecode() throws Exception { - final NormalizedNode documentOne = TestModel.createTestContainer(); - - final NormalizedNodeToNodeCodec normalizedNodeToNodeCodec = new NormalizedNodeToNodeCodec(schemaContext); - - Container container = normalizedNodeToNodeCodec.encode(YangInstanceIdentifier.builder().build(), documentOne); - - - final NormalizedNode decode = normalizedNodeToNodeCodec.decode(instanceIdentifierFromString("/(urn:opendaylight:params:xml:ns:yang:controller:md:sal:dom:store:test?revision=2014-03-13)test"),container.getNormalizedNode()); - assertNotNull(decode != null); - - //let us ensure that the return decode normalized node encode returns same container - Container containerResult = normalizedNodeToNodeCodec.encode(YangInstanceIdentifier.builder().build(), decode); - - assertEquals(container.getParentPath(),containerResult.getParentPath()); - assertEquals(container.getNormalizedNode().getChildCount(),container.getNormalizedNode().getChildCount()); - - Assert.assertEquals(containerResult.getNormalizedNode().getChildCount(),container.getNormalizedNode().getChildCount()); - - //check first level children are proper - ListchildrenResult = containerResult.getNormalizedNode().getChildList(); - ListchildrenOriginal = container.getNormalizedNode().getChildList(); - - System.out.println("-------------------------------------------------"); - - System.out.println(childrenOriginal.toString()); - - System.out.println("-------------------------------------------------"); - - System.out.println(childrenResult.toString()); - - boolean bFound; - for(Node resultChild: childrenResult){ - bFound = false; - for(Node originalChild:childrenOriginal){ - if(originalChild.getPath().equals(resultChild.getPath()) - && resultChild.getType().equals(resultChild.getType())){ - bFound=true; - break; - } - } - Assert.assertTrue(bFound); - } - - } - - @Test - public void addAugmentations(){ - String stringId = "/(urn:opendaylight:params:xml:ns:yang:controller:md:sal:dom:store:test?revision=2014-03-13)test" + - "/(urn:opendaylight:params:xml:ns:yang:controller:md:sal:dom:store:test?revision=2014-03-13)augmented-list" + - "/(urn:opendaylight:params:xml:ns:yang:controller:md:sal:dom:store:test?revision=2014-03-13)augmented-list[{(urn:opendaylight:params:xml:ns:yang:controller:md:sal:dom:store:test?revision=2014-03-13)id=1}]"; - - YangInstanceIdentifier identifier = instanceIdentifierFromString(stringId); - - MapEntryNode uno = TestModel.createAugmentedListEntry(1, "Uno"); - - NormalizedNodeToNodeCodec codec = - new NormalizedNodeToNodeCodec(schemaContext); - - Container encode = codec - .encode(identifier, uno); - - System.out.println(encode.getNormalizedNode()); - - codec.decode(identifier, encode.getNormalizedNode()); - } - -} diff --git a/opendaylight/md-sal/sal-protocolbuffer-encoding/src/test/java/org/opendaylight/controller/cluster/datastore/node/utils/NodeIdentifierFactoryTest.java b/opendaylight/md-sal/sal-protocolbuffer-encoding/src/test/java/org/opendaylight/controller/cluster/datastore/node/utils/NodeIdentifierFactoryTest.java deleted file mode 100644 index 4b0bde83e0..0000000000 --- a/opendaylight/md-sal/sal-protocolbuffer-encoding/src/test/java/org/opendaylight/controller/cluster/datastore/node/utils/NodeIdentifierFactoryTest.java +++ /dev/null @@ -1,20 +0,0 @@ -package org.opendaylight.controller.cluster.datastore.node.utils; - -import junit.framework.Assert; -import org.junit.Test; -import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier; - -public class NodeIdentifierFactoryTest { - - @Test - public void validateAugmentationIdentifier(){ - YangInstanceIdentifier.PathArgument argument = NodeIdentifierFactory - .getArgument( - "AugmentationIdentifier{childNames=[(urn:opendaylight:flow:table:statistics?revision=2013-12-15)flow-table-statistics]}"); - - Assert.assertTrue(argument instanceof YangInstanceIdentifier.AugmentationIdentifier); - - - } - -} diff --git a/opendaylight/md-sal/sal-protocolbuffer-encoding/src/test/java/org/opendaylight/controller/cluster/datastore/util/InstanceIdentifierUtilsTest.java b/opendaylight/md-sal/sal-protocolbuffer-encoding/src/test/java/org/opendaylight/controller/cluster/datastore/util/InstanceIdentifierUtilsTest.java deleted file mode 100644 index bb246fb1e4..0000000000 --- a/opendaylight/md-sal/sal-protocolbuffer-encoding/src/test/java/org/opendaylight/controller/cluster/datastore/util/InstanceIdentifierUtilsTest.java +++ /dev/null @@ -1,141 +0,0 @@ -package org.opendaylight.controller.cluster.datastore.util; - -import org.junit.Assert; -import org.junit.Test; -import org.opendaylight.controller.protobuff.messages.common.NormalizedNodeMessages; -import org.opendaylight.yangtools.yang.common.QName; -import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier; - -import java.util.ArrayList; -import java.util.Arrays; -import java.util.HashSet; -import java.util.List; - -public class InstanceIdentifierUtilsTest { - - private static QName TEST_QNAME = QName.create("(urn:opendaylight:params:xml:ns:yang:controller:md:sal:dom:store:test?revision=2014-03-13)test"); - private static QName NODE_WITH_VALUE_QNAME = QName.create("(urn:opendaylight:params:xml:ns:yang:controller:md:sal:dom:store:test?revision=2014-03-13)value"); - private static QName NODE_WITH_PREDICATES_QNAME = QName.create("(urn:opendaylight:params:xml:ns:yang:controller:md:sal:dom:store:test?revision=2014-03-13)pred"); - private static QName NAME_QNAME = QName.create("(urn:opendaylight:params:xml:ns:yang:controller:md:sal:dom:store:test?revision=2014-03-13)name"); - - @Test - public void testSerializationOfNodeIdentifier(){ - YangInstanceIdentifier.PathArgument p1 = - new YangInstanceIdentifier.NodeIdentifier(TEST_QNAME); - - List arguments = new ArrayList<>(); - - arguments.add(p1); - - YangInstanceIdentifier expected = YangInstanceIdentifier.create(arguments); - - NormalizedNodeMessages.InstanceIdentifier instanceIdentifier = - InstanceIdentifierUtils.toSerializable(expected); - - YangInstanceIdentifier actual = - InstanceIdentifierUtils.fromSerializable(instanceIdentifier); - - - Assert.assertEquals(expected.getLastPathArgument(), - actual.getLastPathArgument()); - - - } - - @Test - public void testSerializationOfNodeWithValue(){ - - withValue((short) 1); - withValue((long) 2); - withValue(3); - withValue(true); - - } - - private void withValue(Object value){ - YangInstanceIdentifier.PathArgument p1 = - new YangInstanceIdentifier.NodeIdentifier(TEST_QNAME); - - YangInstanceIdentifier.PathArgument p2 = - new YangInstanceIdentifier.NodeWithValue(NODE_WITH_VALUE_QNAME, value); - - - List arguments = new ArrayList<>(); - - arguments.add(p1); - arguments.add(p2); - - YangInstanceIdentifier expected = YangInstanceIdentifier.create(arguments); - - NormalizedNodeMessages.InstanceIdentifier instanceIdentifier = - InstanceIdentifierUtils.toSerializable(expected); - - YangInstanceIdentifier actual = - InstanceIdentifierUtils.fromSerializable(instanceIdentifier); - - - Assert.assertEquals(expected.getLastPathArgument(), - actual.getLastPathArgument()); - } - - - @Test - public void testSerializationOfNodeIdentifierWithPredicates(){ - - withPredicates((short) 1); - withPredicates((long) 2); - withPredicates(3); - withPredicates(true); - - } - - private void withPredicates(Object value){ - YangInstanceIdentifier.PathArgument p1 = - new YangInstanceIdentifier.NodeIdentifier(TEST_QNAME); - - YangInstanceIdentifier.PathArgument p2 = - new YangInstanceIdentifier.NodeIdentifierWithPredicates(NODE_WITH_PREDICATES_QNAME, NAME_QNAME, value); - - - List arguments = new ArrayList<>(); - - arguments.add(p1); - arguments.add(p2); - - YangInstanceIdentifier expected = YangInstanceIdentifier.create(arguments); - - NormalizedNodeMessages.InstanceIdentifier instanceIdentifier = - InstanceIdentifierUtils.toSerializable(expected); - - YangInstanceIdentifier actual = - InstanceIdentifierUtils.fromSerializable(instanceIdentifier); - - - Assert.assertEquals(expected.getLastPathArgument(), - actual.getLastPathArgument()); - } - - @Test - public void testAugmentationIdentifier(){ - YangInstanceIdentifier.PathArgument p1 = - new YangInstanceIdentifier.AugmentationIdentifier(new HashSet(Arrays.asList(TEST_QNAME))); - - List arguments = new ArrayList<>(); - - arguments.add(p1); - - YangInstanceIdentifier expected = YangInstanceIdentifier.create(arguments); - - NormalizedNodeMessages.InstanceIdentifier instanceIdentifier = - InstanceIdentifierUtils.toSerializable(expected); - - YangInstanceIdentifier actual = - InstanceIdentifierUtils.fromSerializable(instanceIdentifier); - - - Assert.assertEquals(expected.getLastPathArgument(), - actual.getLastPathArgument()); - - } - -} diff --git a/opendaylight/md-sal/sal-protocolbuffer-encoding/src/test/java/org/opendaylight/controller/cluster/datastore/util/NormalizedNodeXmlConverterTest.java b/opendaylight/md-sal/sal-protocolbuffer-encoding/src/test/java/org/opendaylight/controller/cluster/datastore/util/NormalizedNodeXmlConverterTest.java deleted file mode 100644 index fb28704952..0000000000 --- a/opendaylight/md-sal/sal-protocolbuffer-encoding/src/test/java/org/opendaylight/controller/cluster/datastore/util/NormalizedNodeXmlConverterTest.java +++ /dev/null @@ -1,482 +0,0 @@ -/* - * Copyright (c) 2013 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.cluster.datastore.util; - -import com.google.common.base.Preconditions; -import com.google.common.collect.Lists; -import com.google.common.collect.Maps; -import com.google.common.collect.Sets; -import org.custommonkey.xmlunit.Diff; -import org.custommonkey.xmlunit.XMLUnit; -import org.junit.Test; -import org.opendaylight.controller.protobuff.messages.common.SimpleNormalizedNodeMessage; -import org.opendaylight.yangtools.yang.common.QName; -import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier; -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; -import org.opendaylight.yangtools.yang.data.api.schema.MapEntryNode; -import org.opendaylight.yangtools.yang.data.api.schema.MapNode; -import org.opendaylight.yangtools.yang.data.impl.codec.xml.XmlDocumentUtils; -import org.opendaylight.yangtools.yang.data.impl.schema.Builders; -import org.opendaylight.yangtools.yang.data.impl.schema.builder.api.CollectionNodeBuilder; -import org.opendaylight.yangtools.yang.data.impl.schema.builder.api.DataContainerNodeBuilder; -import org.opendaylight.yangtools.yang.data.impl.schema.builder.api.ListNodeBuilder; -import org.opendaylight.yangtools.yang.data.impl.schema.builder.api.NormalizedNodeBuilder; -import org.opendaylight.yangtools.yang.data.impl.schema.transform.dom.DomUtils; -import org.opendaylight.yangtools.yang.data.impl.schema.transform.dom.parser.DomToNormalizedNodeParserFactory; -import org.opendaylight.yangtools.yang.data.impl.schema.transform.dom.serializer.DomFromNormalizedNodeSerializerFactory; -import org.opendaylight.yangtools.yang.model.api.ChoiceNode; -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.Module; -import org.opendaylight.yangtools.yang.model.api.SchemaContext; -import org.opendaylight.yangtools.yang.parser.impl.YangParserImpl; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; -import org.w3c.dom.Document; -import org.w3c.dom.Element; -import org.xml.sax.SAXException; - -import javax.xml.parsers.DocumentBuilder; -import javax.xml.parsers.DocumentBuilderFactory; -import javax.xml.parsers.ParserConfigurationException; -import javax.xml.transform.OutputKeys; -import javax.xml.transform.Transformer; -import javax.xml.transform.TransformerException; -import javax.xml.transform.TransformerFactory; -import javax.xml.transform.TransformerFactoryConfigurationError; -import javax.xml.transform.dom.DOMSource; -import javax.xml.transform.stream.StreamResult; -import java.io.ByteArrayInputStream; -import java.io.IOException; -import java.io.InputStream; -import java.io.StringWriter; -import java.net.URI; -import java.text.ParseException; -import java.text.SimpleDateFormat; -import java.util.ArrayList; -import java.util.Collection; -import java.util.Collections; -import java.util.Date; -import java.util.List; -import java.util.Map; -import java.util.Set; - - -/** - * Two of the testcases in the yangtools/yang-data-impl are leveraged (with modification) to - * create the serialization of NormalizedNode using the ProtocolBuffer - * - * @syedbahm - * - */ - - -public class NormalizedNodeXmlConverterTest { - private static final Logger logger = LoggerFactory - .getLogger(NormalizedNodeXmlConverterTest.class); - public static final String NAMESPACE = - "urn:opendaylight:params:xml:ns:yang:controller:test"; - private static Date revision; - private ContainerNode expectedNode; - private ContainerSchemaNode containerNode; - private String xmlPath; - - static { - try { - revision = new SimpleDateFormat("yyyy-MM-dd").parse("2014-03-13"); - } catch (ParseException e) { - throw new RuntimeException(e); - } - } - - public static DataSchemaNode getSchemaNode(final SchemaContext context, - final String moduleName, final String childNodeName) { - for (Module module : context.getModules()) { - if (module.getName().equals(moduleName)) { - DataSchemaNode found = - findChildNode(module.getChildNodes(), childNodeName); - Preconditions.checkState(found != null, "Unable to find %s", - childNodeName); - return found; - } - } - throw new IllegalStateException("Unable to find child node " - + childNodeName); - } - - static DataSchemaNode findChildNode(final Collection children, final String name) { - List containers = Lists.newArrayList(); - - for (DataSchemaNode dataSchemaNode : children) { - if (dataSchemaNode.getQName().getLocalName().equals(name)) { - return dataSchemaNode; - } - if (dataSchemaNode instanceof DataNodeContainer) { - containers.add((DataNodeContainer) dataSchemaNode); - } else if (dataSchemaNode instanceof ChoiceNode) { - containers.addAll(((ChoiceNode) dataSchemaNode).getCases()); - } - } - - for (DataNodeContainer container : containers) { - DataSchemaNode retVal = findChildNode(container.getChildNodes(), name); - if (retVal != null) { - return retVal; - } - } - - return null; - } - - public static YangInstanceIdentifier.NodeIdentifier getNodeIdentifier( - final String localName) { - return new YangInstanceIdentifier.NodeIdentifier(QName.create( - URI.create(NAMESPACE), revision, localName)); - } - - public static YangInstanceIdentifier.AugmentationIdentifier getAugmentIdentifier( - final String... childNames) { - Set qn = Sets.newHashSet(); - - for (String childName : childNames) { - qn.add(getNodeIdentifier(childName).getNodeType()); - } - - return new YangInstanceIdentifier.AugmentationIdentifier(qn); - } - - - public static ContainerNode augmentChoiceExpectedNode() { - - DataContainerNodeBuilder b = - Builders.containerBuilder(); - b.withNodeIdentifier(getNodeIdentifier("container")); - - b.withChild(Builders - .choiceBuilder() - .withNodeIdentifier(getNodeIdentifier("ch2")) - .withChild( - Builders.leafBuilder() - .withNodeIdentifier(getNodeIdentifier("c2Leaf")).withValue("2") - .build()) - .withChild( - Builders - .choiceBuilder() - .withNodeIdentifier(getNodeIdentifier("c2DeepChoice")) - .withChild( - Builders - .leafBuilder() - .withNodeIdentifier( - getNodeIdentifier("c2DeepChoiceCase1Leaf2")) - .withValue("2").build()).build()).build()); - - b.withChild(Builders - .choiceBuilder() - .withNodeIdentifier(getNodeIdentifier("ch3")) - .withChild( - Builders.leafBuilder() - .withNodeIdentifier(getNodeIdentifier("c3Leaf")).withValue("3") - .build()).build()); - - b.withChild(Builders - .augmentationBuilder() - .withNodeIdentifier(getAugmentIdentifier("augLeaf")) - .withChild( - Builders.leafBuilder() - .withNodeIdentifier(getNodeIdentifier("augLeaf")) - .withValue("augment").build()).build()); - - b.withChild(Builders - .augmentationBuilder() - .withNodeIdentifier(getAugmentIdentifier("ch")) - .withChild( - Builders - .choiceBuilder() - .withNodeIdentifier(getNodeIdentifier("ch")) - .withChild( - Builders.leafBuilder() - .withNodeIdentifier(getNodeIdentifier("c1Leaf")) - .withValue("1").build()) - .withChild( - Builders - .augmentationBuilder() - .withNodeIdentifier( - getAugmentIdentifier("c1Leaf_AnotherAugment", - "deepChoice")) - .withChild( - Builders - .leafBuilder() - .withNodeIdentifier( - getNodeIdentifier("c1Leaf_AnotherAugment")) - .withValue("1").build()) - .withChild( - Builders - .choiceBuilder() - .withNodeIdentifier( - getNodeIdentifier("deepChoice")) - .withChild( - Builders - .leafBuilder() - .withNodeIdentifier( - getNodeIdentifier("deepLeafc1")) - .withValue("1").build()).build()) - .build()).build()).build()); - - return b.build(); - } - - - - public void init(final String yangPath, final String xmlPath, final ContainerNode expectedNode) - throws Exception { - SchemaContext schema = parseTestSchema(yangPath); - this.xmlPath = xmlPath; - this.containerNode = - (ContainerSchemaNode) getSchemaNode(schema, "test", "container"); - this.expectedNode = expectedNode; - } - - SchemaContext parseTestSchema(final String yangPath) throws Exception { - - YangParserImpl yangParserImpl = new YangParserImpl(); - InputStream stream = - NormalizedNodeXmlConverterTest.class.getResourceAsStream(yangPath); - ArrayList al = new ArrayList(); - al.add(stream); - Set modules = yangParserImpl.parseYangModelsFromStreams(al); - return yangParserImpl.resolveSchemaContext(modules); - - } - - - @Test - public void testConversionWithAugmentChoice() throws Exception { - init("/augment_choice.yang", "/augment_choice.xml", - augmentChoiceExpectedNode()); - Document doc = loadDocument(xmlPath); - - ContainerNode built = - DomToNormalizedNodeParserFactory - .getInstance(DomUtils.defaultValueCodecProvider()) - .getContainerNodeParser() - .parse(Collections.singletonList(doc.getDocumentElement()), - containerNode); - - if (expectedNode != null) { - junit.framework.Assert.assertEquals(expectedNode, built); - } - - logger.info("{}", built); - - Iterable els = - DomFromNormalizedNodeSerializerFactory - .getInstance(XmlDocumentUtils.getDocument(), - DomUtils.defaultValueCodecProvider()) - .getContainerNodeSerializer().serialize(containerNode, built); - - Element el = els.iterator().next(); - - XMLUnit.setIgnoreWhitespace(true); - XMLUnit.setIgnoreComments(true); - - System.out.println(toString(doc.getDocumentElement())); - System.out.println(toString(el)); - - new Diff( - XMLUnit.buildControlDocument(toString(doc.getDocumentElement())), - XMLUnit.buildTestDocument(toString(el))).similar(); - } - - private static ContainerNode listLeafListWithAttributes() { - DataContainerNodeBuilder b = - Builders.containerBuilder(); - b.withNodeIdentifier(getNodeIdentifier("container")); - - CollectionNodeBuilder listBuilder = - Builders.mapBuilder().withNodeIdentifier(getNodeIdentifier("list")); - - Map predicates = Maps.newHashMap(); - predicates.put(getNodeIdentifier("uint32InList").getNodeType(), 3L); - - DataContainerNodeBuilder list1Builder = - Builders.mapEntryBuilder().withNodeIdentifier( - new YangInstanceIdentifier.NodeIdentifierWithPredicates( - getNodeIdentifier("list").getNodeType(), predicates)); - NormalizedNodeBuilder> uint32InListBuilder = - Builders.leafBuilder().withNodeIdentifier( - getNodeIdentifier("uint32InList")); - - list1Builder.withChild(uint32InListBuilder.withValue(3L).build()); - - listBuilder.withChild(list1Builder.build()); - b.withChild(listBuilder.build()); - - NormalizedNodeBuilder> booleanBuilder = - Builders.leafBuilder().withNodeIdentifier(getNodeIdentifier("boolean")); - booleanBuilder.withValue(false); - b.withChild(booleanBuilder.build()); - - ListNodeBuilder> leafListBuilder = - Builders.leafSetBuilder().withNodeIdentifier( - getNodeIdentifier("leafList")); - - NormalizedNodeBuilder> leafList1Builder = - Builders.leafSetEntryBuilder().withNodeIdentifier( - new YangInstanceIdentifier.NodeWithValue(getNodeIdentifier("leafList") - .getNodeType(), "a")); - - leafList1Builder.withValue("a"); - - leafListBuilder.withChild(leafList1Builder.build()); - b.withChild(leafListBuilder.build()); - - return b.build(); - } - - - @Test - public void testConversionWithAttributes() throws Exception { - init("/test.yang", "/simple_xml_with_attributes.xml", - listLeafListWithAttributes()); - Document doc = loadDocument(xmlPath); - - ContainerNode built = - DomToNormalizedNodeParserFactory - .getInstance(DomUtils.defaultValueCodecProvider()) - .getContainerNodeParser() - .parse(Collections.singletonList(doc.getDocumentElement()), - containerNode); - - if (expectedNode != null) { - junit.framework.Assert.assertEquals(expectedNode, built); - } - - logger.info("{}", built); - - Iterable els = - DomFromNormalizedNodeSerializerFactory - .getInstance(XmlDocumentUtils.getDocument(), - DomUtils.defaultValueCodecProvider()) - .getContainerNodeSerializer().serialize(containerNode, built); - - Element el = els.iterator().next(); - - XMLUnit.setIgnoreWhitespace(true); - XMLUnit.setIgnoreComments(true); - - System.out.println(toString(doc.getDocumentElement())); - System.out.println(toString(el)); - - new Diff( - XMLUnit.buildControlDocument(toString(doc.getDocumentElement())), - XMLUnit.buildTestDocument(toString(el))).similar(); - } - - - private Document loadDocument(final String xmlPath) throws Exception { - InputStream resourceAsStream = - NormalizedNodeXmlConverterTest.class.getResourceAsStream(xmlPath); - - Document currentConfigElement = readXmlToDocument(resourceAsStream); - Preconditions.checkNotNull(currentConfigElement); - return currentConfigElement; - } - - private static final DocumentBuilderFactory BUILDERFACTORY; - - static { - DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance(); - factory.setNamespaceAware(true); - factory.setCoalescing(true); - factory.setIgnoringElementContentWhitespace(true); - factory.setIgnoringComments(true); - BUILDERFACTORY = factory; - } - - private Document readXmlToDocument(final InputStream xmlContent) - throws IOException, SAXException { - DocumentBuilder dBuilder; - try { - dBuilder = BUILDERFACTORY.newDocumentBuilder(); - } catch (ParserConfigurationException e) { - throw new RuntimeException("Failed to parse XML document", e); - } - Document doc = dBuilder.parse(xmlContent); - - doc.getDocumentElement().normalize(); - return doc; - } - - public static String toString(final Element xml) { - try { - Transformer transformer = - TransformerFactory.newInstance().newTransformer(); - transformer.setOutputProperty(OutputKeys.INDENT, "yes"); - - StreamResult result = new StreamResult(new StringWriter()); - DOMSource source = new DOMSource(xml); - transformer.transform(source, result); - - return result.getWriter().toString(); - } catch (IllegalArgumentException | TransformerFactoryConfigurationError - | TransformerException e) { - throw new RuntimeException("Unable to serialize xml element " + xml, e); - } - } - - @Test - public void testConversionToNormalizedXml() throws Exception { - SimpleNormalizedNodeMessage.NormalizedNodeXml nnXml = - EncoderDecoderUtil.encode(parseTestSchema("/augment_choice.yang"), - augmentChoiceExpectedNode()); - Document expectedDoc = loadDocument("/augment_choice.xml"); - Document convertedDoc = - EncoderDecoderUtil.factory.newDocumentBuilder().parse( - new ByteArrayInputStream(nnXml.getXmlString().getBytes("utf-8"))); - System.out.println(toString(convertedDoc.getDocumentElement())); - XMLUnit.setIgnoreWhitespace(true); - XMLUnit.setIgnoreComments(true); - new Diff(XMLUnit.buildControlDocument(toString(expectedDoc - .getDocumentElement())), - XMLUnit.buildTestDocument(toString(convertedDoc - .getDocumentElement()))).similar(); - System.out.println(toString(expectedDoc.getDocumentElement())); - - } - - - @Test - public void testConversionFromXmlToNormalizedNode() throws Exception { - SimpleNormalizedNodeMessage.NormalizedNodeXml nnXml = - EncoderDecoderUtil.encode(parseTestSchema("/test.yang"), - listLeafListWithAttributes()); - Document expectedDoc = loadDocument("/simple_xml_with_attributes.xml"); - Document convertedDoc = - EncoderDecoderUtil.factory.newDocumentBuilder().parse( - new ByteArrayInputStream(nnXml.getXmlString().getBytes("utf-8"))); - System.out.println(toString(convertedDoc.getDocumentElement())); - XMLUnit.setIgnoreWhitespace(true); - XMLUnit.setIgnoreComments(true); - new Diff(XMLUnit.buildControlDocument(toString(expectedDoc - .getDocumentElement())), - XMLUnit.buildTestDocument(toString(convertedDoc - .getDocumentElement()))).similar(); - System.out.println(toString(expectedDoc.getDocumentElement())); - - // now we will try to convert xml back to normalize node. - ContainerNode cn = - (ContainerNode) EncoderDecoderUtil.decode( - parseTestSchema("/test.yang"), nnXml); - junit.framework.Assert.assertEquals(listLeafListWithAttributes(), cn); - - } - -} diff --git a/opendaylight/md-sal/sal-protocolbuffer-encoding/src/test/java/org/opendaylight/controller/cluster/datastore/util/TestModel.java b/opendaylight/md-sal/sal-protocolbuffer-encoding/src/test/java/org/opendaylight/controller/cluster/datastore/util/TestModel.java deleted file mode 100644 index bef4057aa2..0000000000 --- a/opendaylight/md-sal/sal-protocolbuffer-encoding/src/test/java/org/opendaylight/controller/cluster/datastore/util/TestModel.java +++ /dev/null @@ -1,486 +0,0 @@ -package org.opendaylight.controller.cluster.datastore.util; - -import org.opendaylight.yangtools.yang.common.QName; -import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier; -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.LeafSetEntryNode; -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.opendaylight.yangtools.yang.data.impl.schema.ImmutableNodes; -import org.opendaylight.yangtools.yang.data.impl.schema.builder.api.CollectionNodeBuilder; -import org.opendaylight.yangtools.yang.data.impl.schema.builder.api.DataContainerNodeAttrBuilder; -import org.opendaylight.yangtools.yang.data.impl.schema.builder.api.DataContainerNodeBuilder; -import org.opendaylight.yangtools.yang.data.impl.schema.builder.impl.ImmutableContainerNodeBuilder; -import org.opendaylight.yangtools.yang.data.impl.schema.builder.impl.ImmutableLeafSetEntryNodeBuilder; -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.model.api.Module; -import org.opendaylight.yangtools.yang.model.api.SchemaContext; -import org.opendaylight.yangtools.yang.parser.impl.YangParserImpl; - -import java.io.InputStream; -import java.util.ArrayList; -import java.util.HashSet; -import java.util.List; -import java.util.Set; - -import static org.opendaylight.yangtools.yang.data.impl.schema.ImmutableNodes.mapEntry; -import static org.opendaylight.yangtools.yang.data.impl.schema.ImmutableNodes.mapEntryBuilder; -import static org.opendaylight.yangtools.yang.data.impl.schema.ImmutableNodes.mapNodeBuilder; - -public class TestModel { - - public static final QName TEST_QNAME = QName.create( - "urn:opendaylight:params:xml:ns:yang:controller:md:sal:dom:store:test", - "2014-03-13", "test"); - - public static final QName AUG_NAME_QNAME = QName.create( - "urn:opendaylight:params:xml:ns:yang:controller:md:sal:dom:store:aug", - "2014-03-13", "name"); - - public static final QName AUG_CONT_QNAME = QName.create( - "urn:opendaylight:params:xml:ns:yang:controller:md:sal:dom:store:aug", - "2014-03-13", "cont"); - - - public static final QName DESC_QNAME = QName.create(TEST_QNAME, "desc"); - public static final QName POINTER_QNAME = - QName.create(TEST_QNAME, "pointer"); - public static final QName SOME_REF_QNAME = - QName.create(TEST_QNAME, "some-ref"); - public static final QName MYIDENTITY_QNAME = - QName.create(TEST_QNAME, "myidentity"); - public static final QName SWITCH_FEATURES_QNAME = - QName.create(TEST_QNAME, "switch-features"); - - public static final QName AUGMENTED_LIST_QNAME = - QName.create(TEST_QNAME, "augmented-list"); - - public static final QName OUTER_LIST_QNAME = QName.create(TEST_QNAME, - "outer-list"); - public static final QName INNER_LIST_QNAME = QName.create(TEST_QNAME, - "inner-list"); - public static final QName OUTER_CHOICE_QNAME = QName.create(TEST_QNAME, - "outer-choice"); - public static final QName ID_QNAME = QName.create(TEST_QNAME, "id"); - public static final QName NAME_QNAME = QName.create(TEST_QNAME, "name"); - public static final QName VALUE_QNAME = QName.create(TEST_QNAME, "value"); - private static final String DATASTORE_TEST_YANG = - "/odl-datastore-test.yang"; - private static final String DATASTORE_AUG_YANG = - "/odl-datastore-augmentation.yang"; - private static final String DATASTORE_TEST_NOTIFICATION_YANG = - "/odl-datastore-test-notification.yang"; - - - public static final YangInstanceIdentifier TEST_PATH = YangInstanceIdentifier - .of(TEST_QNAME); - public static final YangInstanceIdentifier DESC_PATH = YangInstanceIdentifier - .builder(TEST_PATH).node(DESC_QNAME).build(); - public static final YangInstanceIdentifier OUTER_LIST_PATH = YangInstanceIdentifier - .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"); - - private static final Integer ONE_ID = 1; - private static final Integer TWO_ID = 2; - private static final String TWO_ONE_NAME = "one"; - private static final String TWO_TWO_NAME = "two"; - private static final String DESC = "Hello there"; - - // Family specific constants - public static final QName FAMILY_QNAME = - QName - .create( - "urn:opendaylight:params:xml:ns:yang:controller:md:sal:dom:store:notification-test", - "2014-04-17", "family"); - public static final QName CHILDREN_QNAME = QName.create(FAMILY_QNAME, - "children"); - public static final QName GRAND_CHILDREN_QNAME = QName.create(FAMILY_QNAME, - "grand-children"); - public static final QName CHILD_NUMBER_QNAME = QName.create(FAMILY_QNAME, - "child-number"); - public static final QName CHILD_NAME_QNAME = QName.create(FAMILY_QNAME, - "child-name"); - public static final QName GRAND_CHILD_NUMBER_QNAME = QName.create( - FAMILY_QNAME, "grand-child-number"); - public static final QName GRAND_CHILD_NAME_QNAME = - QName.create(FAMILY_QNAME, - "grand-child-name"); - - public static final YangInstanceIdentifier FAMILY_PATH = YangInstanceIdentifier - .of(FAMILY_QNAME); - public static final YangInstanceIdentifier FAMILY_DESC_PATH = YangInstanceIdentifier - .builder(FAMILY_PATH).node(DESC_QNAME).build(); - public static final YangInstanceIdentifier CHILDREN_PATH = YangInstanceIdentifier - .builder(FAMILY_PATH).node(CHILDREN_QNAME).build(); - - private static final Integer FIRST_CHILD_ID = 1; - private static final Integer SECOND_CHILD_ID = 2; - - private static final String FIRST_CHILD_NAME = "first child"; - private static final String SECOND_CHILD_NAME = "second child"; - - private static final Integer FIRST_GRAND_CHILD_ID = 1; - private static final Integer SECOND_GRAND_CHILD_ID = 2; - - private static final String FIRST_GRAND_CHILD_NAME = "first grand child"; - private static final String SECOND_GRAND_CHILD_NAME = "second grand child"; - - // first child - private static final YangInstanceIdentifier CHILDREN_1_PATH = YangInstanceIdentifier - .builder(CHILDREN_PATH) - .nodeWithKey(CHILDREN_QNAME, CHILD_NUMBER_QNAME, FIRST_CHILD_ID) // - .build(); - private static final YangInstanceIdentifier CHILDREN_1_NAME_PATH = - YangInstanceIdentifier.builder(CHILDREN_PATH) - .nodeWithKey(CHILDREN_QNAME, CHILD_NAME_QNAME, FIRST_CHILD_NAME) // - .build(); - - private static final YangInstanceIdentifier CHILDREN_2_PATH = YangInstanceIdentifier - .builder(CHILDREN_PATH) - .nodeWithKey(CHILDREN_QNAME, CHILD_NUMBER_QNAME, SECOND_CHILD_ID) // - .build(); - private static final YangInstanceIdentifier CHILDREN_2_NAME_PATH = - YangInstanceIdentifier.builder(CHILDREN_PATH) - .nodeWithKey(CHILDREN_QNAME, CHILD_NAME_QNAME, SECOND_CHILD_NAME) // - .build(); - - - private static final YangInstanceIdentifier GRAND_CHILD_1_PATH = - YangInstanceIdentifier.builder(CHILDREN_1_PATH) - .node(GRAND_CHILDREN_QNAME) - // - .nodeWithKey(GRAND_CHILDREN_QNAME, GRAND_CHILD_NUMBER_QNAME, - FIRST_GRAND_CHILD_ID) // - .build(); - - private static final YangInstanceIdentifier GRAND_CHILD_1_NAME_PATH = - YangInstanceIdentifier.builder(CHILDREN_1_PATH) - .node(GRAND_CHILDREN_QNAME) - // - .nodeWithKey(GRAND_CHILDREN_QNAME, GRAND_CHILD_NAME_QNAME, - FIRST_GRAND_CHILD_NAME) // - .build(); - - private static final YangInstanceIdentifier GRAND_CHILD_2_PATH = - YangInstanceIdentifier.builder(CHILDREN_2_PATH) - .node(GRAND_CHILDREN_QNAME) - // - .nodeWithKey(GRAND_CHILDREN_QNAME, GRAND_CHILD_NUMBER_QNAME, - SECOND_GRAND_CHILD_ID) // - .build(); - - private static final YangInstanceIdentifier GRAND_CHILD_2_NAME_PATH = - YangInstanceIdentifier.builder(CHILDREN_2_PATH) - .node(GRAND_CHILDREN_QNAME) - // - .nodeWithKey(GRAND_CHILDREN_QNAME, GRAND_CHILD_NAME_QNAME, - SECOND_GRAND_CHILD_NAME) // - .build(); - - private static final YangInstanceIdentifier DESC_PATH_ID = YangInstanceIdentifier - .builder(DESC_PATH).build(); - private static final YangInstanceIdentifier OUTER_LIST_1_PATH = - YangInstanceIdentifier.builder(OUTER_LIST_PATH) - .nodeWithKey(OUTER_LIST_QNAME, ID_QNAME, ONE_ID) // - .build(); - - private static final YangInstanceIdentifier OUTER_LIST_2_PATH = - YangInstanceIdentifier.builder(OUTER_LIST_PATH) - .nodeWithKey(OUTER_LIST_QNAME, ID_QNAME, TWO_ID) // - .build(); - - private static final YangInstanceIdentifier TWO_TWO_PATH = YangInstanceIdentifier - .builder(OUTER_LIST_2_PATH).node(INNER_LIST_QNAME) // - .nodeWithKey(INNER_LIST_QNAME, NAME_QNAME, TWO_TWO_NAME) // - .build(); - - private static final YangInstanceIdentifier TWO_TWO_VALUE_PATH = - YangInstanceIdentifier.builder(TWO_TWO_PATH).node(VALUE_QNAME) // - .build(); - - private static final MapEntryNode BAR_NODE = mapEntryBuilder( - OUTER_LIST_QNAME, ID_QNAME, TWO_ID) // - .withChild(mapNodeBuilder(INNER_LIST_QNAME) // - .withChild(mapEntry(INNER_LIST_QNAME, NAME_QNAME, TWO_ONE_NAME)) // - .withChild(mapEntry(INNER_LIST_QNAME, NAME_QNAME, TWO_TWO_NAME)) // - .build()) // - .build(); - - public static final InputStream getDatastoreTestInputStream() { - return getInputStream(DATASTORE_TEST_YANG); - } - - public static final InputStream getDatastoreAugInputStream() { - return getInputStream(DATASTORE_AUG_YANG); - } - - public static final InputStream getDatastoreTestNotificationInputStream() { - return getInputStream(DATASTORE_TEST_NOTIFICATION_YANG); - } - - private static InputStream getInputStream(final String resourceName) { - return TestModel.class.getResourceAsStream(resourceName); - } - - public static SchemaContext createTestContext() { - List inputStreams = new ArrayList<>(); - inputStreams.add(getDatastoreTestInputStream()); - inputStreams.add(getDatastoreAugInputStream()); - inputStreams.add(getDatastoreTestNotificationInputStream()); - - YangParserImpl parser = new YangParserImpl(); - Set modules = parser.parseYangModelsFromStreams(inputStreams); - return parser.resolveSchemaContext(modules); - } - - /** - * Returns a test document - *

      - *

      -     * test
      -     *     outer-list
      -     *          id 1
      -     *     outer-list
      -     *          id 2
      -     *          inner-list
      -     *                  name "one"
      -     *          inner-list
      -     *                  name "two"
      -     *
      -     * 
      - * - * @return - */ - public static NormalizedNode createDocumentOne( - SchemaContext schemaContext) { - return ImmutableContainerNodeBuilder - .create() - .withNodeIdentifier( - new YangInstanceIdentifier.NodeIdentifier(schemaContext.getQName())) - .withChild(createTestContainer()).build(); - - } - - public static ContainerNode createTestContainer() { - - - // Create a list of shoes - // This is to test leaf list entry - final LeafSetEntryNode nike = - ImmutableLeafSetEntryNodeBuilder - .create() - .withNodeIdentifier( - new YangInstanceIdentifier.NodeWithValue( - QName.create(TEST_QNAME, - "shoe"), "nike") - ).withValue("nike").build(); - - final LeafSetEntryNode puma = - ImmutableLeafSetEntryNodeBuilder - .create() - .withNodeIdentifier( - new YangInstanceIdentifier.NodeWithValue( - QName.create(TEST_QNAME, - "shoe"), "puma") - ).withValue("puma").build(); - - final LeafSetNode shoes = - ImmutableLeafSetNodeBuilder - .create() - .withNodeIdentifier( - new YangInstanceIdentifier.NodeIdentifier( - QName.create(TEST_QNAME, - "shoe")) - ).withChild(nike).withChild(puma).build(); - - - // Test a leaf-list where each entry contains an identity - final LeafSetEntryNode cap1 = - ImmutableLeafSetEntryNodeBuilder - .create() - .withNodeIdentifier( - new YangInstanceIdentifier.NodeWithValue( - QName.create(TEST_QNAME, - "capability"), DESC_QNAME) - ).withValue(DESC_QNAME).build(); - - final LeafSetNode capabilities = - ImmutableLeafSetNodeBuilder - .create() - .withNodeIdentifier( - new YangInstanceIdentifier.NodeIdentifier( - QName.create(TEST_QNAME, - "capability")) - ).withChild(cap1).build(); - - ContainerNode switchFeatures = ImmutableContainerNodeBuilder - .create() - .withNodeIdentifier(new YangInstanceIdentifier.NodeIdentifier( - SWITCH_FEATURES_QNAME)) - .withChild(capabilities) - .build(); - - // Create a leaf list with numbers - final LeafSetEntryNode five = - ImmutableLeafSetEntryNodeBuilder - .create() - .withNodeIdentifier( - (new YangInstanceIdentifier.NodeWithValue( - QName.create(TEST_QNAME, - "number"), 5)) - ).withValue(5).build(); - final LeafSetEntryNode fifteen = - ImmutableLeafSetEntryNodeBuilder - .create() - .withNodeIdentifier( - (new YangInstanceIdentifier.NodeWithValue( - QName.create(TEST_QNAME, - "number"), 15)) - ).withValue(15).build(); - final LeafSetNode numbers = - ImmutableLeafSetNodeBuilder - .create() - .withNodeIdentifier( - new YangInstanceIdentifier.NodeIdentifier( - QName.create(TEST_QNAME, - "number")) - ).withChild(five).withChild(fifteen).build(); - - - // Create augmentations - MapEntryNode mapEntry = createAugmentedListEntry(1, "First Test"); - - - // Create the document - return ImmutableContainerNodeBuilder - .create() - .withNodeIdentifier( - new YangInstanceIdentifier.NodeIdentifier(TEST_QNAME)) - .withChild(ImmutableNodes.leafNode(DESC_QNAME, DESC)) - .withChild(ImmutableNodes.leafNode(POINTER_QNAME, "pointer")) - .withChild(ImmutableNodes.leafNode(SOME_REF_QNAME, - YangInstanceIdentifier.builder().build())) - .withChild(ImmutableNodes.leafNode(MYIDENTITY_QNAME, DESC_QNAME)) - - //.withChild(augmentationNode) - .withChild(shoes) - .withChild(numbers) - .withChild(switchFeatures) - .withChild(mapNodeBuilder(AUGMENTED_LIST_QNAME).withChild(mapEntry).build()) - .withChild( - mapNodeBuilder(OUTER_LIST_QNAME) - .withChild(mapEntry(OUTER_LIST_QNAME, ID_QNAME, ONE_ID)) - .withChild(BAR_NODE).build() - ).build(); - - } - - public static MapEntryNode createAugmentedListEntry(int id, String name) { - - Set childAugmentations = new HashSet<>(); - childAugmentations.add(AUG_CONT_QNAME); - - ContainerNode augCont = ImmutableContainerNodeBuilder - .create() - .withNodeIdentifier(new YangInstanceIdentifier.NodeIdentifier(AUG_CONT_QNAME)) - .withChild(ImmutableNodes.leafNode(AUG_NAME_QNAME, name)) - .build(); - - - final YangInstanceIdentifier.AugmentationIdentifier augmentationIdentifier = - new YangInstanceIdentifier.AugmentationIdentifier(childAugmentations); - - final AugmentationNode augmentationNode = - Builders.augmentationBuilder() - .withNodeIdentifier(augmentationIdentifier) - .withChild(augCont) - .build(); - - return ImmutableMapEntryNodeBuilder.create() - .withNodeIdentifier( - new YangInstanceIdentifier.NodeIdentifierWithPredicates( - AUGMENTED_LIST_QNAME, ID_QNAME, id)) - .withChild(ImmutableNodes.leafNode(ID_QNAME, id)) - .withChild(augmentationNode).build(); - } - - - public static ContainerNode createFamily() { - final DataContainerNodeAttrBuilder - familyContainerBuilder = - ImmutableContainerNodeBuilder.create().withNodeIdentifier( - new YangInstanceIdentifier.NodeIdentifier(FAMILY_QNAME)); - - final CollectionNodeBuilder childrenBuilder = - mapNodeBuilder(CHILDREN_QNAME); - - final DataContainerNodeBuilder - firstChildBuilder = - mapEntryBuilder(CHILDREN_QNAME, CHILD_NUMBER_QNAME, FIRST_CHILD_ID); - final DataContainerNodeBuilder - secondChildBuilder = - mapEntryBuilder(CHILDREN_QNAME, CHILD_NUMBER_QNAME, - SECOND_CHILD_ID); - - final DataContainerNodeBuilder - firstGrandChildBuilder = - mapEntryBuilder(GRAND_CHILDREN_QNAME, GRAND_CHILD_NUMBER_QNAME, - FIRST_GRAND_CHILD_ID); - final DataContainerNodeBuilder - secondGrandChildBuilder = - mapEntryBuilder(GRAND_CHILDREN_QNAME, GRAND_CHILD_NUMBER_QNAME, - SECOND_GRAND_CHILD_ID); - - firstGrandChildBuilder - .withChild( - ImmutableNodes.leafNode(GRAND_CHILD_NUMBER_QNAME, - FIRST_GRAND_CHILD_ID) - ).withChild( - ImmutableNodes.leafNode(GRAND_CHILD_NAME_QNAME, - FIRST_GRAND_CHILD_NAME) - ); - - secondGrandChildBuilder.withChild( - ImmutableNodes - .leafNode(GRAND_CHILD_NUMBER_QNAME, SECOND_GRAND_CHILD_ID) - ) - .withChild( - ImmutableNodes.leafNode(GRAND_CHILD_NAME_QNAME, - SECOND_GRAND_CHILD_NAME) - ); - - firstChildBuilder - .withChild( - ImmutableNodes.leafNode(CHILD_NUMBER_QNAME, FIRST_CHILD_ID)) - .withChild( - ImmutableNodes.leafNode(CHILD_NAME_QNAME, FIRST_CHILD_NAME)) - .withChild( - mapNodeBuilder(GRAND_CHILDREN_QNAME).withChild( - firstGrandChildBuilder.build()).build() - ); - - - secondChildBuilder - .withChild( - ImmutableNodes.leafNode(CHILD_NUMBER_QNAME, SECOND_CHILD_ID)) - .withChild( - ImmutableNodes.leafNode(CHILD_NAME_QNAME, SECOND_CHILD_NAME)) - .withChild( - mapNodeBuilder(GRAND_CHILDREN_QNAME).withChild( - firstGrandChildBuilder.build()).build() - ); - - childrenBuilder.withChild(firstChildBuilder.build()); - childrenBuilder.withChild(secondChildBuilder.build()); - - return familyContainerBuilder.withChild(childrenBuilder.build()) - .build(); - } - -} diff --git a/opendaylight/md-sal/sal-protocolbuffer-encoding/src/test/java/org/opendaylight/controller/protobuff/messages/ShardManagerMessagesTest.java b/opendaylight/md-sal/sal-protocolbuffer-encoding/src/test/java/org/opendaylight/controller/protobuff/messages/ShardManagerMessagesTest.java deleted file mode 100644 index b0758da9d1..0000000000 --- a/opendaylight/md-sal/sal-protocolbuffer-encoding/src/test/java/org/opendaylight/controller/protobuff/messages/ShardManagerMessagesTest.java +++ /dev/null @@ -1,42 +0,0 @@ -package org.opendaylight.controller.protobuff.messages; - -/** - * This test case is present to ensure that if others have used proper version of protocol buffer. - * - * If a different version of protocol buffer is used then it would generate different java sources - * and would result in breaking of this test case. - * - * @author: syedbahm Date: 6/20/14 - * - */ - -import org.junit.Assert; -import org.junit.Test; -import org.opendaylight.controller.protobuff.messages.shard.ShardManagerMessages; - -import java.io.File; -import java.io.FileInputStream; -import java.io.FileOutputStream; - -public class ShardManagerMessagesTest { - - @Test - public void verifySerialization() throws Exception { - ShardManagerMessages.FindPrimary.Builder builder = - ShardManagerMessages.FindPrimary.newBuilder(); - builder.setShardName("Inventory"); - File testFile = new File("./test"); - FileOutputStream output = new FileOutputStream(testFile); - builder.build().writeTo(output); - output.close(); - - // Here we will read the same and check we got back what we had saved - ShardManagerMessages.FindPrimary findPrimary = - ShardManagerMessages.FindPrimary - .parseFrom(new FileInputStream(testFile)); - Assert.assertEquals("Inventory", findPrimary.getShardName()); - - testFile.delete(); - - } -} diff --git a/opendaylight/md-sal/sal-protocolbuffer-encoding/src/test/java/org/opendaylight/controller/protobuff/messages/transaction/ShardTransactionMessagesTest.java b/opendaylight/md-sal/sal-protocolbuffer-encoding/src/test/java/org/opendaylight/controller/protobuff/messages/transaction/ShardTransactionMessagesTest.java deleted file mode 100644 index 2b1ee5630c..0000000000 --- a/opendaylight/md-sal/sal-protocolbuffer-encoding/src/test/java/org/opendaylight/controller/protobuff/messages/transaction/ShardTransactionMessagesTest.java +++ /dev/null @@ -1,10 +0,0 @@ -package org.opendaylight.controller.protobuff.messages.transaction; - -/** - * @author: syedbahm - * Date: 7/7/14 - */ -public class ShardTransactionMessagesTest { - - -} diff --git a/opendaylight/md-sal/sal-remoterpc-connector/pom.xml b/opendaylight/md-sal/sal-remoterpc-connector/pom.xml index ce3bfe9a4c..a2bee8ffee 100644 --- a/opendaylight/md-sal/sal-remoterpc-connector/pom.xml +++ b/opendaylight/md-sal/sal-remoterpc-connector/pom.xml @@ -34,7 +34,10 @@ com.typesafe.akka akka-testkit_${scala.version} - + + com.typesafe.akka + akka-osgi_${scala.version} + diff --git a/opendaylight/md-sal/sal-remoterpc-connector/src/main/java/org/opendaylight/controller/config/yang/config/remote_rpc_connector/RemoteRPCBrokerModule.java b/opendaylight/md-sal/sal-remoterpc-connector/src/main/java/org/opendaylight/controller/config/yang/config/remote_rpc_connector/RemoteRPCBrokerModule.java index 9824889b80..2be8ba47b9 100644 --- a/opendaylight/md-sal/sal-remoterpc-connector/src/main/java/org/opendaylight/controller/config/yang/config/remote_rpc_connector/RemoteRPCBrokerModule.java +++ b/opendaylight/md-sal/sal-remoterpc-connector/src/main/java/org/opendaylight/controller/config/yang/config/remote_rpc_connector/RemoteRPCBrokerModule.java @@ -2,8 +2,10 @@ package org.opendaylight.controller.config.yang.config.remote_rpc_connector; import org.opendaylight.controller.remote.rpc.RemoteRpcProviderFactory; import org.opendaylight.controller.sal.core.api.Broker; +import org.osgi.framework.BundleContext; public class RemoteRPCBrokerModule extends org.opendaylight.controller.config.yang.config.remote_rpc_connector.AbstractRemoteRPCBrokerModule { + private BundleContext bundleContext; public RemoteRPCBrokerModule(org.opendaylight.controller.config.api.ModuleIdentifier identifier, org.opendaylight.controller.config.api.DependencyResolver dependencyResolver) { super(identifier, dependencyResolver); } @@ -20,6 +22,10 @@ public class RemoteRPCBrokerModule extends org.opendaylight.controller.config.ya @Override public java.lang.AutoCloseable createInstance() { Broker broker = getDomBrokerDependency(); - return RemoteRpcProviderFactory.createInstance(broker); + return RemoteRpcProviderFactory.createInstance(broker, bundleContext); + } + + public void setBundleContext(BundleContext bundleContext) { + this.bundleContext = bundleContext; } } diff --git a/opendaylight/md-sal/sal-remoterpc-connector/src/main/java/org/opendaylight/controller/config/yang/config/remote_rpc_connector/RemoteRPCBrokerModuleFactory.java b/opendaylight/md-sal/sal-remoterpc-connector/src/main/java/org/opendaylight/controller/config/yang/config/remote_rpc_connector/RemoteRPCBrokerModuleFactory.java index 330845b14f..f97338d329 100644 --- a/opendaylight/md-sal/sal-remoterpc-connector/src/main/java/org/opendaylight/controller/config/yang/config/remote_rpc_connector/RemoteRPCBrokerModuleFactory.java +++ b/opendaylight/md-sal/sal-remoterpc-connector/src/main/java/org/opendaylight/controller/config/yang/config/remote_rpc_connector/RemoteRPCBrokerModuleFactory.java @@ -10,6 +10,25 @@ package org.opendaylight.controller.config.yang.config.remote_rpc_connector; +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 RemoteRPCBrokerModuleFactory extends org.opendaylight.controller.config.yang.config.remote_rpc_connector.AbstractRemoteRPCBrokerModuleFactory { + @Override + public Module createModule(String instanceName, DependencyResolver dependencyResolver, BundleContext bundleContext) { + RemoteRPCBrokerModule module = (RemoteRPCBrokerModule)super.createModule(instanceName,dependencyResolver,bundleContext); + module.setBundleContext(bundleContext); + return module; + } + @Override + public Module createModule(String instanceName, DependencyResolver dependencyResolver, + DynamicMBeanWithInstance old, BundleContext bundleContext) throws Exception { + RemoteRPCBrokerModule module = (RemoteRPCBrokerModule)super.createModule(instanceName, dependencyResolver, + old, bundleContext); + module.setBundleContext(bundleContext); + return module; + } } diff --git a/opendaylight/md-sal/sal-remoterpc-connector/src/main/java/org/opendaylight/controller/remote/rpc/ActorConstants.java b/opendaylight/md-sal/sal-remoterpc-connector/src/main/java/org/opendaylight/controller/remote/rpc/ActorConstants.java new file mode 100644 index 0000000000..1f1a0f5cc6 --- /dev/null +++ b/opendaylight/md-sal/sal-remoterpc-connector/src/main/java/org/opendaylight/controller/remote/rpc/ActorConstants.java @@ -0,0 +1,19 @@ +/* + * 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.remote.rpc; + + +public class ActorConstants { + public static final String RPC_BROKER = "rpc-broker"; + public static final String RPC_REGISTRY = "rpc-registry"; + public static final String RPC_MANAGER = "rpc"; + + public static final String RPC_BROKER_PATH= "/user/rpc/rpc-broker"; + public static final String RPC_REGISTRY_PATH = "/user/rpc/rpc-registry"; +} diff --git a/opendaylight/md-sal/sal-remoterpc-connector/src/main/java/org/opendaylight/controller/remote/rpc/ActorSystemFactory.java b/opendaylight/md-sal/sal-remoterpc-connector/src/main/java/org/opendaylight/controller/remote/rpc/ActorSystemFactory.java index 4a6124a3bc..f1ca3ccd50 100644 --- a/opendaylight/md-sal/sal-remoterpc-connector/src/main/java/org/opendaylight/controller/remote/rpc/ActorSystemFactory.java +++ b/opendaylight/md-sal/sal-remoterpc-connector/src/main/java/org/opendaylight/controller/remote/rpc/ActorSystemFactory.java @@ -9,25 +9,38 @@ package org.opendaylight.controller.remote.rpc; import akka.actor.ActorSystem; -import akka.actor.Props; -import com.google.common.base.Function; +import akka.osgi.BundleDelegatingClassLoader; import com.typesafe.config.ConfigFactory; +import org.osgi.framework.BundleContext; -import javax.annotation.Nullable; public class ActorSystemFactory { - private static final ActorSystem actorSystem = (new Function(){ + private static volatile ActorSystem actorSystem = null; - @Nullable @Override public ActorSystem apply(@Nullable Void aVoid) { - ActorSystem system = - ActorSystem.create("opendaylight-rpc", ConfigFactory - .load().getConfig("odl-cluster")); - system.actorOf(Props.create(TerminationMonitor.class), "termination-monitor"); - return system; - } - }).apply(null); + public static final ActorSystem getInstance(){ + return actorSystem; + } - public static final ActorSystem getInstance(){ - return actorSystem; + /** + * This method should be called only once during initialization + * + * @param bundleContext + */ + public static final void createInstance(final BundleContext bundleContext) { + if(actorSystem == null) { + // Create an OSGi bundle classloader for actor system + BundleDelegatingClassLoader classLoader = new BundleDelegatingClassLoader(bundleContext.getBundle(), + Thread.currentThread().getContextClassLoader()); + synchronized (ActorSystemFactory.class) { + // Double check + if (actorSystem == null) { + ActorSystem system = ActorSystem.create("opendaylight-cluster-rpc", + ConfigFactory.load().getConfig("odl-cluster-rpc"), classLoader); + actorSystem = system; + } + } + } else { + throw new IllegalStateException("Actor system should be created only once. Use getInstance method to access existing actor system"); } + } } diff --git a/opendaylight/md-sal/sal-remoterpc-connector/src/main/java/org/opendaylight/controller/remote/rpc/RemoteRpcProvider.java b/opendaylight/md-sal/sal-remoterpc-connector/src/main/java/org/opendaylight/controller/remote/rpc/RemoteRpcProvider.java index 3df572d7c2..ac50b8fe5b 100644 --- a/opendaylight/md-sal/sal-remoterpc-connector/src/main/java/org/opendaylight/controller/remote/rpc/RemoteRpcProvider.java +++ b/opendaylight/md-sal/sal-remoterpc-connector/src/main/java/org/opendaylight/controller/remote/rpc/RemoteRpcProvider.java @@ -68,7 +68,7 @@ public class RemoteRpcProvider implements AutoCloseable, Provider, SchemaContext SchemaService schemaService = brokerSession.getService(SchemaService.class); schemaContext = schemaService.getGlobalContext(); - rpcManager = actorSystem.actorOf(RpcManager.props(clusterWrapper, schemaContext, brokerSession, rpcProvisionRegistry), "rpc"); + rpcManager = actorSystem.actorOf(RpcManager.props(clusterWrapper, schemaContext, brokerSession, rpcProvisionRegistry), ActorConstants.RPC_MANAGER); LOG.debug("Rpc actors are created."); } diff --git a/opendaylight/md-sal/sal-remoterpc-connector/src/main/java/org/opendaylight/controller/remote/rpc/RemoteRpcProviderFactory.java b/opendaylight/md-sal/sal-remoterpc-connector/src/main/java/org/opendaylight/controller/remote/rpc/RemoteRpcProviderFactory.java index 4c40ca1777..fc75f7747a 100644 --- a/opendaylight/md-sal/sal-remoterpc-connector/src/main/java/org/opendaylight/controller/remote/rpc/RemoteRpcProviderFactory.java +++ b/opendaylight/md-sal/sal-remoterpc-connector/src/main/java/org/opendaylight/controller/remote/rpc/RemoteRpcProviderFactory.java @@ -11,9 +11,12 @@ package org.opendaylight.controller.remote.rpc; import org.opendaylight.controller.sal.core.api.Broker; import org.opendaylight.controller.sal.core.api.RpcProvisionRegistry; +import org.osgi.framework.BundleContext; public class RemoteRpcProviderFactory { - public static RemoteRpcProvider createInstance(final Broker broker){ + public static RemoteRpcProvider createInstance(final Broker broker, final BundleContext bundleContext){ + + ActorSystemFactory.createInstance(bundleContext); RemoteRpcProvider rpcProvider = new RemoteRpcProvider(ActorSystemFactory.getInstance(), (RpcProvisionRegistry) broker); broker.registerProvider(rpcProvider); diff --git a/opendaylight/md-sal/sal-remoterpc-connector/src/main/java/org/opendaylight/controller/remote/rpc/RpcManager.java b/opendaylight/md-sal/sal-remoterpc-connector/src/main/java/org/opendaylight/controller/remote/rpc/RpcManager.java index 4925a17c13..5c56455bd0 100644 --- a/opendaylight/md-sal/sal-remoterpc-connector/src/main/java/org/opendaylight/controller/remote/rpc/RpcManager.java +++ b/opendaylight/md-sal/sal-remoterpc-connector/src/main/java/org/opendaylight/controller/remote/rpc/RpcManager.java @@ -72,14 +72,14 @@ public class RpcManager extends AbstractUntypedActor { private void createRpcActors() { LOG.debug("Create rpc registry and broker actors"); - rpcRegistry = getContext().actorOf(RpcRegistry.props(clusterWrapper), "rpc-registry"); - rpcBroker = getContext().actorOf(RpcBroker.props(brokerSession, rpcRegistry, schemaContext), "rpc-broker"); + rpcRegistry = getContext().actorOf(RpcRegistry.props(clusterWrapper), ActorConstants.RPC_REGISTRY); + rpcBroker = getContext().actorOf(RpcBroker.props(brokerSession, rpcRegistry, schemaContext), ActorConstants.RPC_BROKER); } private void startListeners() { LOG.debug("Registers rpc listeners"); - String rpcBrokerPath = clusterWrapper.getAddress().toString() + "/user/rpc/rpc-broker"; + String rpcBrokerPath = clusterWrapper.getAddress().toString() + ActorConstants.RPC_BROKER_PATH; rpcListener = new RpcListener(rpcRegistry, rpcBrokerPath); routeChangeListener = new RoutedRpcListener(rpcRegistry, rpcBrokerPath); rpcImplementation = new RemoteRpcImplementation(rpcBroker, schemaContext); diff --git a/opendaylight/md-sal/sal-remoterpc-connector/src/main/java/org/opendaylight/controller/remote/rpc/registry/RpcRegistry.java b/opendaylight/md-sal/sal-remoterpc-connector/src/main/java/org/opendaylight/controller/remote/rpc/registry/RpcRegistry.java index 7cb505aa98..e36060cc13 100644 --- a/opendaylight/md-sal/sal-remoterpc-connector/src/main/java/org/opendaylight/controller/remote/rpc/registry/RpcRegistry.java +++ b/opendaylight/md-sal/sal-remoterpc-connector/src/main/java/org/opendaylight/controller/remote/rpc/registry/RpcRegistry.java @@ -14,6 +14,7 @@ import akka.cluster.ClusterEvent; import akka.cluster.Member; import akka.japi.Creator; import org.opendaylight.controller.remote.rpc.AbstractUntypedActor; +import org.opendaylight.controller.remote.rpc.ActorConstants; import org.opendaylight.controller.remote.rpc.messages.AddRoutedRpc; import org.opendaylight.controller.remote.rpc.messages.AddRpc; import org.opendaylight.controller.remote.rpc.messages.GetRoutedRpc; @@ -171,7 +172,7 @@ public class RpcRegistry extends AbstractUntypedActor { } if(i == index) { if(!currentNodeAddress.equals(member.address())) { - actor = this.context().actorSelection(member.address() + "/user/rpc-registry"); + actor = this.context().actorSelection(member.address() + ActorConstants.RPC_REGISTRY_PATH); break; } else if(index < memberSize-1){ // pick the next element in the set index++; @@ -180,7 +181,7 @@ public class RpcRegistry extends AbstractUntypedActor { i++; } if(actor == null && previousMember != null) { - actor = this.context().actorSelection(previousMember.address() + "/user/rpc-registry"); + actor = this.context().actorSelection(previousMember.address() + ActorConstants.RPC_REGISTRY_PATH); } } return actor; diff --git a/opendaylight/md-sal/sal-remoterpc-connector/src/main/java/org/opendaylight/controller/remote/rpc/utils/XmlDocumentUtils.java b/opendaylight/md-sal/sal-remoterpc-connector/src/main/java/org/opendaylight/controller/remote/rpc/utils/XmlDocumentUtils.java index 127aa0732b..b4cca1ab48 100644 --- a/opendaylight/md-sal/sal-remoterpc-connector/src/main/java/org/opendaylight/controller/remote/rpc/utils/XmlDocumentUtils.java +++ b/opendaylight/md-sal/sal-remoterpc-connector/src/main/java/org/opendaylight/controller/remote/rpc/utils/XmlDocumentUtils.java @@ -33,6 +33,7 @@ import org.opendaylight.yangtools.yang.model.api.SchemaContext; import org.opendaylight.yangtools.yang.model.api.SchemaNode; import org.opendaylight.yangtools.yang.model.api.TypeDefinition; import org.opendaylight.yangtools.yang.model.api.type.IdentityrefTypeDefinition; +import org.opendaylight.yangtools.yang.model.util.InstanceIdentifierType; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.w3c.dom.Attr; @@ -155,7 +156,7 @@ public class XmlDocumentUtils { } final TypeDefinition baseType = XmlUtils.resolveBaseTypeFrom(schema.getType()); - if (baseType instanceof org.opendaylight.yangtools.yang.model.util.InstanceIdentifier) { + if (baseType instanceof InstanceIdentifierType) { logger.debug("toSimpleNodeWithType: base type of node is instance identifier, deserializing element", xmlElement); value = InstanceIdentifierForXmlCodec.deserialize(xmlElement,schemaCtx); @@ -184,7 +185,8 @@ public class XmlDocumentUtils { value = codec.deserialize(text); } - if (schema.getType() instanceof org.opendaylight.yangtools.yang.model.util.InstanceIdentifier) { + final TypeDefinition baseType = XmlUtils.resolveBaseTypeFrom(schema.getType()); + if (baseType instanceof InstanceIdentifierType) { logger.debug("toSimpleNodeWithType: base type of node is instance identifier, deserializing element", xmlElement); value = InstanceIdentifierForXmlCodec.deserialize(xmlElement,schemaCtx); } diff --git a/opendaylight/md-sal/sal-remoterpc-connector/src/main/resources/application.conf b/opendaylight/md-sal/sal-remoterpc-connector/src/main/resources/application.conf index 6088dd0e0e..daac89c4c8 100644 --- a/opendaylight/md-sal/sal-remoterpc-connector/src/main/resources/application.conf +++ b/opendaylight/md-sal/sal-remoterpc-connector/src/main/resources/application.conf @@ -1,4 +1,43 @@ -odl-cluster{ + +odl-cluster-data { + akka { + cluster { + roles = [ + "member-1" + ] + } + actor { + provider = "akka.cluster.ClusterActorRefProvider" + serializers { + java = "akka.serialization.JavaSerializer" + proto = "akka.remote.serialization.ProtobufSerializer" + } + + serialization-bindings { + "com.google.protobuf.Message" = proto + + } + } + remote { + log-remote-lifecycle-events = off + netty.tcp { + hostname = "127.0.0.1" + port = 2550 + maximum-frame-size = 2097152 + send-buffer-size = 52428800 + receive-buffer-size = 52428800 + } + } + + cluster { + seed-nodes = ["akka.tcp://opendaylight-cluster-data@127.0.0.1:2550"] + + auto-down-unreachable-after = 10s + } + } +} + +odl-cluster-rpc { akka { actor { provider = "akka.cluster.ClusterActorRefProvider" @@ -7,15 +46,15 @@ odl-cluster{ remote { log-remote-lifecycle-events = off netty.tcp { - hostname = "192.168.141.141" + hostname = "127.0.0.1" port = 2551 } } cluster { - seed-nodes = ["akka.tcp://opendaylight-rpc@192.168.141.141:2551"] + seed-nodes = ["akka.tcp://opendaylight-cluster-rpc@127.0.0.1:2551"] auto-down-unreachable-after = 10s } } -} \ No newline at end of file +} diff --git a/opendaylight/md-sal/sal-rest-connector/pom.xml b/opendaylight/md-sal/sal-rest-connector/pom.xml index 09fb5b3677..e61cafa70b 100644 --- a/opendaylight/md-sal/sal-rest-connector/pom.xml +++ b/opendaylight/md-sal/sal-rest-connector/pom.xml @@ -42,6 +42,14 @@ org.opendaylight.controller sal-common-util + + org.opendaylight.controller + sal-common-impl + + + org.opendaylight.controller + sal-binding-broker-impl + org.opendaylight.controller sal-remote @@ -105,6 +113,11 @@ org.opendaylight.controller sal-core-spi + + org.opendaylight.yangtools + yang-data-composite-node + 0.6.2-SNAPSHOT + diff --git a/opendaylight/md-sal/sal-rest-connector/src/main/java/org/opendaylight/controller/config/yang/md/sal/rest/connector/RestConnectorModule.java b/opendaylight/md-sal/sal-rest-connector/src/main/java/org/opendaylight/controller/config/yang/md/sal/rest/connector/RestConnectorModule.java index 582c657868..52115a8f32 100644 --- a/opendaylight/md-sal/sal-rest-connector/src/main/java/org/opendaylight/controller/config/yang/md/sal/rest/connector/RestConnectorModule.java +++ b/opendaylight/md-sal/sal-rest-connector/src/main/java/org/opendaylight/controller/config/yang/md/sal/rest/connector/RestConnectorModule.java @@ -2,6 +2,7 @@ package org.opendaylight.controller.config.yang.md.sal.rest.connector; import org.opendaylight.controller.sal.rest.impl.RestconfProviderImpl; + public class RestConnectorModule extends org.opendaylight.controller.config.yang.md.sal.rest.connector.AbstractRestConnectorModule { public RestConnectorModule(org.opendaylight.controller.config.api.ModuleIdentifier identifier, org.opendaylight.controller.config.api.DependencyResolver dependencyResolver) { @@ -28,3 +29,4 @@ public class RestConnectorModule extends org.opendaylight.controller.config.yang return instance; } } + diff --git a/opendaylight/md-sal/sal-rest-connector/src/main/java/org/opendaylight/controller/config/yang/md/sal/rest/connector/RestConnectorModuleFactory.java b/opendaylight/md-sal/sal-rest-connector/src/main/java/org/opendaylight/controller/config/yang/md/sal/rest/connector/RestConnectorModuleFactory.java index 957b08f6ae..1964a17472 100644 --- a/opendaylight/md-sal/sal-rest-connector/src/main/java/org/opendaylight/controller/config/yang/md/sal/rest/connector/RestConnectorModuleFactory.java +++ b/opendaylight/md-sal/sal-rest-connector/src/main/java/org/opendaylight/controller/config/yang/md/sal/rest/connector/RestConnectorModuleFactory.java @@ -9,7 +9,6 @@ */ package org.opendaylight.controller.config.yang.md.sal.rest.connector; - public class RestConnectorModuleFactory extends org.opendaylight.controller.config.yang.md.sal.rest.connector.AbstractRestConnectorModuleFactory { } diff --git a/opendaylight/md-sal/sal-rest-connector/src/main/java/org/opendaylight/controller/sal/rest/api/RestconfService.java b/opendaylight/md-sal/sal-rest-connector/src/main/java/org/opendaylight/controller/sal/rest/api/RestconfService.java index a6c4ea5ab8..9c149a21e6 100644 --- a/opendaylight/md-sal/sal-rest-connector/src/main/java/org/opendaylight/controller/sal/rest/api/RestconfService.java +++ b/opendaylight/md-sal/sal-rest-connector/src/main/java/org/opendaylight/controller/sal/rest/api/RestconfService.java @@ -23,6 +23,7 @@ import javax.ws.rs.core.Response; import javax.ws.rs.core.UriInfo; import org.opendaylight.controller.sal.restconf.impl.StructuredData; import org.opendaylight.yangtools.yang.data.api.CompositeNode; +import org.opendaylight.yangtools.yang.data.api.Node; /** * The URI hierarchy for the RESTCONF resources consists of an entry point container, 4 top-level resources, and 1 @@ -30,15 +31,18 @@ import org.opendaylight.yangtools.yang.data.api.CompositeNode; *
        *
      • /restconf - {@link #getRoot()} *
          - *
        • /config - {@link #readConfigurationData(String)} {@link #updateConfigurationData(String, CompositeNode)} - * {@link #createConfigurationData(CompositeNode)} {@link #createConfigurationData(String, CompositeNode)} + *
        • /config - {@link #readConfigurationData(String)} + * {@link #updateConfigurationData(String, CompositeNode)} + * {@link #createConfigurationData(CompositeNode)} + * {@link #createConfigurationData(String, CompositeNode)} * {@link #deleteConfigurationData(String)} *
        • /operational - {@link #readOperationalData(String)} *
        • /modules - {@link #getModules()} *
            *
          • /module *
          - *
        • /operations - {@link #invokeRpc(String, CompositeNode)} {@link #invokeRpc(String, CompositeNode)} + *
        • /operations - {@link #invokeRpc(String, CompositeNode)} + * {@link #invokeRpc(String, CompositeNode)} *
        • /version (field) *
        *
      @@ -119,19 +123,19 @@ public interface RestconfService { @Path("/config/{identifier:.+}") @Consumes({ Draft02.MediaTypes.DATA + JSON, Draft02.MediaTypes.DATA + XML, MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML, MediaType.TEXT_XML }) - public Response updateConfigurationData(@Encoded @PathParam("identifier") String identifier, CompositeNode payload); + public Response updateConfigurationData(@Encoded @PathParam("identifier") String identifier, Node payload); @POST @Path("/config/{identifier:.+}") @Consumes({ Draft02.MediaTypes.DATA + JSON, Draft02.MediaTypes.DATA + XML, MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML, MediaType.TEXT_XML }) - public Response createConfigurationData(@Encoded @PathParam("identifier") String identifier, CompositeNode payload); + public Response createConfigurationData(@Encoded @PathParam("identifier") String identifier, Node payload); @POST @Path("/config") @Consumes({ Draft02.MediaTypes.DATA + JSON, Draft02.MediaTypes.DATA + XML, MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML, MediaType.TEXT_XML }) - public Response createConfigurationData(CompositeNode payload); + public Response createConfigurationData(Node payload); @DELETE @Path("/config/{identifier:.+}") diff --git a/opendaylight/md-sal/sal-rest-connector/src/main/java/org/opendaylight/controller/sal/rest/impl/JsonMapper.java b/opendaylight/md-sal/sal-rest-connector/src/main/java/org/opendaylight/controller/sal/rest/impl/JsonMapper.java index 34aa829b6f..863de10325 100644 --- a/opendaylight/md-sal/sal-rest-connector/src/main/java/org/opendaylight/controller/sal/rest/impl/JsonMapper.java +++ b/opendaylight/md-sal/sal-rest-connector/src/main/java/org/opendaylight/controller/sal/rest/impl/JsonMapper.java @@ -19,7 +19,7 @@ import java.util.HashSet; import java.util.List; import java.util.Set; import javax.activation.UnsupportedDataTypeException; -import org.opendaylight.controller.sal.core.api.mount.MountInstance; +import org.opendaylight.controller.md.sal.dom.api.DOMMountPoint; import org.opendaylight.controller.sal.restconf.impl.ControllerContext; import org.opendaylight.controller.sal.restconf.impl.IdentityValuesDTO; import org.opendaylight.controller.sal.restconf.impl.IdentityValuesDTO.IdentityValue; @@ -52,9 +52,9 @@ import org.slf4j.LoggerFactory; class JsonMapper { private static final Logger LOG = LoggerFactory.getLogger(JsonMapper.class); - private final MountInstance mountPoint; + private final DOMMountPoint mountPoint; - public JsonMapper(final MountInstance mountPoint) { + public JsonMapper(final DOMMountPoint mountPoint) { this.mountPoint = mountPoint; } diff --git a/opendaylight/md-sal/sal-rest-connector/src/main/java/org/opendaylight/controller/sal/rest/impl/JsonToCompositeNodeProvider.java b/opendaylight/md-sal/sal-rest-connector/src/main/java/org/opendaylight/controller/sal/rest/impl/JsonToCompositeNodeProvider.java index 2f3499e269..caff848180 100644 --- a/opendaylight/md-sal/sal-rest-connector/src/main/java/org/opendaylight/controller/sal/rest/impl/JsonToCompositeNodeProvider.java +++ b/opendaylight/md-sal/sal-rest-connector/src/main/java/org/opendaylight/controller/sal/rest/impl/JsonToCompositeNodeProvider.java @@ -22,14 +22,14 @@ import org.opendaylight.controller.sal.rest.api.RestconfService; import org.opendaylight.controller.sal.restconf.impl.RestconfDocumentedException; import org.opendaylight.controller.sal.restconf.impl.RestconfError.ErrorTag; import org.opendaylight.controller.sal.restconf.impl.RestconfError.ErrorType; -import org.opendaylight.yangtools.yang.data.api.CompositeNode; +import org.opendaylight.yangtools.yang.data.api.Node; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @Provider @Consumes({ Draft02.MediaTypes.DATA + RestconfService.JSON, Draft02.MediaTypes.OPERATION + RestconfService.JSON, MediaType.APPLICATION_JSON }) -public enum JsonToCompositeNodeProvider implements MessageBodyReader { +public enum JsonToCompositeNodeProvider implements MessageBodyReader> { INSTANCE; private final static Logger LOG = LoggerFactory.getLogger(JsonToCompositeNodeProvider.class); @@ -41,7 +41,7 @@ public enum JsonToCompositeNodeProvider implements MessageBodyReader type, final Type genericType, + public Node readFrom(final Class> type, final Type genericType, final Annotation[] annotations, final MediaType mediaType, final MultivaluedMap httpHeaders, final InputStream entityStream) throws IOException, WebApplicationException { diff --git a/opendaylight/md-sal/sal-rest-connector/src/main/java/org/opendaylight/controller/sal/rest/impl/RestconfProviderImpl.java b/opendaylight/md-sal/sal-rest-connector/src/main/java/org/opendaylight/controller/sal/rest/impl/RestconfProviderImpl.java index adb176a65d..2fa99819d5 100644 --- a/opendaylight/md-sal/sal-rest-connector/src/main/java/org/opendaylight/controller/sal/rest/impl/RestconfProviderImpl.java +++ b/opendaylight/md-sal/sal-rest-connector/src/main/java/org/opendaylight/controller/sal/rest/impl/RestconfProviderImpl.java @@ -9,25 +9,24 @@ package org.opendaylight.controller.sal.rest.impl; import java.util.Collection; import java.util.Collections; - +import org.opendaylight.controller.md.sal.dom.api.DOMDataBroker; +import org.opendaylight.controller.md.sal.dom.api.DOMMountPointService; import org.opendaylight.controller.sal.core.api.Broker.ProviderSession; import org.opendaylight.controller.sal.core.api.Provider; -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.MountService; import org.opendaylight.controller.sal.rest.api.RestConnector; import org.opendaylight.controller.sal.restconf.impl.BrokerFacade; import org.opendaylight.controller.sal.restconf.impl.ControllerContext; import org.opendaylight.controller.sal.streams.websockets.WebSocketServer; import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev100924.PortNumber; import org.opendaylight.yangtools.concepts.ListenerRegistration; -import org.opendaylight.yangtools.yang.model.api.SchemaServiceListener; +import org.opendaylight.yangtools.yang.model.api.SchemaContextListener; public class RestconfProviderImpl implements Provider, AutoCloseable, RestConnector { public final static String NOT_INITALIZED_MSG = "Restconf is not initialized yet. Please try again later"; - private ListenerRegistration listenerRegistration; + private ListenerRegistration listenerRegistration; private PortNumber port; public void setWebsocketPort(PortNumber port) { this.port = port; @@ -37,15 +36,15 @@ public class RestconfProviderImpl implements Provider, AutoCloseable, RestConnec @Override public void onSessionInitiated(ProviderSession session) { - DataBrokerService dataService = session.getService(DataBrokerService.class); + final DOMDataBroker domDataBroker = session.getService(DOMDataBroker.class); BrokerFacade.getInstance().setContext(session); - BrokerFacade.getInstance().setDataService(dataService); + BrokerFacade.getInstance().setDomDataBroker( domDataBroker); SchemaService schemaService = session.getService(SchemaService.class); - listenerRegistration = schemaService.registerSchemaServiceListener(ControllerContext.getInstance()); + listenerRegistration = schemaService.registerSchemaContextListener(ControllerContext.getInstance()); ControllerContext.getInstance().setSchemas(schemaService.getGlobalContext()); - ControllerContext.getInstance().setMountService(session.getService(MountService.class)); + ControllerContext.getInstance().setMountService(session.getService(DOMMountPointService.class)); webSocketServerThread = new Thread(WebSocketServer.createInstance(port.getValue().intValue())); webSocketServerThread.setName("Web socket server on port " + port); diff --git a/opendaylight/md-sal/sal-rest-connector/src/main/java/org/opendaylight/controller/sal/rest/impl/XmlToCompositeNodeProvider.java b/opendaylight/md-sal/sal-rest-connector/src/main/java/org/opendaylight/controller/sal/rest/impl/XmlToCompositeNodeProvider.java index 31e9c96462..d56a32e36e 100644 --- a/opendaylight/md-sal/sal-rest-connector/src/main/java/org/opendaylight/controller/sal/rest/impl/XmlToCompositeNodeProvider.java +++ b/opendaylight/md-sal/sal-rest-connector/src/main/java/org/opendaylight/controller/sal/rest/impl/XmlToCompositeNodeProvider.java @@ -23,25 +23,25 @@ import org.opendaylight.controller.sal.rest.api.RestconfService; import org.opendaylight.controller.sal.restconf.impl.RestconfDocumentedException; import org.opendaylight.controller.sal.restconf.impl.RestconfError.ErrorTag; import org.opendaylight.controller.sal.restconf.impl.RestconfError.ErrorType; -import org.opendaylight.yangtools.yang.data.api.CompositeNode; +import org.opendaylight.yangtools.yang.data.api.Node; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @Provider @Consumes({ Draft02.MediaTypes.DATA + RestconfService.XML, Draft02.MediaTypes.OPERATION + RestconfService.XML, MediaType.APPLICATION_XML, MediaType.TEXT_XML }) -public enum XmlToCompositeNodeProvider implements MessageBodyReader { +public enum XmlToCompositeNodeProvider implements MessageBodyReader> { INSTANCE; - private final static Logger LOG = LoggerFactory.getLogger(XmlToCompositeNodeProvider.class); @Override - public boolean isReadable(Class type, Type genericType, Annotation[] annotations, MediaType mediaType) { + public boolean isReadable(final Class type, final Type genericType, final Annotation[] annotations, + final MediaType mediaType) { return true; } @Override - public CompositeNode readFrom(Class type, Type genericType, Annotation[] annotations, + public Node readFrom(final Class> type, final Type genericType, final Annotation[] annotations, MediaType mediaType, MultivaluedMap httpHeaders, InputStream entityStream) throws IOException, WebApplicationException { XmlToCompositeNodeReader xmlReader = new XmlToCompositeNodeReader(); diff --git a/opendaylight/md-sal/sal-rest-connector/src/main/java/org/opendaylight/controller/sal/rest/impl/XmlToCompositeNodeReader.java b/opendaylight/md-sal/sal-rest-connector/src/main/java/org/opendaylight/controller/sal/rest/impl/XmlToCompositeNodeReader.java index 413823f520..5944d6003e 100644 --- a/opendaylight/md-sal/sal-rest-connector/src/main/java/org/opendaylight/controller/sal/rest/impl/XmlToCompositeNodeReader.java +++ b/opendaylight/md-sal/sal-rest-connector/src/main/java/org/opendaylight/controller/sal/rest/impl/XmlToCompositeNodeReader.java @@ -33,10 +33,11 @@ public class XmlToCompositeNodeReader { private final static XMLInputFactory xmlInputFactory = XMLInputFactory.newInstance(); private XMLEventReader eventReader; - public CompositeNodeWrapper read(InputStream entityStream) throws XMLStreamException, UnsupportedFormatException, - IOException { - // Get an XML stream which can be marked, and reset, so we can check and - // see if there is any content being provided. + public Node read(InputStream entityStream) throws XMLStreamException, + UnsupportedFormatException, + IOException { + //Get an XML stream which can be marked, and reset, so we can check and see if there is + //any content being provided. entityStream = getMarkableStream(entityStream); if (isInputStreamEmpty(entityStream)) { @@ -52,12 +53,8 @@ public class XmlToCompositeNodeReader { } } - if (eventReader.hasNext() && !isCompositeNodeEvent(eventReader.peek())) { - throw new UnsupportedFormatException("Root element of XML has to be composite element."); - } - final Stack> processingQueue = new Stack<>(); - CompositeNodeWrapper root = null; + NodeWrapper root = null; NodeWrapper element = null; while (eventReader.hasNext()) { final XMLEvent event = eventReader.nextEvent(); @@ -70,17 +67,15 @@ public class XmlToCompositeNodeReader { } NodeWrapper newNode = null; if (isCompositeNodeEvent(event)) { + newNode = resolveCompositeNodeFromStartElement(startElement); if (root == null) { - root = resolveCompositeNodeFromStartElement(startElement); - newNode = root; - } else { - newNode = resolveCompositeNodeFromStartElement(startElement); + root = newNode; } } else if (isSimpleNodeEvent(event)) { + newNode = resolveSimpleNodeFromStartElement(startElement); if (root == null) { - throw new UnsupportedFormatException("Root element of XML has to be composite element."); + root = newNode; } - newNode = resolveSimpleNodeFromStartElement(startElement); } if (newNode != null) { @@ -98,7 +93,7 @@ public class XmlToCompositeNodeReader { throw new UnsupportedFormatException("XML should contain only one root element"); } - return root; + return (Node) root; } /** diff --git a/opendaylight/md-sal/sal-rest-connector/src/main/java/org/opendaylight/controller/sal/rest/impl/XmlToNormalizedNodeReaderWithSchema.java b/opendaylight/md-sal/sal-rest-connector/src/main/java/org/opendaylight/controller/sal/rest/impl/XmlToNormalizedNodeReaderWithSchema.java new file mode 100644 index 0000000000..935d96cb12 --- /dev/null +++ b/opendaylight/md-sal/sal-rest-connector/src/main/java/org/opendaylight/controller/sal/rest/impl/XmlToNormalizedNodeReaderWithSchema.java @@ -0,0 +1,352 @@ +/* + * 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.rest.impl; + +import static com.google.common.base.Preconditions.checkArgument; + +import java.io.BufferedInputStream; +import java.io.IOException; +import java.io.InputStream; +import java.net.URI; +import java.util.HashMap; +import java.util.Map; +import java.util.Stack; +import javax.xml.stream.XMLEventReader; +import javax.xml.stream.XMLInputFactory; +import javax.xml.stream.XMLStreamConstants; +import javax.xml.stream.XMLStreamException; +import javax.xml.stream.events.Characters; +import javax.xml.stream.events.StartElement; +import javax.xml.stream.events.XMLEvent; +import org.opendaylight.controller.sal.restconf.impl.CompositeNodeWrapper; +import org.opendaylight.controller.sal.restconf.impl.IdentityValuesDTO; +import org.opendaylight.controller.sal.restconf.impl.InstanceIdWithSchemaNode; +import org.opendaylight.controller.sal.restconf.impl.NodeWrapper; +import org.opendaylight.controller.sal.restconf.impl.RestCodec; +import org.opendaylight.controller.sal.restconf.impl.RestconfDocumentedException; +import org.opendaylight.controller.sal.restconf.impl.RestconfError.ErrorTag; +import org.opendaylight.controller.sal.restconf.impl.RestconfError.ErrorType; +import org.opendaylight.controller.sal.restconf.impl.SimpleNodeWrapper; +import org.opendaylight.yangtools.yang.common.QName; +import org.opendaylight.yangtools.yang.data.api.Node; +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.TypeDefinition; + +public class XmlToNormalizedNodeReaderWithSchema { + + private final static XMLInputFactory xmlInputFactory = XMLInputFactory.newInstance(); + private XMLEventReader eventReader; + private InstanceIdWithSchemaNode iiWithSchema; + + public XmlToNormalizedNodeReaderWithSchema(final InstanceIdWithSchemaNode iiWithSchema) { + this.iiWithSchema = iiWithSchema; + } + + public Node read(InputStream entityStream) throws XMLStreamException, UnsupportedFormatException, IOException { + // Get an XML stream which can be marked, and reset, so we can check and see if there is + // any content being provided. + entityStream = getMarkableStream(entityStream); + + if (isInputStreamEmpty(entityStream)) { + return null; + } + + eventReader = xmlInputFactory.createXMLEventReader(entityStream); + if (eventReader.hasNext()) { + XMLEvent element = eventReader.peek(); + if (element.isStartDocument()) { + eventReader.nextEvent(); + } + } + + final Stack> processingQueue = new Stack<>(); + NodeWrapper root = null; + NodeWrapper element = null; + Stack processingQueueSchema = new Stack<>(); + + while (eventReader.hasNext()) { + final XMLEvent event = eventReader.nextEvent(); + + if (event.isStartElement()) { + final StartElement startElement = event.asStartElement(); + CompositeNodeWrapper compParentNode = null; + if (!processingQueue.isEmpty() && processingQueue.peek() instanceof CompositeNodeWrapper) { + compParentNode = (CompositeNodeWrapper) processingQueue.peek(); + findSchemaNodeForElement(startElement, processingQueueSchema); + } else { + processingQueueSchema = checkElementAndSchemaNodeNameAndNamespace(startElement, + iiWithSchema.getSchemaNode()); + DataSchemaNode currentSchemaNode = processingQueueSchema.peek(); + if (!(currentSchemaNode instanceof ListSchemaNode) + && !(currentSchemaNode instanceof ContainerSchemaNode)) { + throw new UnsupportedFormatException( + "Top level element has to be of type list or container schema node."); + } + } + + NodeWrapper newNode = null; + if (isCompositeNodeEvent(event)) { + newNode = resolveCompositeNodeFromStartElement(processingQueueSchema.peek().getQName()); + if (root == null) { + root = newNode; + } + } else if (isSimpleNodeEvent(event)) { + newNode = resolveSimpleNodeFromStartElement(processingQueueSchema.peek(), getValueOf(startElement)); + if (root == null) { + root = newNode; + } + } + + if (newNode != null) { + processingQueue.push(newNode); + if (compParentNode != null) { + compParentNode.addValue(newNode); + } + } + } else if (event.isEndElement()) { + element = processingQueue.pop(); +// if(((EndElement)event).getName().getLocalPart().equals + processingQueueSchema.pop(); + } + } + + if (!root.getLocalName().equals(element.getLocalName())) { + throw new UnsupportedFormatException("XML should contain only one root element"); + } + + return root.unwrap(); + } + + private void findSchemaNodeForElement(StartElement element, Stack processingQueueSchema) { + DataSchemaNode currentSchemaNode = processingQueueSchema.peek(); + if (currentSchemaNode instanceof DataNodeContainer) { + final URI realNamespace = getNamespaceFor(element); + final String realName = getLocalNameFor(element); + Map childNamesakes = resolveChildsWithNameAsElement( + ((DataNodeContainer) currentSchemaNode), realName); + DataSchemaNode childDataSchemaNode = childNamesakes.get(realNamespace); + if (childDataSchemaNode == null) { + throw new RestconfDocumentedException("Element " + realName + " has namespace " + realNamespace + + ". Available namespaces are: " + childNamesakes.keySet(), ErrorType.APPLICATION, + ErrorTag.INVALID_VALUE); + } + processingQueueSchema.push(childDataSchemaNode); + } else { + throw new RestconfDocumentedException("Element " + processingQueueSchema.peek().getQName().getLocalName() + + " should be data node container .", ErrorType.APPLICATION, ErrorTag.INVALID_VALUE); + } + + } + + /** + * Returns map of data schema node which are accesible by URI which have equal name + */ + private Map resolveChildsWithNameAsElement(final DataNodeContainer dataNodeContainer, + final String realName) { + final Map namespaceToDataSchemaNode = new HashMap(); + for (DataSchemaNode dataSchemaNode : dataNodeContainer.getChildNodes()) { + if (dataSchemaNode.equals(realName)) { + namespaceToDataSchemaNode.put(dataSchemaNode.getQName().getNamespace(), dataSchemaNode); + } + } + return namespaceToDataSchemaNode; + } + + private final Stack checkElementAndSchemaNodeNameAndNamespace(final StartElement startElement, + final DataSchemaNode node) { + checkArgument(startElement != null, "Start Element cannot be NULL!"); + final String expectedName = node.getQName().getLocalName(); + final String xmlName = getLocalNameFor(startElement); + final URI expectedNamespace = node.getQName().getNamespace(); + final URI xmlNamespace = getNamespaceFor(startElement); + if (!expectedName.equals(xmlName)) { + throw new RestconfDocumentedException("Xml element name: " + xmlName + "\nSchema node name: " + + expectedName, org.opendaylight.controller.sal.restconf.impl.RestconfError.ErrorType.APPLICATION, + ErrorTag.INVALID_VALUE); + } + + if (xmlNamespace != null && !expectedNamespace.equals(xmlNamespace)) { + throw new RestconfDocumentedException("Xml element ns: " + xmlNamespace + "\nSchema node ns: " + + expectedNamespace, + org.opendaylight.controller.sal.restconf.impl.RestconfError.ErrorType.APPLICATION, + ErrorTag.INVALID_VALUE); + } + Stack processingQueueSchema = new Stack<>(); + processingQueueSchema.push(node); + return processingQueueSchema; + } + + /** + * If the input stream is not markable, then it wraps the input stream with a buffered stream, which is mark able. + * That way we can check if the stream is empty safely. + * + * @param entityStream + * @return + */ + private InputStream getMarkableStream(InputStream entityStream) { + if (!entityStream.markSupported()) { + entityStream = new BufferedInputStream(entityStream); + } + return entityStream; + } + + private boolean isInputStreamEmpty(final InputStream entityStream) throws IOException { + boolean isEmpty = false; + entityStream.mark(1); + if (entityStream.read() == -1) { + isEmpty = true; + } + entityStream.reset(); + return isEmpty; + } + + private boolean isSimpleNodeEvent(final XMLEvent event) throws XMLStreamException { + checkArgument(event != null, "XML Event cannot be NULL!"); + if (event.isStartElement()) { + XMLEvent innerEvent = skipCommentsAndWhitespace(); + if (innerEvent != null && (innerEvent.isCharacters() || innerEvent.isEndElement())) { + return true; + } + } + return false; + } + + private boolean isCompositeNodeEvent(final XMLEvent event) throws XMLStreamException { + checkArgument(event != null, "XML Event cannot be NULL!"); + if (event.isStartElement()) { + XMLEvent innerEvent = skipCommentsAndWhitespace(); + if (innerEvent != null) { + if (innerEvent.isStartElement()) { + return true; + } + } + } + return false; + } + + private XMLEvent skipCommentsAndWhitespace() throws XMLStreamException { + while (eventReader.hasNext()) { + XMLEvent event = eventReader.peek(); + if (event.getEventType() == XMLStreamConstants.COMMENT) { + eventReader.nextEvent(); + continue; + } + + if (event.isCharacters()) { + Characters chars = event.asCharacters(); + if (chars.isWhiteSpace()) { + eventReader.nextEvent(); + continue; + } + } + return event; + } + return null; + } + + private CompositeNodeWrapper resolveCompositeNodeFromStartElement(final QName qName) { + // checkArgument(startElement != null, "Start Element cannot be NULL!"); + CompositeNodeWrapper compositeNodeWrapper = new CompositeNodeWrapper("dummy"); + compositeNodeWrapper.setQname(qName); + return compositeNodeWrapper; + + } + + private SimpleNodeWrapper resolveSimpleNodeFromStartElement(final DataSchemaNode node, final String value) + throws XMLStreamException { + // checkArgument(startElement != null, "Start Element cannot be NULL!"); + Object deserializedValue = null; + + if (node instanceof LeafSchemaNode) { + TypeDefinition baseType = RestUtil.resolveBaseTypeFrom(((LeafSchemaNode) node).getType()); + deserializedValue = RestCodec.from(baseType, iiWithSchema.getMountPoint()).deserialize(value); + } else if (node instanceof LeafListSchemaNode) { + TypeDefinition baseType = RestUtil.resolveBaseTypeFrom(((LeafListSchemaNode) node).getType()); + deserializedValue = RestCodec.from(baseType, iiWithSchema.getMountPoint()).deserialize(value); + } + // String data; + // if (data == null) { + // return new EmptyNodeWrapper(getNamespaceFor(startElement), getLocalNameFor(startElement)); + // } + SimpleNodeWrapper simpleNodeWrapper = new SimpleNodeWrapper("dummy", deserializedValue); + simpleNodeWrapper.setQname(node.getQName()); + return simpleNodeWrapper; + } + + private String getValueOf(final StartElement startElement) throws XMLStreamException { + String data = null; + if (eventReader.hasNext()) { + final XMLEvent innerEvent = eventReader.peek(); + if (innerEvent.isCharacters()) { + final Characters chars = innerEvent.asCharacters(); + if (!chars.isWhiteSpace()) { + data = innerEvent.asCharacters().getData(); + data = data + getAdditionalData(eventReader.nextEvent()); + } + } else if (innerEvent.isEndElement()) { + if (startElement.getLocation().getCharacterOffset() == innerEvent.getLocation().getCharacterOffset()) { + data = null; + } else { + data = ""; + } + } + } + return data == null ? null : data.trim(); + } + + private String getAdditionalData(final XMLEvent event) throws XMLStreamException { + String data = ""; + if (eventReader.hasNext()) { + final XMLEvent innerEvent = eventReader.peek(); + if (innerEvent.isCharacters() && !innerEvent.isEndElement()) { + final Characters chars = innerEvent.asCharacters(); + if (!chars.isWhiteSpace()) { + data = innerEvent.asCharacters().getData(); + data = data + getAdditionalData(eventReader.nextEvent()); + } + } + } + return data; + } + + private String getLocalNameFor(final StartElement startElement) { + return startElement.getName().getLocalPart(); + } + + private URI getNamespaceFor(final StartElement startElement) { + String namespaceURI = startElement.getName().getNamespaceURI(); + return namespaceURI.isEmpty() ? null : URI.create(namespaceURI); + } + + private Object resolveValueOfElement(final String value, final StartElement startElement) { + // it could be instance-identifier Built-In Type + if (value.startsWith("/")) { + IdentityValuesDTO iiValue = RestUtil.asInstanceIdentifier(value, new RestUtil.PrefixMapingFromXml( + startElement)); + if (iiValue != null) { + return iiValue; + } + } + // it could be identityref Built-In Type + String[] namespaceAndValue = value.split(":"); + if (namespaceAndValue.length == 2) { + String namespace = startElement.getNamespaceContext().getNamespaceURI(namespaceAndValue[0]); + if (namespace != null && !namespace.isEmpty()) { + return new IdentityValuesDTO(namespace, namespaceAndValue[1], namespaceAndValue[0], value); + } + } + // it is not "prefix:value" but just "value" + return value; + } + +} diff --git a/opendaylight/md-sal/sal-rest-connector/src/main/java/org/opendaylight/controller/sal/restconf/impl/BrokerFacade.java b/opendaylight/md-sal/sal-rest-connector/src/main/java/org/opendaylight/controller/sal/restconf/impl/BrokerFacade.java index 861aaac3d8..e8701f37e5 100644 --- a/opendaylight/md-sal/sal-rest-connector/src/main/java/org/opendaylight/controller/sal/restconf/impl/BrokerFacade.java +++ b/opendaylight/md-sal/sal-rest-connector/src/main/java/org/opendaylight/controller/sal/restconf/impl/BrokerFacade.java @@ -7,38 +7,50 @@ */ package org.opendaylight.controller.sal.restconf.impl; -import com.google.common.util.concurrent.Futures; - +import static org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType.CONFIGURATION; +import static org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType.OPERATIONAL; + +import com.google.common.base.Optional; +import com.google.common.util.concurrent.CheckedFuture; +import com.google.common.util.concurrent.ListenableFuture; +import java.util.ArrayList; +import java.util.Iterator; +import java.util.List; +import java.util.concurrent.ExecutionException; import java.util.concurrent.Future; - import javax.ws.rs.core.Response.Status; - -import org.opendaylight.controller.md.sal.common.api.TransactionStatus; -import org.opendaylight.controller.md.sal.common.api.data.DataReader; +import org.opendaylight.controller.md.sal.common.api.data.AsyncDataBroker.DataChangeScope; +import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType; +import org.opendaylight.controller.md.sal.common.api.data.TransactionCommitFailedException; +import org.opendaylight.controller.md.sal.common.impl.util.compat.DataNormalizationException; +import org.opendaylight.controller.md.sal.common.impl.util.compat.DataNormalizationOperation; +import org.opendaylight.controller.md.sal.common.impl.util.compat.DataNormalizer; +import org.opendaylight.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.controller.md.sal.dom.api.DOMMountPoint; import org.opendaylight.controller.sal.core.api.Broker.ConsumerSession; -import org.opendaylight.controller.sal.core.api.data.DataBrokerService; -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.mount.MountInstance; import org.opendaylight.controller.sal.restconf.impl.RestconfError.ErrorTag; import org.opendaylight.controller.sal.restconf.impl.RestconfError.ErrorType; import org.opendaylight.controller.sal.streams.listeners.ListenerAdapter; import org.opendaylight.yangtools.concepts.ListenerRegistration; import org.opendaylight.yangtools.yang.common.QName; import org.opendaylight.yangtools.yang.common.RpcResult; -import org.opendaylight.yangtools.yang.common.RpcResultBuilder; import org.opendaylight.yangtools.yang.data.api.CompositeNode; import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier; +import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier.PathArgument; +import org.opendaylight.yangtools.yang.data.api.schema.NormalizedNode; import org.slf4j.Logger; import org.slf4j.LoggerFactory; -public class BrokerFacade implements DataReader { +public class BrokerFacade { private final static Logger LOG = LoggerFactory.getLogger(BrokerFacade.class); private final static BrokerFacade INSTANCE = new BrokerFacade(); - - private volatile DataBrokerService dataService; private volatile ConsumerSession context; + private DOMDataBroker domDataBroker; private BrokerFacade() { } @@ -47,154 +59,213 @@ public class BrokerFacade implements DataReader readConfigurationData(final YangInstanceIdentifier path) { + checkPreconditions(); + return readDataViaTransaction(domDataBroker.newReadOnlyTransaction(), CONFIGURATION, path); + } - return dataService.readConfigurationData(path); + public NormalizedNode readConfigurationData(final DOMMountPoint mountPoint, final YangInstanceIdentifier path) { + final Optional domDataBrokerService = mountPoint.getService(DOMDataBroker.class); + if (domDataBrokerService.isPresent()) { + return readDataViaTransaction(domDataBrokerService.get().newReadOnlyTransaction(), CONFIGURATION, path); + } + throw new RestconfDocumentedException("DOM data broker service isn't available for mount point."); } - public CompositeNode readConfigurationDataBehindMountPoint(final MountInstance mountPoint, - final YangInstanceIdentifier path) { - this.checkPreconditions(); + // READ operational + public NormalizedNode readOperationalData(final YangInstanceIdentifier path) { + checkPreconditions(); + return readDataViaTransaction(domDataBroker.newReadOnlyTransaction(), OPERATIONAL, path); + } - LOG.trace("Read Configuration via Restconf: {}", path); + public NormalizedNode readOperationalData(final DOMMountPoint mountPoint, final YangInstanceIdentifier path) { + final Optional domDataBrokerService = mountPoint.getService(DOMDataBroker.class); + if (domDataBrokerService.isPresent()) { + return readDataViaTransaction(domDataBrokerService.get().newReadOnlyTransaction(), OPERATIONAL, path); + } + throw new RestconfDocumentedException("DOM data broker service isn't available for mount point."); + } - return mountPoint.readConfigurationData(path); + // PUT configuration + public CheckedFuture commitConfigurationDataPut( + final YangInstanceIdentifier path, final NormalizedNode payload) { + checkPreconditions(); + DataNormalizationOperation rootOp = ControllerContext.getInstance().getRootOperation(); + return putDataViaTransaction(domDataBroker.newReadWriteTransaction(), CONFIGURATION, path, payload, rootOp); } - @Override - public CompositeNode readOperationalData(final YangInstanceIdentifier path) { - this.checkPreconditions(); + public CheckedFuture commitConfigurationDataPut( + final DOMMountPoint mountPoint, final YangInstanceIdentifier path, final NormalizedNode payload) { + final Optional domDataBrokerService = mountPoint.getService(DOMDataBroker.class); + if (domDataBrokerService.isPresent()) { + DataNormalizationOperation rootOp = new DataNormalizer(mountPoint.getSchemaContext()).getRootOperation(); + return putDataViaTransaction(domDataBrokerService.get().newReadWriteTransaction(), CONFIGURATION, path, + payload, rootOp); + } + throw new RestconfDocumentedException("DOM data broker service isn't available for mount point."); + } - BrokerFacade.LOG.trace("Read Operational via Restconf: {}", path); + // POST configuration + public CheckedFuture commitConfigurationDataPost( + final YangInstanceIdentifier path, final NormalizedNode payload) { + checkPreconditions(); + DataNormalizationOperation rootOp = ControllerContext.getInstance().getRootOperation(); + return postDataViaTransaction(domDataBroker.newReadWriteTransaction(), CONFIGURATION, path, payload, rootOp); + } - return dataService.readOperationalData(path); + public CheckedFuture commitConfigurationDataPost( + final DOMMountPoint mountPoint, final YangInstanceIdentifier path, final NormalizedNode payload) { + final Optional domDataBrokerService = mountPoint.getService(DOMDataBroker.class); + if (domDataBrokerService.isPresent()) { + DataNormalizationOperation rootOp = new DataNormalizer(mountPoint.getSchemaContext()).getRootOperation(); + return postDataViaTransaction(domDataBrokerService.get().newReadWriteTransaction(), CONFIGURATION, path, + payload, rootOp); + } + throw new RestconfDocumentedException("DOM data broker service isn't available for mount point."); } - public CompositeNode readOperationalDataBehindMountPoint(final MountInstance mountPoint, + // DELETE configuration + public CheckedFuture commitConfigurationDataDelete( final YangInstanceIdentifier path) { - this.checkPreconditions(); - - BrokerFacade.LOG.trace("Read Operational via Restconf: {}", path); + checkPreconditions(); + return deleteDataViaTransaction(domDataBroker.newWriteOnlyTransaction(), CONFIGURATION, path); + } - return mountPoint.readOperationalData(path); + public CheckedFuture commitConfigurationDataDelete( + final DOMMountPoint mountPoint, final YangInstanceIdentifier path) { + final Optional domDataBrokerService = mountPoint.getService(DOMDataBroker.class); + if (domDataBrokerService.isPresent()) { + return deleteDataViaTransaction(domDataBrokerService.get().newWriteOnlyTransaction(), CONFIGURATION, path); + } + throw new RestconfDocumentedException("DOM data broker service isn't available for mount point."); } + // RPC public Future> invokeRpc(final QName type, final CompositeNode payload) { this.checkPreconditions(); return context.rpc(type, payload); } - public Future> commitConfigurationDataPut(final YangInstanceIdentifier path, - final CompositeNode payload) { + public void registerToListenDataChanges(final LogicalDatastoreType datastore, final DataChangeScope scope, + final ListenerAdapter listener) { this.checkPreconditions(); - final DataModificationTransaction transaction = dataService.beginTransaction(); - BrokerFacade.LOG.trace("Put Configuration via Restconf: {}", path); - transaction.putConfigurationData(path, payload); - return transaction.commit(); - } + if (listener.isListening()) { + return; + } - public Future> commitConfigurationDataPutBehindMountPoint( - final MountInstance mountPoint, final YangInstanceIdentifier path, final CompositeNode payload) { - this.checkPreconditions(); + YangInstanceIdentifier path = listener.getPath(); + final ListenerRegistration registration = domDataBroker.registerDataChangeListener( + datastore, path, listener, scope); - final DataModificationTransaction transaction = mountPoint.beginTransaction(); - BrokerFacade.LOG.trace("Put Configuration via Restconf: {}", path); - transaction.putConfigurationData(path, payload); - return transaction.commit(); + listener.setRegistration(registration); } - public Future> commitConfigurationDataPost(final YangInstanceIdentifier path, - final CompositeNode payload) { - this.checkPreconditions(); - - final DataModificationTransaction transaction = dataService.beginTransaction(); - /* check for available Node in Configuration DataStore by path */ - CompositeNode availableNode = transaction.readConfigurationData(path); - if (availableNode != null) { - String errMsg = "Post Configuration via Restconf was not executed because data already exists"; - BrokerFacade.LOG.warn((new StringBuilder(errMsg)).append(" : ").append(path).toString()); - - throw new RestconfDocumentedException("Data already exists for path: " + path, ErrorType.PROTOCOL, - ErrorTag.DATA_EXISTS); + private NormalizedNode readDataViaTransaction(final DOMDataReadTransaction transaction, + LogicalDatastoreType datastore, YangInstanceIdentifier path) { + LOG.trace("Read " + datastore.name() + " via Restconf: {}", path); + final ListenableFuture>> listenableFuture = transaction.read(datastore, path); + if (listenableFuture != null) { + Optional> optional; + try { + LOG.debug("Reading result data from transaction."); + optional = listenableFuture.get(); + } catch (InterruptedException | ExecutionException e) { + throw new RestconfDocumentedException("Problem to get data from transaction.", e.getCause()); + + } + if (optional != null) { + if (optional.isPresent()) { + return optional.get(); + } + } } - BrokerFacade.LOG.trace("Post Configuration via Restconf: {}", path); - transaction.putConfigurationData(path, payload); - return transaction.commit(); + return null; } - public Future> commitConfigurationDataPostBehindMountPoint( - final MountInstance mountPoint, final YangInstanceIdentifier path, final CompositeNode payload) { - this.checkPreconditions(); - - final DataModificationTransaction transaction = mountPoint.beginTransaction(); - /* check for available Node in Configuration DataStore by path */ - CompositeNode availableNode = transaction.readConfigurationData(path); - if (availableNode != null) { - String errMsg = "Post Configuration via Restconf was not executed because data already exists"; - BrokerFacade.LOG.warn((new StringBuilder(errMsg)).append(" : ").append(path).toString()); - - throw new RestconfDocumentedException("Data already exists for path: " + path, ErrorType.PROTOCOL, - ErrorTag.DATA_EXISTS); + private CheckedFuture postDataViaTransaction( + final DOMDataReadWriteTransaction rWTransaction, final LogicalDatastoreType datastore, + final YangInstanceIdentifier path, final NormalizedNode payload, DataNormalizationOperation root) { + ListenableFuture>> futureDatastoreData = rWTransaction.read(datastore, path); + try { + final Optional> optionalDatastoreData = futureDatastoreData.get(); + if (optionalDatastoreData.isPresent() && payload.equals(optionalDatastoreData.get())) { + String errMsg = "Post Configuration via Restconf was not executed because data already exists"; + LOG.trace(errMsg + ":{}", path); + throw new RestconfDocumentedException("Data already exists for path: " + path, ErrorType.PROTOCOL, + ErrorTag.DATA_EXISTS); + } + } catch (InterruptedException | ExecutionException e) { + LOG.trace("It wasn't possible to get data loaded from datastore at path " + path); } - BrokerFacade.LOG.trace("Post Configuration via Restconf: {}", path); - transaction.putConfigurationData(path, payload); - return transaction.commit(); - } - public Future> commitConfigurationDataDelete(final YangInstanceIdentifier path) { - this.checkPreconditions(); - return deleteDataAtTarget(path, dataService.beginTransaction()); + ensureParentsByMerge(datastore, path, rWTransaction, root); + rWTransaction.merge(datastore, path, payload); + LOG.trace("Post " + datastore.name() + " via Restconf: {}", path); + return rWTransaction.submit(); } - public Future> commitConfigurationDataDeleteBehindMountPoint( - final MountInstance mountPoint, final YangInstanceIdentifier path) { - this.checkPreconditions(); - return deleteDataAtTarget(path, mountPoint.beginTransaction()); + private CheckedFuture putDataViaTransaction( + final DOMDataReadWriteTransaction writeTransaction, final LogicalDatastoreType datastore, + final YangInstanceIdentifier path, final NormalizedNode payload, DataNormalizationOperation root) { + LOG.trace("Put " + datastore.name() + " via Restconf: {}", path); + ensureParentsByMerge(datastore, path, writeTransaction, root); + writeTransaction.put(datastore, path, payload); + return writeTransaction.submit(); } - private Future> deleteDataAtTarget(final YangInstanceIdentifier path, - final DataModificationTransaction transaction) { - LOG.info("Delete Configuration via Restconf: {}", path); - CompositeNode redDataAtPath = transaction.readConfigurationData(path); - if (redDataAtPath == null) { - return Futures.immediateFuture(RpcResultBuilder. - success(TransactionStatus.COMMITED).build()); - } - transaction.removeConfigurationData(path); - return transaction.commit(); + private CheckedFuture deleteDataViaTransaction( + final DOMDataWriteTransaction writeTransaction, final LogicalDatastoreType datastore, + YangInstanceIdentifier path) { + LOG.info("Delete " + datastore.name() + " via Restconf: {}", path); + writeTransaction.delete(datastore, path); + return writeTransaction.submit(); } - public void registerToListenDataChanges(final ListenerAdapter listener) { - this.checkPreconditions(); + public void setDomDataBroker(DOMDataBroker domDataBroker) { + this.domDataBroker = domDataBroker; + } - if (listener.isListening()) { - return; + private final void ensureParentsByMerge(final LogicalDatastoreType store, + final YangInstanceIdentifier normalizedPath, final DOMDataReadWriteTransaction rwTx, + final DataNormalizationOperation root) { + List currentArguments = new ArrayList<>(); + Iterator iterator = normalizedPath.getPathArguments().iterator(); + DataNormalizationOperation currentOp = root; + while (iterator.hasNext()) { + PathArgument currentArg = iterator.next(); + try { + currentOp = currentOp.getChild(currentArg); + } catch (DataNormalizationException e) { + throw new IllegalArgumentException( + String.format("Invalid child encountered in path %s", normalizedPath), e); + } + currentArguments.add(currentArg); + YangInstanceIdentifier currentPath = YangInstanceIdentifier.create(currentArguments); + + final Optional> datastoreData; + try { + datastoreData = rwTx.read(store, currentPath).get(); + } catch (InterruptedException | ExecutionException e) { + LOG.error("Failed to read pre-existing data from store {} path {}", store, currentPath, e); + throw new IllegalStateException("Failed to read pre-existing data", e); + } + + if (!datastoreData.isPresent() && iterator.hasNext()) { + rwTx.merge(store, currentPath, currentOp.createDefault(currentArg)); + } } - - YangInstanceIdentifier path = listener.getPath(); - final ListenerRegistration registration = dataService.registerDataChangeListener(path, - listener); - - listener.setRegistration(registration); } } diff --git a/opendaylight/md-sal/sal-rest-connector/src/main/java/org/opendaylight/controller/sal/restconf/impl/ControllerContext.java b/opendaylight/md-sal/sal-rest-connector/src/main/java/org/opendaylight/controller/sal/restconf/impl/ControllerContext.java index dad7a2cda2..93e6a2c0e9 100644 --- a/opendaylight/md-sal/sal-rest-connector/src/main/java/org/opendaylight/controller/sal/restconf/impl/ControllerContext.java +++ b/opendaylight/md-sal/sal-rest-connector/src/main/java/org/opendaylight/controller/sal/restconf/impl/ControllerContext.java @@ -9,15 +9,13 @@ package org.opendaylight.controller.sal.restconf.impl; import com.google.common.base.Function; import com.google.common.base.Objects; +import com.google.common.base.Optional; import com.google.common.base.Preconditions; import com.google.common.base.Predicate; import com.google.common.base.Splitter; import com.google.common.base.Strings; -import com.google.common.collect.BiMap; -import com.google.common.collect.HashBiMap; import com.google.common.collect.ImmutableMap; import com.google.common.collect.Iterables; - import java.io.UnsupportedEncodingException; import java.net.URI; import java.net.URLDecoder; @@ -29,24 +27,27 @@ import java.util.Collections; import java.util.HashMap; import java.util.List; import java.util.Map; +import java.util.Map.Entry; import java.util.Set; import java.util.concurrent.atomic.AtomicReference; - import javax.ws.rs.core.Response.Status; - -import org.opendaylight.controller.sal.core.api.mount.MountInstance; -import org.opendaylight.controller.sal.core.api.mount.MountService; +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.DOMMountPoint; +import org.opendaylight.controller.md.sal.dom.api.DOMMountPointService; import org.opendaylight.controller.sal.rest.api.Draft02; import org.opendaylight.controller.sal.rest.impl.RestUtil; import org.opendaylight.controller.sal.restconf.impl.RestconfError.ErrorTag; import org.opendaylight.controller.sal.restconf.impl.RestconfError.ErrorType; import org.opendaylight.yangtools.concepts.Codec; import org.opendaylight.yangtools.yang.common.QName; +import org.opendaylight.yangtools.yang.data.api.CompositeNode; import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier; import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier.InstanceIdentifierBuilder; import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier.NodeIdentifier; import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier.NodeIdentifierWithPredicates; import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier.PathArgument; +import org.opendaylight.yangtools.yang.data.api.schema.NormalizedNode; import org.opendaylight.yangtools.yang.model.api.AnyXmlSchemaNode; import org.opendaylight.yangtools.yang.model.api.ChoiceCaseNode; import org.opendaylight.yangtools.yang.model.api.ChoiceNode; @@ -83,21 +84,20 @@ public class ControllerContext implements SchemaContextListener { private static final Splitter SLASH_SPLITTER = Splitter.on('/'); - private final BiMap uriToModuleName = HashBiMap. create(); - - private final Map moduleNameToUri = uriToModuleName.inverse(); - private final AtomicReference> qnameToRpc = new AtomicReference<>(Collections.emptyMap()); private volatile SchemaContext globalSchema; - private volatile MountService mountService; + private volatile DOMMountPointService mountService; + + private DataNormalizer dataNormalizer; public void setGlobalSchema(final SchemaContext globalSchema) { this.globalSchema = globalSchema; + this.dataNormalizer = new DataNormalizer(globalSchema); } - public void setMountService(final MountService mountService) { + public void setMountService(final DOMMountPointService mountService) { this.mountService = mountService; } @@ -143,7 +143,7 @@ public class ControllerContext implements SchemaContextListener { } InstanceIdentifierBuilder builder = YangInstanceIdentifier.builder(); - Module latestModule = this.getLatestModule(globalSchema, startModule); + Module latestModule = globalSchema.findModuleByName(startModule, null); InstanceIdWithSchemaNode iiWithSchemaNode = this.collectPathArguments(builder, pathArgs, latestModule, null, toMountPointIdentifier); @@ -175,59 +175,38 @@ public class ControllerContext implements SchemaContextListener { return list; } - - private Module getLatestModule(final SchemaContext schema, final String moduleName) { - Preconditions.checkArgument(schema != null); - Preconditions.checkArgument(moduleName != null && !moduleName.isEmpty()); - - Predicate filter = new Predicate() { - @Override - public boolean apply(final Module m) { - return Objects.equal(m.getName(), moduleName); - } - }; - - Iterable modules = Iterables.filter(schema.getModules(), filter); - return this.filterLatestModule(modules); - } - - private Module filterLatestModule(final Iterable modules) { - Module latestModule = modules.iterator().hasNext() ? modules.iterator().next() : null; - for (final Module module : modules) { - if (module.getRevision().after(latestModule.getRevision())) { - latestModule = module; - } - } - return latestModule; - } - public Module findModuleByName(final String moduleName) { this.checkPreconditions(); Preconditions.checkArgument(moduleName != null && !moduleName.isEmpty()); - return this.getLatestModule(globalSchema, moduleName); + return globalSchema.findModuleByName(moduleName, null); } - public Module findModuleByName(final MountInstance mountPoint, final String moduleName) { + public Module findModuleByName(final DOMMountPoint mountPoint, final String moduleName) { Preconditions.checkArgument(moduleName != null && mountPoint != null); final SchemaContext mountPointSchema = mountPoint.getSchemaContext(); - return mountPointSchema == null ? null : this.getLatestModule(mountPointSchema, moduleName); + if (mountPointSchema == null) { + return null; + } + + return mountPointSchema.findModuleByName(moduleName, null); } public Module findModuleByNamespace(final URI namespace) { this.checkPreconditions(); Preconditions.checkArgument(namespace != null); - - final Set moduleSchemas = globalSchema.findModuleByNamespace(namespace); - return moduleSchemas == null ? null : this.filterLatestModule(moduleSchemas); + return globalSchema.findModuleByNamespaceAndRevision(namespace, null); } - public Module findModuleByNamespace(final MountInstance mountPoint, final URI namespace) { + public Module findModuleByNamespace(final DOMMountPoint mountPoint, final URI namespace) { Preconditions.checkArgument(namespace != null && mountPoint != null); final SchemaContext mountPointSchema = mountPoint.getSchemaContext(); - Set moduleSchemas = mountPointSchema == null ? null : mountPointSchema.findModuleByNamespace(namespace); - return moduleSchemas == null ? null : this.filterLatestModule(moduleSchemas); + if (mountPointSchema == null) { + return null; + } + + return mountPointSchema.findModuleByNamespaceAndRevision(namespace, null); } public Module findModuleByNameAndRevision(final QName module) { @@ -237,7 +216,7 @@ public class ControllerContext implements SchemaContextListener { return globalSchema.findModuleByName(module.getLocalName(), module.getRevision()); } - public Module findModuleByNameAndRevision(final MountInstance mountPoint, final QName module) { + public Module findModuleByNameAndRevision(final DOMMountPoint mountPoint, final QName module) { this.checkPreconditions(); Preconditions.checkArgument(module != null && module.getLocalName() != null && module.getRevision() != null && mountPoint != null); @@ -294,42 +273,26 @@ public class ControllerContext implements SchemaContextListener { public String findModuleNameByNamespace(final URI namespace) { this.checkPreconditions(); - String moduleName = this.uriToModuleName.get(namespace); - if (moduleName == null) { - final Module module = this.findModuleByNamespace(namespace); - if (module != null) { - moduleName = module.getName(); - this.uriToModuleName.put(namespace, moduleName); - } - } - - return moduleName; + final Module module = this.findModuleByNamespace(namespace); + return module == null ? null : module.getName(); } - public String findModuleNameByNamespace(final MountInstance mountPoint, final URI namespace) { + public String findModuleNameByNamespace(final DOMMountPoint mountPoint, final URI namespace) { final Module module = this.findModuleByNamespace(mountPoint, namespace); return module == null ? null : module.getName(); } public URI findNamespaceByModuleName(final String moduleName) { - URI namespace = this.moduleNameToUri.get(moduleName); - if (namespace == null) { - Module module = this.findModuleByName(moduleName); - if (module != null) { - URI _namespace = module.getNamespace(); - namespace = _namespace; - this.uriToModuleName.put(namespace, moduleName); - } - } - return namespace; + final Module module = this.findModuleByName(moduleName); + return module == null ? null : module.getNamespace(); } - public URI findNamespaceByModuleName(final MountInstance mountPoint, final String moduleName) { + public URI findNamespaceByModuleName(final DOMMountPoint mountPoint, final String moduleName) { final Module module = this.findModuleByName(mountPoint, moduleName); return module == null ? null : module.getNamespace(); } - public Set getAllModules(final MountInstance mountPoint) { + public Set getAllModules(final DOMMountPoint mountPoint) { this.checkPreconditions(); SchemaContext schemaContext = mountPoint == null ? null : mountPoint.getSchemaContext(); @@ -341,52 +304,36 @@ public class ControllerContext implements SchemaContextListener { return globalSchema.getModules(); } + private static final CharSequence toRestconfIdentifier(final SchemaContext context, final QName qname) { + final Module schema = context.findModuleByNamespaceAndRevision(qname.getNamespace(), qname.getRevision()); + return schema == null ? null : schema.getName() + ':' + qname.getLocalName(); + } + public CharSequence toRestconfIdentifier(final QName qname) { this.checkPreconditions(); - String module = this.uriToModuleName.get(qname.getNamespace()); - if (module == null) { - final Module moduleSchema = globalSchema.findModuleByNamespaceAndRevision(qname.getNamespace(), - qname.getRevision()); - if (moduleSchema == null) { - return null; - } - - this.uriToModuleName.put(qname.getNamespace(), moduleSchema.getName()); - module = moduleSchema.getName(); - } - - StringBuilder builder = new StringBuilder(); - builder.append(module); - builder.append(":"); - builder.append(qname.getLocalName()); - return builder.toString(); + return toRestconfIdentifier(globalSchema, qname); } - public CharSequence toRestconfIdentifier(final MountInstance mountPoint, final QName qname) { + public CharSequence toRestconfIdentifier(final DOMMountPoint mountPoint, final QName qname) { if (mountPoint == null) { return null; } - SchemaContext schemaContext = mountPoint.getSchemaContext(); - - final Module moduleSchema = schemaContext.findModuleByNamespaceAndRevision(qname.getNamespace(), - qname.getRevision()); - if (moduleSchema == null) { - return null; - } - - StringBuilder builder = new StringBuilder(); - builder.append(moduleSchema.getName()); - builder.append(":"); - builder.append(qname.getLocalName()); - return builder.toString(); + return toRestconfIdentifier(mountPoint.getSchemaContext(), qname); } public Module getRestconfModule() { return findModuleByNameAndRevision(Draft02.RestConfModule.IETF_RESTCONF_QNAME); } + private static final Predicate ERRORS_GROUPING_FILTER = new Predicate() { + @Override + public boolean apply(final GroupingDefinition g) { + return Draft02.RestConfModule.ERRORS_GROUPING_SCHEMA_NODE.equals(g.getQName().getLocalName()); + } + }; + public DataSchemaNode getRestconfModuleErrorsSchemaNode() { Module restconfModule = getRestconfModule(); if (restconfModule == null) { @@ -395,22 +342,22 @@ public class ControllerContext implements SchemaContextListener { Set groupings = restconfModule.getGroupings(); - final Predicate filter = new Predicate() { - @Override - public boolean apply(final GroupingDefinition g) { - return Objects.equal(g.getQName().getLocalName(), Draft02.RestConfModule.ERRORS_GROUPING_SCHEMA_NODE); - } - }; - - Iterable filteredGroups = Iterables.filter(groupings, filter); + Iterable filteredGroups = Iterables.filter(groupings, ERRORS_GROUPING_FILTER); final GroupingDefinition restconfGrouping = Iterables.getFirst(filteredGroups, null); - List instanceDataChildrenByName = this.findInstanceDataChildrenByName(restconfGrouping, + List instanceDataChildrenByName = findInstanceDataChildrenByName(restconfGrouping, Draft02.RestConfModule.ERRORS_CONTAINER_SCHEMA_NODE); return Iterables.getFirst(instanceDataChildrenByName, null); } + private static final Predicate GROUPING_FILTER = new Predicate() { + @Override + public boolean apply(final GroupingDefinition g) { + return Draft02.RestConfModule.RESTCONF_GROUPING_SCHEMA_NODE.equals(g.getQName().getLocalName()); + } + }; + public DataSchemaNode getRestconfModuleRestConfSchemaNode(final Module inRestconfModule, final String schemaNodeName) { Module restconfModule = inRestconfModule; if (restconfModule == null) { @@ -422,50 +369,41 @@ public class ControllerContext implements SchemaContextListener { } Set groupings = restconfModule.getGroupings(); - - final Predicate filter = new Predicate() { - @Override - public boolean apply(final GroupingDefinition g) { - return Objects.equal(g.getQName().getLocalName(), Draft02.RestConfModule.RESTCONF_GROUPING_SCHEMA_NODE); - } - }; - - Iterable filteredGroups = Iterables.filter(groupings, filter); - + Iterable filteredGroups = Iterables.filter(groupings, GROUPING_FILTER); final GroupingDefinition restconfGrouping = Iterables.getFirst(filteredGroups, null); - List instanceDataChildrenByName = this.findInstanceDataChildrenByName(restconfGrouping, + List instanceDataChildrenByName = findInstanceDataChildrenByName(restconfGrouping, Draft02.RestConfModule.RESTCONF_CONTAINER_SCHEMA_NODE); final DataSchemaNode restconfContainer = Iterables.getFirst(instanceDataChildrenByName, null); if (Objects.equal(schemaNodeName, Draft02.RestConfModule.OPERATIONS_CONTAINER_SCHEMA_NODE)) { - List instances = this.findInstanceDataChildrenByName( + List instances = findInstanceDataChildrenByName( ((DataNodeContainer) restconfContainer), Draft02.RestConfModule.OPERATIONS_CONTAINER_SCHEMA_NODE); return Iterables.getFirst(instances, null); } else if (Objects.equal(schemaNodeName, Draft02.RestConfModule.STREAMS_CONTAINER_SCHEMA_NODE)) { - List instances = this.findInstanceDataChildrenByName( + List instances = findInstanceDataChildrenByName( ((DataNodeContainer) restconfContainer), Draft02.RestConfModule.STREAMS_CONTAINER_SCHEMA_NODE); return Iterables.getFirst(instances, null); } else if (Objects.equal(schemaNodeName, Draft02.RestConfModule.STREAM_LIST_SCHEMA_NODE)) { - List instances = this.findInstanceDataChildrenByName( + List instances = findInstanceDataChildrenByName( ((DataNodeContainer) restconfContainer), Draft02.RestConfModule.STREAMS_CONTAINER_SCHEMA_NODE); final DataSchemaNode modules = Iterables.getFirst(instances, null); - instances = this.findInstanceDataChildrenByName(((DataNodeContainer) modules), + instances = findInstanceDataChildrenByName(((DataNodeContainer) modules), Draft02.RestConfModule.STREAM_LIST_SCHEMA_NODE); return Iterables.getFirst(instances, null); } else if (Objects.equal(schemaNodeName, Draft02.RestConfModule.MODULES_CONTAINER_SCHEMA_NODE)) { - List instances = this.findInstanceDataChildrenByName( + List instances = findInstanceDataChildrenByName( ((DataNodeContainer) restconfContainer), Draft02.RestConfModule.MODULES_CONTAINER_SCHEMA_NODE); return Iterables.getFirst(instances, null); } else if (Objects.equal(schemaNodeName, Draft02.RestConfModule.MODULE_LIST_SCHEMA_NODE)) { - List instances = this.findInstanceDataChildrenByName( + List instances = findInstanceDataChildrenByName( ((DataNodeContainer) restconfContainer), Draft02.RestConfModule.MODULES_CONTAINER_SCHEMA_NODE); final DataSchemaNode modules = Iterables.getFirst(instances, null); - instances = this.findInstanceDataChildrenByName(((DataNodeContainer) modules), + instances = findInstanceDataChildrenByName(((DataNodeContainer) modules), Draft02.RestConfModule.MODULE_LIST_SCHEMA_NODE); return Iterables.getFirst(instances, null); } else if (Objects.equal(schemaNodeName, Draft02.RestConfModule.STREAMS_CONTAINER_SCHEMA_NODE)) { - List instances = this.findInstanceDataChildrenByName( + List instances = findInstanceDataChildrenByName( ((DataNodeContainer) restconfContainer), Draft02.RestConfModule.STREAMS_CONTAINER_SCHEMA_NODE); return Iterables.getFirst(instances, null); } @@ -508,9 +446,9 @@ public class ControllerContext implements SchemaContextListener { DataSchemaNode ret = container.getDataChildByName(name); if (ret == null) { for (final DataSchemaNode node : container.getChildNodes()) { - if ((node instanceof ChoiceCaseNode)) { - final ChoiceCaseNode caseNode = ((ChoiceCaseNode) node); - DataSchemaNode childByQName = ControllerContext.childByQName(caseNode, name); + if ((node instanceof ChoiceNode)) { + final ChoiceNode choiceNode = ((ChoiceNode) node); + DataSchemaNode childByQName = ControllerContext.childByQName(choiceNode, name); if (childByQName != null) { return childByQName; } @@ -525,7 +463,7 @@ public class ControllerContext implements SchemaContextListener { } private InstanceIdWithSchemaNode collectPathArguments(final InstanceIdentifierBuilder builder, - final List strings, final DataNodeContainer parentNode, final MountInstance mountPoint, + final List strings, final DataNodeContainer parentNode, final DOMMountPoint mountPoint, final boolean returnJustMountPoint) { Preconditions.> checkNotNull(strings); @@ -557,12 +495,13 @@ public class ControllerContext implements SchemaContextListener { } final YangInstanceIdentifier partialPath = builder.toInstance(); - final MountInstance mount = mountService.getMountPoint(partialPath); - if (mount == null) { + final Optional mountOpt = mountService.getMountPoint(partialPath); + if (!mountOpt.isPresent()) { LOG.debug("Instance identifier to missing mount point: {}", partialPath); throw new RestconfDocumentedException("Mount point does not exist.", ErrorType.PROTOCOL, ErrorTag.UNKNOWN_ELEMENT); } + DOMMountPoint mount = mountOpt.get(); final SchemaContext mountPointSchema = mount.getSchemaContext(); if (mountPointSchema == null) { @@ -587,8 +526,7 @@ public class ControllerContext implements SchemaContextListener { ErrorType.PROTOCOL, ErrorTag.INVALID_VALUE); } - final Module moduleBehindMountPoint = this - .getLatestModule(mountPointSchema, moduleNameBehindMountPoint); + final Module moduleBehindMountPoint = mountPointSchema.findModuleByName(moduleNameBehindMountPoint, null); if (moduleBehindMountPoint == null) { throw new RestconfDocumentedException("\"" + moduleName + "\" module does not exist in mount point.", ErrorType.PROTOCOL, ErrorTag.UNKNOWN_ELEMENT); @@ -601,21 +539,25 @@ public class ControllerContext implements SchemaContextListener { Module module = null; if (mountPoint == null) { - module = this.getLatestModule(globalSchema, moduleName); + module = globalSchema.findModuleByName(moduleName, null); if (module == null) { throw new RestconfDocumentedException("\"" + moduleName + "\" module does not exist.", ErrorType.PROTOCOL, ErrorTag.UNKNOWN_ELEMENT); } } else { SchemaContext schemaContext = mountPoint.getSchemaContext(); - module = schemaContext == null ? null : this.getLatestModule(schemaContext, moduleName); + if (schemaContext != null) { + module = schemaContext.findModuleByName(moduleName, null); + } else { + module = null; + } if (module == null) { throw new RestconfDocumentedException("\"" + moduleName + "\" module does not exist in mount point.", ErrorType.PROTOCOL, ErrorTag.UNKNOWN_ELEMENT); } } - targetNode = this.findInstanceDataChildByNameAndNamespace(parentNode, nodeName, module.getNamespace()); + targetNode = findInstanceDataChildByNameAndNamespace(parentNode, nodeName, module.getNamespace()); if (targetNode == null) { throw new RestconfDocumentedException("URI has bad format. Possible reasons:\n" + " 1. \"" + head + "\" was not found in parent data node.\n" + " 2. \"" + head @@ -623,7 +565,7 @@ public class ControllerContext implements SchemaContextListener { ErrorType.PROTOCOL, ErrorTag.INVALID_VALUE); } } else { - final List potentialSchemaNodes = this.findInstanceDataChildrenByName(parentNode, nodeName); + final List potentialSchemaNodes = findInstanceDataChildrenByName(parentNode, nodeName); if (potentialSchemaNodes.size() > 1) { final StringBuilder strBuilder = new StringBuilder(); for (final DataSchemaNode potentialNodeSchema : potentialSchemaNodes) { @@ -693,11 +635,11 @@ public class ControllerContext implements SchemaContextListener { return new InstanceIdWithSchemaNode(builder.toInstance(), targetNode, mountPoint); } - public DataSchemaNode findInstanceDataChildByNameAndNamespace(final DataNodeContainer container, final String name, + public static DataSchemaNode findInstanceDataChildByNameAndNamespace(final DataNodeContainer container, final String name, final URI namespace) { Preconditions. checkNotNull(namespace); - final List potentialSchemaNodes = this.findInstanceDataChildrenByName(container, name); + final List potentialSchemaNodes = findInstanceDataChildrenByName(container, name); Predicate filter = new Predicate() { @Override @@ -710,16 +652,23 @@ public class ControllerContext implements SchemaContextListener { return Iterables.getFirst(result, null); } - public List findInstanceDataChildrenByName(final DataNodeContainer container, final String name) { + public static List findInstanceDataChildrenByName(final DataNodeContainer container, final String name) { Preconditions. checkNotNull(container); Preconditions. checkNotNull(name); List instantiatedDataNodeContainers = new ArrayList(); - this.collectInstanceDataNodeContainers(instantiatedDataNodeContainers, container, name); + collectInstanceDataNodeContainers(instantiatedDataNodeContainers, container, name); return instantiatedDataNodeContainers; } - private void collectInstanceDataNodeContainers(final List potentialSchemaNodes, + private static final Function> CHOICE_FUNCTION = new Function>() { + @Override + public Set apply(final ChoiceNode node) { + return node.getCases(); + } + }; + + private static void collectInstanceDataNodeContainers(final List potentialSchemaNodes, final DataNodeContainer container, final String name) { Predicate filter = new Predicate() { @@ -734,37 +683,28 @@ public class ControllerContext implements SchemaContextListener { // Can't combine this loop with the filter above because the filter is // lazily-applied by Iterables.filter. for (final DataSchemaNode potentialNode : nodes) { - if (this.isInstantiatedDataSchema(potentialNode)) { + if (isInstantiatedDataSchema(potentialNode)) { potentialSchemaNodes.add(potentialNode); } } - Iterable choiceNodes = Iterables. filter(container.getChildNodes(), ChoiceNode.class); - - final Function> choiceFunction = new Function>() { - @Override - public Set apply(final ChoiceNode node) { - return node.getCases(); - } - }; - - Iterable> map = Iterables.> transform(choiceNodes, - choiceFunction); + Iterable choiceNodes = Iterables.filter(container.getChildNodes(), ChoiceNode.class); + Iterable> map = Iterables.transform(choiceNodes, CHOICE_FUNCTION); final Iterable allCases = Iterables. concat(map); for (final ChoiceCaseNode caze : allCases) { - this.collectInstanceDataNodeContainers(potentialSchemaNodes, caze, name); + collectInstanceDataNodeContainers(potentialSchemaNodes, caze, name); } } - public boolean isInstantiatedDataSchema(final DataSchemaNode node) { + public static boolean isInstantiatedDataSchema(final DataSchemaNode node) { return node instanceof LeafSchemaNode || node instanceof LeafListSchemaNode || node instanceof ContainerSchemaNode || node instanceof ListSchemaNode || node instanceof AnyXmlSchemaNode; } private void addKeyValue(final HashMap map, final DataSchemaNode node, final String uriValue, - final MountInstance mountPoint) { + final DOMMountPoint mountPoint) { Preconditions. checkNotNull(uriValue); Preconditions.checkArgument((node instanceof LeafSchemaNode)); @@ -891,11 +831,7 @@ public class ControllerContext implements SchemaContextListener { } private CharSequence convertToRestconfIdentifier(final NodeIdentifier argument, final ContainerSchemaNode node) { - StringBuilder builder = new StringBuilder(); - builder.append("/"); - QName nodeType = argument.getNodeType(); - builder.append(this.toRestconfIdentifier(nodeType)); - return builder.toString(); + return "/" + this.toRestconfIdentifier(argument.getNodeType()); } private CharSequence convertToRestconfIdentifier(final NodeIdentifierWithPredicates argument, @@ -905,9 +841,9 @@ public class ControllerContext implements SchemaContextListener { final Map keyValues = argument.getKeyValues(); StringBuilder builder = new StringBuilder(); - builder.append("/"); + builder.append('/'); builder.append(nodeIdentifier); - builder.append("/"); + builder.append('/'); List keyDefinition = node.getKeyDefinition(); boolean hasElements = false; @@ -915,7 +851,7 @@ public class ControllerContext implements SchemaContextListener { if (!hasElements) { hasElements = true; } else { - builder.append("/"); + builder.append('/'); } try { @@ -947,4 +883,35 @@ public class ControllerContext implements SchemaContextListener { + Arrays. asList(container, name).toString()); } } + + public Entry> toNormalized(final YangInstanceIdentifier legacy, + final CompositeNode compositeNode) { + try { + return dataNormalizer.toNormalized(legacy, compositeNode); + } catch (NullPointerException e) { + throw new RestconfDocumentedException("Data normalizer isn't set. Normalization isn't possible", e); + } + } + + public YangInstanceIdentifier toNormalized(final YangInstanceIdentifier legacy) { + try { + return dataNormalizer.toNormalized(legacy); + } catch (NullPointerException e) { + throw new RestconfDocumentedException("Data normalizer isn't set. Normalization isn't possible", e); + } + } + + public CompositeNode toLegacy(final YangInstanceIdentifier instanceIdentifier, + final NormalizedNode normalizedNode) { + try { + return dataNormalizer.toLegacy(instanceIdentifier, normalizedNode); + } catch (NullPointerException e) { + throw new RestconfDocumentedException("Data normalizer isn't set. Normalization isn't possible", e); + } + } + + public DataNormalizationOperation getRootOperation() { + return dataNormalizer.getRootOperation(); + } + } diff --git a/opendaylight/md-sal/sal-rest-connector/src/main/java/org/opendaylight/controller/sal/restconf/impl/InstanceIdWithSchemaNode.java b/opendaylight/md-sal/sal-rest-connector/src/main/java/org/opendaylight/controller/sal/restconf/impl/InstanceIdWithSchemaNode.java index 12c1ba66ec..b58a6eeaea 100644 --- a/opendaylight/md-sal/sal-rest-connector/src/main/java/org/opendaylight/controller/sal/restconf/impl/InstanceIdWithSchemaNode.java +++ b/opendaylight/md-sal/sal-rest-connector/src/main/java/org/opendaylight/controller/sal/restconf/impl/InstanceIdWithSchemaNode.java @@ -7,7 +7,7 @@ */ package org.opendaylight.controller.sal.restconf.impl; -import org.opendaylight.controller.sal.core.api.mount.MountInstance; +import org.opendaylight.controller.md.sal.dom.api.DOMMountPoint; import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier; import org.opendaylight.yangtools.yang.model.api.DataSchemaNode; @@ -15,10 +15,10 @@ public class InstanceIdWithSchemaNode { private final YangInstanceIdentifier instanceIdentifier; private final DataSchemaNode schemaNode; - private final MountInstance mountPoint; + private final DOMMountPoint mountPoint; public InstanceIdWithSchemaNode(YangInstanceIdentifier instanceIdentifier, DataSchemaNode schemaNode, - MountInstance mountPoint) { + DOMMountPoint mountPoint) { this.instanceIdentifier = instanceIdentifier; this.schemaNode = schemaNode; this.mountPoint = mountPoint; @@ -32,7 +32,7 @@ public class InstanceIdWithSchemaNode { return schemaNode; } - public MountInstance getMountPoint() { + public DOMMountPoint getMountPoint() { return mountPoint; } diff --git a/opendaylight/md-sal/sal-rest-connector/src/main/java/org/opendaylight/controller/sal/restconf/impl/RestCodec.java b/opendaylight/md-sal/sal-rest-connector/src/main/java/org/opendaylight/controller/sal/restconf/impl/RestCodec.java index ff90dd8439..665fafacc8 100644 --- a/opendaylight/md-sal/sal-rest-connector/src/main/java/org/opendaylight/controller/sal/restconf/impl/RestCodec.java +++ b/opendaylight/md-sal/sal-rest-connector/src/main/java/org/opendaylight/controller/sal/restconf/impl/RestCodec.java @@ -12,7 +12,7 @@ import java.util.ArrayList; import java.util.HashMap; import java.util.List; import java.util.Map; -import org.opendaylight.controller.sal.core.api.mount.MountInstance; +import org.opendaylight.controller.md.sal.dom.api.DOMMountPoint; import org.opendaylight.controller.sal.rest.impl.RestUtil; import org.opendaylight.controller.sal.restconf.impl.IdentityValuesDTO.IdentityValue; import org.opendaylight.controller.sal.restconf.impl.IdentityValuesDTO.Predicate; @@ -47,7 +47,7 @@ public class RestCodec { } public static final Codec from(final TypeDefinition typeDefinition, - final MountInstance mountPoint) { + final DOMMountPoint mountPoint) { return new ObjectCodec(typeDefinition, mountPoint); } @@ -62,7 +62,7 @@ public class RestCodec { private final TypeDefinition type; - private ObjectCodec(final TypeDefinition typeDefinition, final MountInstance mountPoint) { + private ObjectCodec(final TypeDefinition typeDefinition, final DOMMountPoint mountPoint) { type = RestUtil.resolveBaseTypeFrom(typeDefinition); if (type instanceof IdentityrefTypeDefinition) { identityrefCodec = new IdentityrefCodecImpl(mountPoint); @@ -158,9 +158,9 @@ public class RestCodec { private final Logger logger = LoggerFactory.getLogger(IdentityrefCodecImpl.class); - private final MountInstance mountPoint; + private final DOMMountPoint mountPoint; - public IdentityrefCodecImpl(final MountInstance mountPoint) { + public IdentityrefCodecImpl(final DOMMountPoint mountPoint) { this.mountPoint = mountPoint; } @@ -200,9 +200,9 @@ public class RestCodec { public static class InstanceIdentifierCodecImpl implements InstanceIdentifierCodec { private final Logger logger = LoggerFactory.getLogger(InstanceIdentifierCodecImpl.class); - private final MountInstance mountPoint; + private final DOMMountPoint mountPoint; - public InstanceIdentifierCodecImpl(final MountInstance mountPoint) { + public InstanceIdentifierCodecImpl(final DOMMountPoint mountPoint) { this.mountPoint = mountPoint; } @@ -244,7 +244,7 @@ public class RestCodec { for (int i = 0; i < identities.size(); i++) { IdentityValue identityValue = identities.get(i); URI validNamespace = resolveValidNamespace(identityValue.getNamespace(), mountPoint); - DataSchemaNode node = ControllerContext.getInstance().findInstanceDataChildByNameAndNamespace( + DataSchemaNode node = ControllerContext.findInstanceDataChildByNameAndNamespace( parentContainer, identityValue.getValue(), validNamespace); if (node == null) { logger.info("'{}' node was not found in {}", identityValue, parentContainer.getChildNodes()); @@ -271,7 +271,7 @@ public class RestCodec { Map predicatesMap = new HashMap<>(); for (Predicate predicate : identityValue.getPredicates()) { validNamespace = resolveValidNamespace(predicate.getName().getNamespace(), mountPoint); - DataSchemaNode listKey = ControllerContext.getInstance() + DataSchemaNode listKey = ControllerContext .findInstanceDataChildByNameAndNamespace(listNode, predicate.getName().getValue(), validNamespace); predicatesMap.put(listKey.getQName(), predicate.getValue()); @@ -286,7 +286,7 @@ public class RestCodec { } result.add(pathArgument); if (i < identities.size() - 1) { // last element in instance-identifier can be other than - // DataNodeContainer + // DataNodeContainer if (node instanceof DataNodeContainer) { parentContainer = (DataNodeContainer) node; } else { @@ -318,7 +318,7 @@ public class RestCodec { } } - private static Module getModuleByNamespace(final String namespace, final MountInstance mountPoint) { + private static Module getModuleByNamespace(final String namespace, final DOMMountPoint mountPoint) { URI validNamespace = resolveValidNamespace(namespace, mountPoint); Module module = null; @@ -334,7 +334,7 @@ public class RestCodec { return module; } - private static URI resolveValidNamespace(final String namespace, final MountInstance mountPoint) { + private static URI resolveValidNamespace(final String namespace, final DOMMountPoint mountPoint) { URI validNamespace; if (mountPoint != null) { validNamespace = ControllerContext.getInstance().findNamespaceByModuleName(mountPoint, namespace); diff --git a/opendaylight/md-sal/sal-rest-connector/src/main/java/org/opendaylight/controller/sal/restconf/impl/RestconfImpl.java b/opendaylight/md-sal/sal-rest-connector/src/main/java/org/opendaylight/controller/sal/restconf/impl/RestconfImpl.java index 4c005c6ae5..73ca02c505 100644 --- a/opendaylight/md-sal/sal-rest-connector/src/main/java/org/opendaylight/controller/sal/restconf/impl/RestconfImpl.java +++ b/opendaylight/md-sal/sal-rest-connector/src/main/java/org/opendaylight/controller/sal/restconf/impl/RestconfImpl.java @@ -15,6 +15,7 @@ import com.google.common.base.Strings; import com.google.common.collect.ImmutableList; import com.google.common.collect.Iterables; import com.google.common.collect.Lists; + import java.net.URI; import java.text.ParseException; import java.text.SimpleDateFormat; @@ -24,17 +25,20 @@ import java.util.Collection; import java.util.Collections; import java.util.Date; import java.util.HashMap; +import java.util.Iterator; import java.util.List; import java.util.Map; import java.util.Set; -import java.util.concurrent.Future; import javax.ws.rs.core.Response; import javax.ws.rs.core.Response.Status; import javax.ws.rs.core.UriBuilder; import javax.ws.rs.core.UriInfo; + import org.apache.commons.lang3.StringUtils; -import org.opendaylight.controller.md.sal.common.api.TransactionStatus; -import org.opendaylight.controller.sal.core.api.mount.MountInstance; +import org.opendaylight.controller.md.sal.common.api.data.AsyncDataBroker.DataChangeScope; +import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType; +import org.opendaylight.controller.md.sal.common.impl.util.compat.DataNormalizer; +import org.opendaylight.controller.md.sal.dom.api.DOMMountPoint; import org.opendaylight.controller.sal.rest.api.Draft02; import org.opendaylight.controller.sal.rest.api.RestconfService; import org.opendaylight.controller.sal.restconf.impl.RestconfError.ErrorTag; @@ -47,16 +51,19 @@ import org.opendaylight.controller.sal.streams.listeners.Notificator; import org.opendaylight.controller.sal.streams.websockets.WebSocketServer; import org.opendaylight.yangtools.concepts.Codec; import org.opendaylight.yangtools.yang.common.QName; +import org.opendaylight.yangtools.yang.common.QNameModule; import org.opendaylight.yangtools.yang.common.RpcError; import org.opendaylight.yangtools.yang.common.RpcResult; import org.opendaylight.yangtools.yang.data.api.CompositeNode; +import org.opendaylight.yangtools.yang.data.api.MutableCompositeNode; +import org.opendaylight.yangtools.yang.data.api.Node; +import org.opendaylight.yangtools.yang.data.api.SimpleNode; import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier; import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier.InstanceIdentifierBuilder; import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier.NodeIdentifierWithPredicates; import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier.PathArgument; -import org.opendaylight.yangtools.yang.data.api.MutableCompositeNode; -import org.opendaylight.yangtools.yang.data.api.Node; -import org.opendaylight.yangtools.yang.data.api.SimpleNode; +import org.opendaylight.yangtools.yang.data.api.schema.NormalizedNode; +import org.opendaylight.yangtools.yang.data.composite.node.schema.cnsn.parser.CnSnToNormalizedNodeParserFactory; import org.opendaylight.yangtools.yang.data.impl.ImmutableCompositeNode; import org.opendaylight.yangtools.yang.data.impl.NodeFactory; import org.opendaylight.yangtools.yang.model.api.AnyXmlSchemaNode; @@ -76,6 +83,8 @@ import org.opendaylight.yangtools.yang.model.api.type.IdentityrefTypeDefinition; import org.opendaylight.yangtools.yang.model.util.EmptyType; import org.opendaylight.yangtools.yang.parser.builder.impl.ContainerSchemaNodeBuilder; import org.opendaylight.yangtools.yang.parser.builder.impl.LeafSchemaNodeBuilder; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; public class RestconfImpl implements RestconfService { private enum UriParameters { @@ -84,7 +93,7 @@ public class RestconfImpl implements RestconfService { private String uriParameterName; - UriParameters(String uriParameterName) { + UriParameters(final String uriParameterName) { this.uriParameterName = uriParameterName; } @@ -96,6 +105,8 @@ public class RestconfImpl implements RestconfService { private final static RestconfImpl INSTANCE = new RestconfImpl(); + private static final int NOTIFICATION_PORT = 8181; + private static final int CHAR_NOT_FOUND = -1; private final static String MOUNT_POINT_MODULE_NAME = "ietf-netconf"; @@ -110,6 +121,30 @@ public class RestconfImpl implements RestconfService { private ControllerContext controllerContext; + private static final Logger LOG = LoggerFactory.getLogger(RestconfImpl.class); + + private static final DataChangeScope DEFAULT_SCOPE = DataChangeScope.BASE; + + private static final LogicalDatastoreType DEFAULT_DATASTORE = LogicalDatastoreType.CONFIGURATION; + + private static final URI NAMESPACE_EVENT_SUBSCRIPTION_AUGMENT = URI.create("urn:sal:restconf:event:subscription"); + + private static final Date EVENT_SUBSCRIPTION_AUGMENT_REVISION; + + private static final String DATASTORE_PARAM_NAME = "datastore"; + + private static final String SCOPE_PARAM_NAME = "scope"; + + static { + try { + EVENT_SUBSCRIPTION_AUGMENT_REVISION = new SimpleDateFormat("yyyy-MM-dd").parse("2014-07-08"); + } catch (ParseException e) { + throw new RestconfDocumentedException( + "It wasn't possible to convert revision date of sal-remote-augment to date", ErrorType.APPLICATION, + ErrorTag.OPERATION_FAILED); + } + } + public void setBroker(final BrokerFacade broker) { this.broker = broker; } @@ -168,7 +203,7 @@ public class RestconfImpl implements RestconfService { @Override public StructuredData getModules(final String identifier, final UriInfo uriInfo) { Set modules = null; - MountInstance mountPoint = null; + DOMMountPoint mountPoint = null; if (identifier.contains(ControllerContext.MOUNT)) { InstanceIdWithSchemaNode mountPointIdentifier = this.controllerContext.toMountPointIdentifier(identifier); mountPoint = mountPointIdentifier.getMountPoint(); @@ -199,7 +234,7 @@ public class RestconfImpl implements RestconfService { public StructuredData getModule(final String identifier, final UriInfo uriInfo) { final QName moduleNameAndRevision = this.getModuleNameAndRevision(identifier); Module module = null; - MountInstance mountPoint = null; + DOMMountPoint mountPoint = null; if (identifier.contains(ControllerContext.MOUNT)) { InstanceIdWithSchemaNode mountPointIdentifier = this.controllerContext.toMountPointIdentifier(identifier); mountPoint = mountPointIdentifier.getMountPoint(); @@ -230,7 +265,7 @@ public class RestconfImpl implements RestconfService { @Override public StructuredData getOperations(final String identifier, final UriInfo uriInfo) { Set modules = null; - MountInstance mountPoint = null; + DOMMountPoint mountPoint = null; if (identifier.contains(ControllerContext.MOUNT)) { InstanceIdWithSchemaNode mountPointIdentifier = this.controllerContext.toMountPointIdentifier(identifier); mountPoint = mountPointIdentifier.getMountPoint(); @@ -245,7 +280,7 @@ public class RestconfImpl implements RestconfService { } private StructuredData operationsFromModulesToStructuredData(final Set modules, - final MountInstance mountPoint, boolean prettyPrint) { + final DOMMountPoint mountPoint, final boolean prettyPrint) { final List> operationsAsData = new ArrayList>(); Module restconfModule = this.getRestconfModule(); final DataSchemaNode operationsSchemaNode = controllerContext.getRestconfModuleRestConfSchemaNode( @@ -321,31 +356,31 @@ public class RestconfImpl implements RestconfService { private CompositeNode toStreamCompositeNode(final String streamName, final DataSchemaNode streamSchemaNode) { final List> streamNodeValues = new ArrayList>(); - List instanceDataChildrenByName = this.controllerContext.findInstanceDataChildrenByName( + List instanceDataChildrenByName = ControllerContext.findInstanceDataChildrenByName( ((DataNodeContainer) streamSchemaNode), "name"); final DataSchemaNode nameSchemaNode = Iterables.getFirst(instanceDataChildrenByName, null); streamNodeValues - .add(NodeFactory. createImmutableSimpleNode(nameSchemaNode.getQName(), null, streamName)); + .add(NodeFactory. createImmutableSimpleNode(nameSchemaNode.getQName(), null, streamName)); - instanceDataChildrenByName = this.controllerContext.findInstanceDataChildrenByName( + instanceDataChildrenByName = ControllerContext.findInstanceDataChildrenByName( ((DataNodeContainer) streamSchemaNode), "description"); final DataSchemaNode descriptionSchemaNode = Iterables.getFirst(instanceDataChildrenByName, null); streamNodeValues.add(NodeFactory. createImmutableSimpleNode(descriptionSchemaNode.getQName(), null, "DESCRIPTION_PLACEHOLDER")); - instanceDataChildrenByName = this.controllerContext.findInstanceDataChildrenByName( + instanceDataChildrenByName = ControllerContext.findInstanceDataChildrenByName( ((DataNodeContainer) streamSchemaNode), "replay-support"); final DataSchemaNode replaySupportSchemaNode = Iterables.getFirst(instanceDataChildrenByName, null); streamNodeValues.add(NodeFactory. createImmutableSimpleNode(replaySupportSchemaNode.getQName(), null, Boolean.valueOf(true))); - instanceDataChildrenByName = this.controllerContext.findInstanceDataChildrenByName( + instanceDataChildrenByName = ControllerContext.findInstanceDataChildrenByName( ((DataNodeContainer) streamSchemaNode), "replay-log-creation-time"); final DataSchemaNode replayLogCreationTimeSchemaNode = Iterables.getFirst(instanceDataChildrenByName, null); streamNodeValues.add(NodeFactory. createImmutableSimpleNode(replayLogCreationTimeSchemaNode.getQName(), null, "")); - instanceDataChildrenByName = this.controllerContext.findInstanceDataChildrenByName( + instanceDataChildrenByName = ControllerContext.findInstanceDataChildrenByName( ((DataNodeContainer) streamSchemaNode), "events"); final DataSchemaNode eventsSchemaNode = Iterables.getFirst(instanceDataChildrenByName, null); streamNodeValues.add(NodeFactory. createImmutableSimpleNode(eventsSchemaNode.getQName(), null, "")); @@ -355,26 +390,26 @@ public class RestconfImpl implements RestconfService { private CompositeNode toModuleCompositeNode(final Module module, final DataSchemaNode moduleSchemaNode) { final List> moduleNodeValues = new ArrayList>(); - List instanceDataChildrenByName = this.controllerContext.findInstanceDataChildrenByName( + List instanceDataChildrenByName = ControllerContext.findInstanceDataChildrenByName( ((DataNodeContainer) moduleSchemaNode), "name"); final DataSchemaNode nameSchemaNode = Iterables.getFirst(instanceDataChildrenByName, null); moduleNodeValues.add(NodeFactory. createImmutableSimpleNode(nameSchemaNode.getQName(), null, module.getName())); - instanceDataChildrenByName = this.controllerContext.findInstanceDataChildrenByName( + instanceDataChildrenByName = ControllerContext.findInstanceDataChildrenByName( ((DataNodeContainer) moduleSchemaNode), "revision"); final DataSchemaNode revisionSchemaNode = Iterables.getFirst(instanceDataChildrenByName, null); Date _revision = module.getRevision(); moduleNodeValues.add(NodeFactory. createImmutableSimpleNode(revisionSchemaNode.getQName(), null, REVISION_FORMAT.format(_revision))); - instanceDataChildrenByName = this.controllerContext.findInstanceDataChildrenByName( + instanceDataChildrenByName = ControllerContext.findInstanceDataChildrenByName( ((DataNodeContainer) moduleSchemaNode), "namespace"); final DataSchemaNode namespaceSchemaNode = Iterables.getFirst(instanceDataChildrenByName, null); moduleNodeValues.add(NodeFactory. createImmutableSimpleNode(namespaceSchemaNode.getQName(), null, module.getNamespace().toString())); - instanceDataChildrenByName = this.controllerContext.findInstanceDataChildrenByName( + instanceDataChildrenByName = ControllerContext.findInstanceDataChildrenByName( ((DataNodeContainer) moduleSchemaNode), "feature"); final DataSchemaNode featureSchemaNode = Iterables.getFirst(instanceDataChildrenByName, null); for (final FeatureDefinition feature : module.getFeatures()) { @@ -405,7 +440,7 @@ public class RestconfImpl implements RestconfService { return callRpc(rpc, payload, parsePrettyPrintParameter(uriInfo)); } - private void validateInput(final DataSchemaNode inputSchema, final CompositeNode payload) { + private void validateInput(final DataSchemaNode inputSchema, final Node payload) { if (inputSchema != null && payload == null) { // expected a non null payload throw new RestconfDocumentedException("Input is required.", ErrorType.PROTOCOL, ErrorTag.MALFORMED_MESSAGE); @@ -416,6 +451,7 @@ public class RestconfImpl implements RestconfService { // else // { // TODO: Validate "mandatory" and "config" values here??? Or should those be + // those be // validate in a more central location inside MD-SAL core. // } } @@ -436,7 +472,16 @@ public class RestconfImpl implements RestconfService { String streamName = null; if (!Iterables.isEmpty(pathIdentifier.getPathArguments())) { String fullRestconfIdentifier = this.controllerContext.toFullRestconfIdentifier(pathIdentifier); - streamName = Notificator.createStreamNameFromUri(fullRestconfIdentifier); + + LogicalDatastoreType datastore = parseEnumTypeParameter(value, LogicalDatastoreType.class, + DATASTORE_PARAM_NAME); + datastore = datastore == null ? DEFAULT_DATASTORE : datastore; + + DataChangeScope scope = parseEnumTypeParameter(value, DataChangeScope.class, SCOPE_PARAM_NAME); + scope = scope == null ? DEFAULT_SCOPE : scope; + + streamName = Notificator.createStreamNameFromUri(fullRestconfIdentifier + "/datastore=" + datastore + + "/scope=" + scope); } if (Strings.isNullOrEmpty(streamName)) { @@ -453,7 +498,7 @@ public class RestconfImpl implements RestconfService { final MutableCompositeNode responseData = NodeFactory.createMutableCompositeNode(rpc.getOutput().getQName(), null, output, null, null); - if (!Notificator.existListenerFor(pathIdentifier)) { + if (!Notificator.existListenerFor(streamName)) { Notificator.createListener(pathIdentifier, streamName); } @@ -470,7 +515,7 @@ public class RestconfImpl implements RestconfService { private RpcExecutor resolveIdentifierInInvokeRpc(final String identifier) { String identifierEncoded = null; - MountInstance mountPoint = null; + DOMMountPoint mountPoint = null; if (identifier.contains(ControllerContext.MOUNT)) { // mounted RPC call - look up mount instance. InstanceIdWithSchemaNode mountPointId = controllerContext.toMountPointIdentifier(identifier); @@ -529,7 +574,7 @@ public class RestconfImpl implements RestconfService { return null; } - private StructuredData callRpc(final RpcExecutor rpcExecutor, final CompositeNode payload, boolean prettyPrint) { + private StructuredData callRpc(final RpcExecutor rpcExecutor, final CompositeNode payload, final boolean prettyPrint) { if (rpcExecutor == null) { throw new RestconfDocumentedException("RPC does not exist.", ErrorType.RPC, ErrorTag.UNKNOWN_ELEMENT); } @@ -582,18 +627,23 @@ public class RestconfImpl implements RestconfService { @Override public StructuredData readConfigurationData(final String identifier, final UriInfo uriInfo) { - final InstanceIdWithSchemaNode iiWithData = this.controllerContext.toInstanceIdentifier(identifier); - CompositeNode data = null; - MountInstance mountPoint = iiWithData.getMountPoint(); + final InstanceIdWithSchemaNode iiWithData = controllerContext.toInstanceIdentifier(identifier); + DOMMountPoint mountPoint = iiWithData.getMountPoint(); + NormalizedNode data = null; + YangInstanceIdentifier normalizedII; if (mountPoint != null) { - data = broker.readConfigurationDataBehindMountPoint(mountPoint, iiWithData.getInstanceIdentifier()); + normalizedII = new DataNormalizer(mountPoint.getSchemaContext()).toNormalized(iiWithData.getInstanceIdentifier()); + data = broker.readConfigurationData(mountPoint, normalizedII); } else { - data = broker.readConfigurationData(iiWithData.getInstanceIdentifier()); + normalizedII = controllerContext.toNormalized(iiWithData.getInstanceIdentifier()); + data = broker.readConfigurationData(normalizedII); } - data = pruneDataAtDepth(data, parseDepthParameter(uriInfo)); - boolean prettyPrintMode = parsePrettyPrintParameter(uriInfo); - return new StructuredData(data, iiWithData.getSchemaNode(), iiWithData.getMountPoint(), prettyPrintMode); + final CompositeNode compositeNode = datastoreNormalizedNodeToCompositeNode(data, iiWithData.getSchemaNode()); + final CompositeNode prunedCompositeNode = pruneDataAtDepth(compositeNode, parseDepthParameter(uriInfo)); + + final boolean prettyPrintMode = parsePrettyPrintParameter(uriInfo); + return new StructuredData(prunedCompositeNode, iiWithData.getSchemaNode(), mountPoint, prettyPrintMode); } @SuppressWarnings("unchecked") @@ -640,52 +690,57 @@ public class RestconfImpl implements RestconfService { @Override public StructuredData readOperationalData(final String identifier, final UriInfo info) { - final InstanceIdWithSchemaNode iiWithData = this.controllerContext.toInstanceIdentifier(identifier); - CompositeNode data = null; - MountInstance mountPoint = iiWithData.getMountPoint(); + final InstanceIdWithSchemaNode iiWithData = controllerContext.toInstanceIdentifier(identifier); + DOMMountPoint mountPoint = iiWithData.getMountPoint(); + NormalizedNode data = null; + YangInstanceIdentifier normalizedII; if (mountPoint != null) { - data = broker.readOperationalDataBehindMountPoint(mountPoint, iiWithData.getInstanceIdentifier()); + normalizedII = new DataNormalizer(mountPoint.getSchemaContext()).toNormalized(iiWithData.getInstanceIdentifier()); + data = broker.readOperationalData(mountPoint, normalizedII); } else { - data = broker.readOperationalData(iiWithData.getInstanceIdentifier()); + normalizedII = controllerContext.toNormalized(iiWithData.getInstanceIdentifier()); + data = broker.readOperationalData(normalizedII); } - data = pruneDataAtDepth(data, parseDepthParameter(info)); - boolean prettyPrintMode = parsePrettyPrintParameter(info); - return new StructuredData(data, iiWithData.getSchemaNode(), mountPoint, prettyPrintMode); + final CompositeNode compositeNode = datastoreNormalizedNodeToCompositeNode(data, iiWithData.getSchemaNode()); + final CompositeNode prunedCompositeNode = pruneDataAtDepth(compositeNode, parseDepthParameter(info)); + + final boolean prettyPrintMode = parsePrettyPrintParameter(info); + return new StructuredData(prunedCompositeNode, iiWithData.getSchemaNode(), mountPoint, prettyPrintMode); } - private boolean parsePrettyPrintParameter(UriInfo info) { + private boolean parsePrettyPrintParameter(final UriInfo info) { String param = info.getQueryParameters(false).getFirst(UriParameters.PRETTY_PRINT.toString()); return Boolean.parseBoolean(param); } @Override - public Response updateConfigurationData(final String identifier, final CompositeNode payload) { + public Response updateConfigurationData(final String identifier, final Node payload) { final InstanceIdWithSchemaNode iiWithData = this.controllerContext.toInstanceIdentifier(identifier); validateInput(iiWithData.getSchemaNode(), payload); - MountInstance mountPoint = iiWithData.getMountPoint(); + DOMMountPoint mountPoint = iiWithData.getMountPoint(); final CompositeNode value = this.normalizeNode(payload, iiWithData.getSchemaNode(), mountPoint); - validateListKeysEqualityInPayloadAndUri(iiWithData, payload); - RpcResult status = null; + validateListKeysEqualityInPayloadAndUri(iiWithData, value); + final NormalizedNode datastoreNormalizedNode = compositeNodeToDatastoreNormalizedNode(value, + iiWithData.getSchemaNode()); + + YangInstanceIdentifier normalizedII; try { if (mountPoint != null) { - status = broker.commitConfigurationDataPutBehindMountPoint(mountPoint, - iiWithData.getInstanceIdentifier(), value).get(); + normalizedII = new DataNormalizer(mountPoint.getSchemaContext()).toNormalized(iiWithData.getInstanceIdentifier()); + broker.commitConfigurationDataPut(mountPoint, normalizedII, datastoreNormalizedNode).get(); } else { - status = broker.commitConfigurationDataPut(iiWithData.getInstanceIdentifier(), value).get(); + normalizedII = controllerContext.toNormalized(iiWithData.getInstanceIdentifier()); + broker.commitConfigurationDataPut(normalizedII, datastoreNormalizedNode).get(); } } catch (Exception e) { throw new RestconfDocumentedException("Error updating data", e); } - if (status.getResult() == TransactionStatus.COMMITED) { - return Response.status(Status.OK).build(); - } - - return Response.status(Status.INTERNAL_SERVER_ERROR).build(); + return Response.status(Status.OK).build(); } /** @@ -734,7 +789,7 @@ public class RestconfImpl implements RestconfService { } @Override - public Response createConfigurationData(final String identifier, final CompositeNode payload) { + public Response createConfigurationData(final String identifier, final Node payload) { if (payload == null) { throw new RestconfDocumentedException("Input is required.", ErrorType.PROTOCOL, ErrorTag.MALFORMED_MESSAGE); } @@ -765,50 +820,43 @@ public class RestconfImpl implements RestconfService { final InstanceIdWithSchemaNode incompleteInstIdWithData = this.controllerContext .toInstanceIdentifier(identifier); final DataNodeContainer parentSchema = (DataNodeContainer) incompleteInstIdWithData.getSchemaNode(); - MountInstance mountPoint = incompleteInstIdWithData.getMountPoint(); - final Module module = this.findModule(mountPoint, payload); + DOMMountPoint mountPoint = incompleteInstIdWithData.getMountPoint(); + final Module module = findModule(mountPoint, payload); if (module == null) { throw new RestconfDocumentedException("Module was not found for \"" + payloadNS + "\"", ErrorType.PROTOCOL, ErrorTag.UNKNOWN_ELEMENT); } String payloadName = this.getName(payload); - final DataSchemaNode schemaNode = this.controllerContext.findInstanceDataChildByNameAndNamespace( + final DataSchemaNode schemaNode = ControllerContext.findInstanceDataChildByNameAndNamespace( parentSchema, payloadName, module.getNamespace()); value = this.normalizeNode(payload, schemaNode, mountPoint); - iiWithData = this.addLastIdentifierFromData(incompleteInstIdWithData, value, schemaNode); + iiWithData = addLastIdentifierFromData(incompleteInstIdWithData, value, schemaNode); } - RpcResult status = null; - MountInstance mountPoint = iiWithData.getMountPoint(); + final NormalizedNode datastoreNormalizedData = compositeNodeToDatastoreNormalizedNode(value, + iiWithData.getSchemaNode()); + DOMMountPoint mountPoint = iiWithData.getMountPoint(); + YangInstanceIdentifier normalizedII; + try { if (mountPoint != null) { - Future> future = broker.commitConfigurationDataPostBehindMountPoint( - mountPoint, iiWithData.getInstanceIdentifier(), value); - status = future == null ? null : future.get(); + normalizedII = new DataNormalizer(mountPoint.getSchemaContext()).toNormalized(iiWithData.getInstanceIdentifier()); + broker.commitConfigurationDataPost(mountPoint, normalizedII, datastoreNormalizedData); } else { - Future> future = broker.commitConfigurationDataPost( - iiWithData.getInstanceIdentifier(), value); - status = future == null ? null : future.get(); + normalizedII = controllerContext.toNormalized(iiWithData.getInstanceIdentifier()); + broker.commitConfigurationDataPost(normalizedII, datastoreNormalizedData); } } catch (Exception e) { throw new RestconfDocumentedException("Error creating data", e); } - if (status == null) { - return Response.status(Status.ACCEPTED).build(); - } - - if (status.getResult() == TransactionStatus.COMMITED) { - return Response.status(Status.NO_CONTENT).build(); - } - - return Response.status(Status.INTERNAL_SERVER_ERROR).build(); + return Response.status(Status.NO_CONTENT).build(); } @Override - public Response createConfigurationData(final CompositeNode payload) { + public Response createConfigurationData(final Node payload) { if (payload == null) { throw new RestconfDocumentedException("Input is required.", ErrorType.PROTOCOL, ErrorTag.MALFORMED_MESSAGE); } @@ -828,62 +876,60 @@ public class RestconfImpl implements RestconfService { } String payloadName = this.getName(payload); - final DataSchemaNode schemaNode = this.controllerContext.findInstanceDataChildByNameAndNamespace(module, + final DataSchemaNode schemaNode = ControllerContext.findInstanceDataChildByNameAndNamespace(module, payloadName, module.getNamespace()); final CompositeNode value = this.normalizeNode(payload, schemaNode, null); final InstanceIdWithSchemaNode iiWithData = this.addLastIdentifierFromData(null, value, schemaNode); - RpcResult status = null; - MountInstance mountPoint = iiWithData.getMountPoint(); + final NormalizedNode datastoreNormalizedData = compositeNodeToDatastoreNormalizedNode(value, schemaNode); + DOMMountPoint mountPoint = iiWithData.getMountPoint(); + YangInstanceIdentifier normalizedII; try { if (mountPoint != null) { - Future> future = broker.commitConfigurationDataPostBehindMountPoint( - mountPoint, iiWithData.getInstanceIdentifier(), value); - status = future == null ? null : future.get(); + normalizedII = new DataNormalizer(mountPoint.getSchemaContext()).toNormalized(iiWithData.getInstanceIdentifier()); + broker.commitConfigurationDataPost(mountPoint, normalizedII, datastoreNormalizedData); + } else { - Future> future = broker.commitConfigurationDataPost( - iiWithData.getInstanceIdentifier(), value); - status = future == null ? null : future.get(); + normalizedII = controllerContext.toNormalized(iiWithData.getInstanceIdentifier()); + broker.commitConfigurationDataPost(normalizedII, datastoreNormalizedData); } } catch (Exception e) { throw new RestconfDocumentedException("Error creating data", e); } - if (status == null) { - return Response.status(Status.ACCEPTED).build(); - } - - if (status.getResult() == TransactionStatus.COMMITED) { - return Response.status(Status.NO_CONTENT).build(); - } - - return Response.status(Status.INTERNAL_SERVER_ERROR).build(); + return Response.status(Status.NO_CONTENT).build(); } @Override public Response deleteConfigurationData(final String identifier) { - final InstanceIdWithSchemaNode iiWithData = this.controllerContext.toInstanceIdentifier(identifier); - RpcResult status = null; - MountInstance mountPoint = iiWithData.getMountPoint(); + final InstanceIdWithSchemaNode iiWithData = controllerContext.toInstanceIdentifier(identifier); + DOMMountPoint mountPoint = iiWithData.getMountPoint(); + YangInstanceIdentifier normalizedII; try { if (mountPoint != null) { - status = broker.commitConfigurationDataDeleteBehindMountPoint(mountPoint, - iiWithData.getInstanceIdentifier()).get(); + normalizedII = new DataNormalizer(mountPoint.getSchemaContext()).toNormalized(iiWithData.getInstanceIdentifier()); + broker.commitConfigurationDataDelete(mountPoint, normalizedII); } else { - status = broker.commitConfigurationDataDelete(iiWithData.getInstanceIdentifier()).get(); + normalizedII = controllerContext.toNormalized(iiWithData.getInstanceIdentifier()); + broker.commitConfigurationDataDelete(normalizedII).get(); } } catch (Exception e) { throw new RestconfDocumentedException("Error creating data", e); } - if (status.getResult() == TransactionStatus.COMMITED) { - return Response.status(Status.OK).build(); - } - - return Response.status(Status.INTERNAL_SERVER_ERROR).build(); + return Response.status(Status.OK).build(); } + /** + * Subscribes to some path in schema context (stream) to listen on changes on this stream. + * + * Additional parameters for subscribing to stream are loaded via rpc input parameters: + *
        + *
      • datastore
      • - default CONFIGURATION (other values of {@link LogicalDatastoreType} enum type) + *
      • scope
      • - default BASE (other values of {@link DataChangeScope}) + *
      + */ @Override public Response subscribeToStream(final String identifier, final UriInfo uriInfo) { final String streamName = Notificator.createStreamNameFromUri(identifier); @@ -896,18 +942,98 @@ public class RestconfImpl implements RestconfService { throw new RestconfDocumentedException("Stream was not found.", ErrorType.PROTOCOL, ErrorTag.UNKNOWN_ELEMENT); } - broker.registerToListenDataChanges(listener); + Map paramToValues = resolveValuesFromUri(identifier); + LogicalDatastoreType datastore = parserURIEnumParameter(LogicalDatastoreType.class, + paramToValues.get(DATASTORE_PARAM_NAME)); + if (datastore == null) { + throw new RestconfDocumentedException("Stream name doesn't contains datastore value (pattern /datastore=)", + ErrorType.APPLICATION, ErrorTag.MISSING_ATTRIBUTE); + } + DataChangeScope scope = parserURIEnumParameter(DataChangeScope.class, paramToValues.get(SCOPE_PARAM_NAME)); + if (scope == null) { + throw new RestconfDocumentedException("Stream name doesn't contains datastore value (pattern /scope=)", + ErrorType.APPLICATION, ErrorTag.MISSING_ATTRIBUTE); + } + + broker.registerToListenDataChanges(datastore, scope, listener); final UriBuilder uriBuilder = uriInfo.getAbsolutePathBuilder(); - UriBuilder port = uriBuilder.port(WebSocketServer.getInstance().getPort()); + int notificationPort = NOTIFICATION_PORT; + try { + WebSocketServer webSocketServerInstance = WebSocketServer.getInstance(); + notificationPort = webSocketServerInstance.getPort(); + } catch (NullPointerException e) { + WebSocketServer.createInstance(NOTIFICATION_PORT); + } + UriBuilder port = uriBuilder.port(notificationPort); final URI uriToWebsocketServer = port.replacePath(streamName).build(); return Response.status(Status.OK).location(uriToWebsocketServer).build(); } - private Module findModule(final MountInstance mountPoint, final CompositeNode data) { - if (data instanceof CompositeNodeWrapper) { - return findModule(mountPoint, (CompositeNodeWrapper) data); + /** + * Load parameter for subscribing to stream from input composite node + * + * @param compNode + * contains value + * @return enum object if its string value is equal to {@code paramName}. In other cases null. + */ + private T parseEnumTypeParameter(final CompositeNode compNode, final Class classDescriptor, + final String paramName) { + QNameModule salRemoteAugment = QNameModule.create(NAMESPACE_EVENT_SUBSCRIPTION_AUGMENT, + EVENT_SUBSCRIPTION_AUGMENT_REVISION); + SimpleNode simpleNode = compNode.getFirstSimpleByName(QName.create(salRemoteAugment, paramName)); + if (simpleNode == null) { + return null; + } + Object rawValue = simpleNode.getValue(); + if (!(rawValue instanceof String)) { + return null; + } + + return resolveAsEnum(classDescriptor, (String) rawValue); + } + + /** + * Checks whether {@code value} is one of the string representation of enumeration {@code classDescriptor} + * + * @return enum object if string value of {@code classDescriptor} enumeration is equal to {@code value}. Other cases + * null. + */ + private T parserURIEnumParameter(final Class classDescriptor, final String value) { + if (Strings.isNullOrEmpty(value)) { + return null; + } + return resolveAsEnum(classDescriptor, value); + } + + private T resolveAsEnum(final Class classDescriptor, final String value) { + T[] enumConstants = classDescriptor.getEnumConstants(); + if (enumConstants != null) { + for (T enm : classDescriptor.getEnumConstants()) { + if (((Enum) enm).name().equals(value)) { + return enm; + } + } + } + return null; + } + + private Map resolveValuesFromUri(final String uri) { + Map result = new HashMap<>(); + String[] tokens = uri.split("/"); + for (int i = 1; i < tokens.length; i++) { + String[] parameterTokens = tokens[i].split("="); + if (parameterTokens.length == 2) { + result.put(parameterTokens[0], parameterTokens[1]); + } + } + return result; + } + + private Module findModule(final DOMMountPoint mountPoint, final Node data) { + if (data instanceof NodeWrapper) { + return findModule(mountPoint, (NodeWrapper) data); } else if (data != null) { URI namespace = data.getNodeType().getNamespace(); if (mountPoint != null) { @@ -921,7 +1047,7 @@ public class RestconfImpl implements RestconfService { } } - private Module findModule(final MountInstance mountPoint, final CompositeNodeWrapper data) { + private Module findModule(final DOMMountPoint mountPoint, final NodeWrapper data) { URI namespace = data.getNamespace(); Preconditions. checkNotNull(namespace); @@ -956,15 +1082,10 @@ public class RestconfImpl implements RestconfService { iiBuilder = YangInstanceIdentifier.builder(iiOriginal); } - if ((schemaOfData instanceof ListSchemaNode)) { - HashMap keys = this.resolveKeysFromData(((ListSchemaNode) schemaOfData), data); - iiBuilder.nodeWithKey(schemaOfData.getQName(), keys); - } else { - iiBuilder.node(schemaOfData.getQName()); - } + iiBuilder.node(schemaOfData.getQName()); YangInstanceIdentifier instance = iiBuilder.toInstance(); - MountInstance mountPoint = null; + DOMMountPoint mountPoint = null; if (identifierWithSchemaNode != null) { mountPoint = identifierWithSchemaNode.getMountPoint(); } @@ -972,45 +1093,17 @@ public class RestconfImpl implements RestconfService { return new InstanceIdWithSchemaNode(instance, schemaOfData, mountPoint); } - private HashMap resolveKeysFromData(final ListSchemaNode listNode, final CompositeNode dataNode) { - final HashMap keyValues = new HashMap(); - List _keyDefinition = listNode.getKeyDefinition(); - for (final QName key : _keyDefinition) { - SimpleNode head = null; - String localName = key.getLocalName(); - List> simpleNodesByName = dataNode.getSimpleNodesByName(localName); - if (simpleNodesByName != null) { - head = Iterables.getFirst(simpleNodesByName, null); - } - - Object dataNodeKeyValueObject = null; - if (head != null) { - dataNodeKeyValueObject = head.getValue(); - } - - if (dataNodeKeyValueObject == null) { - throw new RestconfDocumentedException("Data contains list \"" + dataNode.getNodeType().getLocalName() - + "\" which does not contain key: \"" + key.getLocalName() + "\"", ErrorType.PROTOCOL, - ErrorTag.INVALID_VALUE); - } - - keyValues.put(key, dataNodeKeyValueObject); - } - - return keyValues; - } - private boolean endsWithMountPoint(final String identifier) { return identifier.endsWith(ControllerContext.MOUNT) || identifier.endsWith(ControllerContext.MOUNT + "/"); } - private boolean representsMountPointRootData(final CompositeNode data) { + private boolean representsMountPointRootData(final Node data) { URI namespace = this.namespace(data); return (SchemaContext.NAME.getNamespace().equals(namespace) /* - * || MOUNT_POINT_MODULE_NAME .equals( namespace . - * toString( ) ) - */) - && SchemaContext.NAME.getLocalName().equals(this.localName(data)); + * || MOUNT_POINT_MODULE_NAME .equals( namespace . + * toString( ) ) + */) + && SchemaContext.NAME.getLocalName().equals(this.localName(data)); } private String addMountPointIdentifier(final String identifier) { @@ -1022,8 +1115,7 @@ public class RestconfImpl implements RestconfService { return identifier + "/" + ControllerContext.MOUNT; } - private CompositeNode normalizeNode(final CompositeNode node, final DataSchemaNode schema, - final MountInstance mountPoint) { + private CompositeNode normalizeNode(final Node node, final DataSchemaNode schema, final DOMMountPoint mountPoint) { if (schema == null) { QName nodeType = node == null ? null : node.getNodeType(); String localName = nodeType == null ? null : nodeType.getLocalName(); @@ -1037,24 +1129,32 @@ public class RestconfImpl implements RestconfService { ErrorType.PROTOCOL, ErrorTag.INVALID_VALUE); } - if ((node instanceof CompositeNodeWrapper)) { - boolean isChangeAllowed = ((CompositeNodeWrapper) node).isChangeAllowed(); + if ((node instanceof NodeWrapper)) { + NodeWrapper nodeWrap = (NodeWrapper) node; + boolean isChangeAllowed = ((NodeWrapper) node).isChangeAllowed(); if (isChangeAllowed) { + nodeWrap = topLevelElementAsCompositeNodeWrapper((NodeWrapper) node, schema); try { - this.normalizeNode(((CompositeNodeWrapper) node), schema, null, mountPoint); + this.normalizeNode(nodeWrap, schema, null, mountPoint); } catch (IllegalArgumentException e) { throw new RestconfDocumentedException(e.getMessage(), ErrorType.PROTOCOL, ErrorTag.INVALID_VALUE); } + if (nodeWrap instanceof CompositeNodeWrapper) { + return ((CompositeNodeWrapper) nodeWrap).unwrap(); + } } + } - return ((CompositeNodeWrapper) node).unwrap(); + if (node instanceof CompositeNode) { + return (CompositeNode) node; } - return node; + throw new RestconfDocumentedException("Top level element is not interpreted as composite node.", + ErrorType.APPLICATION, ErrorTag.INVALID_VALUE); } private void normalizeNode(final NodeWrapper nodeBuilder, final DataSchemaNode schema, - final QName previousAugment, final MountInstance mountPoint) { + final QName previousAugment, final DOMMountPoint mountPoint) { if (schema == null) { throw new RestconfDocumentedException("Data has bad format.\n\"" + nodeBuilder.getLocalName() + "\" does not exist in yang schema.", ErrorType.PROTOCOL, ErrorTag.INVALID_VALUE); @@ -1111,7 +1211,7 @@ public class RestconfImpl implements RestconfService { } private void normalizeSimpleNode(final SimpleNodeWrapper simpleNode, final DataSchemaNode schema, - final MountInstance mountPoint) { + final DOMMountPoint mountPoint) { final Object value = simpleNode.getValue(); Object inputValue = value; TypeDefinition typeDefinition = this.typeDefinition(schema); @@ -1133,11 +1233,11 @@ public class RestconfImpl implements RestconfService { } private void normalizeCompositeNode(final CompositeNodeWrapper compositeNodeBuilder, - final DataNodeContainer schema, final MountInstance mountPoint, final QName currentAugment) { + final DataNodeContainer schema, final DOMMountPoint mountPoint, final QName currentAugment) { final List> children = compositeNodeBuilder.getValues(); checkNodeMultiplicityAccordingToSchema(schema, children); for (final NodeWrapper child : children) { - final List potentialSchemaNodes = this.controllerContext.findInstanceDataChildrenByName( + final List potentialSchemaNodes = ControllerContext.findInstanceDataChildrenByName( schema, child.getLocalName()); if (potentialSchemaNodes.size() > 1 && child.getNamespace() == null) { @@ -1214,7 +1314,7 @@ public class RestconfImpl implements RestconfService { } private QName normalizeNodeName(final NodeWrapper nodeBuilder, final DataSchemaNode schema, - final QName previousAugment, final MountInstance mountPoint) { + final QName previousAugment, final DOMMountPoint mountPoint) { QName validQName = schema.getQName(); QName currentAugment = previousAugment; if (schema.isAugmenting()) { @@ -1232,15 +1332,16 @@ public class RestconfImpl implements RestconfService { } if (nodeBuilder.getNamespace() == null || Objects.equal(nodeBuilder.getNamespace(), validQName.getNamespace()) - || Objects.equal(nodeBuilder.getNamespace().toString(), moduleName) /* - * || Note : this check is wrong - - * can never be true as it compares - * a URI with a String not sure what - * the intention is so commented out - * ... Objects . equal ( nodeBuilder - * . getNamespace ( ) , - * MOUNT_POINT_MODULE_NAME ) - */) { + || Objects.equal(nodeBuilder.getNamespace().toString(), moduleName)) { + /* + * || Note : this check is wrong - + * can never be true as it compares + * a URI with a String not sure what + * the intention is so commented out + * ... Objects . equal ( nodeBuilder + * . getNamespace ( ) , + * MOUNT_POINT_MODULE_NAME ) + */ nodeBuilder.setQname(validQName); } @@ -1248,9 +1349,9 @@ public class RestconfImpl implements RestconfService { return currentAugment; } - private URI namespace(final CompositeNode data) { - if (data instanceof CompositeNodeWrapper) { - return ((CompositeNodeWrapper) data).getNamespace(); + private URI namespace(final Node data) { + if (data instanceof NodeWrapper) { + return ((NodeWrapper) data).getNamespace(); } else if (data != null) { return data.getNodeType().getNamespace(); } else { @@ -1258,9 +1359,9 @@ public class RestconfImpl implements RestconfService { } } - private String localName(final CompositeNode data) { - if (data instanceof CompositeNodeWrapper) { - return ((CompositeNodeWrapper) data).getLocalName(); + private String localName(final Node data) { + if (data instanceof NodeWrapper) { + return ((NodeWrapper) data).getLocalName(); } else if (data != null) { return data.getNodeType().getLocalName(); } else { @@ -1268,9 +1369,9 @@ public class RestconfImpl implements RestconfService { } } - private String getName(final CompositeNode data) { - if (data instanceof CompositeNodeWrapper) { - return ((CompositeNodeWrapper) data).getLocalName(); + private String getName(final Node data) { + if (data instanceof NodeWrapper) { + return ((NodeWrapper) data).getLocalName(); } else if (data != null) { return data.getNodeType().getLocalName(); } else { @@ -1307,4 +1408,89 @@ public class RestconfImpl implements RestconfService { throw new IllegalArgumentException("Unhandled parameter types: " + Arrays. asList(node).toString()); } } + + private CompositeNode datastoreNormalizedNodeToCompositeNode(final NormalizedNode dataNode, final DataSchemaNode schema) { + Node nodes = null; + if (dataNode == null) { + throw new RestconfDocumentedException(new RestconfError(ErrorType.APPLICATION, ErrorTag.DATA_MISSING, + "No data was found.")); + } + nodes = DataNormalizer.toLegacy(dataNode); + if (nodes != null) { + if (nodes instanceof CompositeNode) { + return (CompositeNode) nodes; + } else { + LOG.error("The node " + dataNode.getNodeType() + " couldn't be transformed to compositenode."); + } + } else { + LOG.error("Top level node isn't of type Container or List schema node but " + + schema.getClass().getSimpleName()); + } + + throw new RestconfDocumentedException(new RestconfError(ErrorType.APPLICATION, ErrorTag.INVALID_VALUE, + "It wasn't possible to correctly interpret data.")); + } + + private NormalizedNode compositeNodeToDatastoreNormalizedNode(final CompositeNode compNode, final DataSchemaNode schema) { + List> lst = new ArrayList>(); + lst.add(compNode); + if (schema instanceof ContainerSchemaNode) { + return CnSnToNormalizedNodeParserFactory.getInstance().getContainerNodeParser() + .parse(lst, (ContainerSchemaNode) schema); + } else if (schema instanceof ListSchemaNode) { + return CnSnToNormalizedNodeParserFactory.getInstance().getMapEntryNodeParser() + .parse(lst, (ListSchemaNode) schema); + } + + LOG.error("Top level isn't of type container, list, leaf schema node but " + schema.getClass().getSimpleName()); + + throw new RestconfDocumentedException(new RestconfError(ErrorType.APPLICATION, ErrorTag.INVALID_VALUE, + "It wasn't possible to translate specified data to datastore readable form.")); + } + + private InstanceIdWithSchemaNode normalizeInstanceIdentifierWithSchemaNode(final InstanceIdWithSchemaNode iiWithSchemaNode) { + return normalizeInstanceIdentifierWithSchemaNode(iiWithSchemaNode, false); + } + + private InstanceIdWithSchemaNode normalizeInstanceIdentifierWithSchemaNode( + final InstanceIdWithSchemaNode iiWithSchemaNode, final boolean unwrapLastListNode) { + return new InstanceIdWithSchemaNode(instanceIdentifierToReadableFormForNormalizeNode( + iiWithSchemaNode.getInstanceIdentifier(), unwrapLastListNode), iiWithSchemaNode.getSchemaNode(), + iiWithSchemaNode.getMountPoint()); + } + + private YangInstanceIdentifier instanceIdentifierToReadableFormForNormalizeNode(final YangInstanceIdentifier instIdentifier, + final boolean unwrapLastListNode) { + Preconditions.checkNotNull(instIdentifier, "Instance identifier can't be null"); + final List result = new ArrayList(); + final Iterator iter = instIdentifier.getPathArguments().iterator(); + while (iter.hasNext()) { + final PathArgument pathArgument = iter.next(); + if (pathArgument instanceof NodeIdentifierWithPredicates && (iter.hasNext() || unwrapLastListNode)) { + result.add(new YangInstanceIdentifier.NodeIdentifier(pathArgument.getNodeType())); + } + result.add(pathArgument); + } + return YangInstanceIdentifier.create(result); + } + + private CompositeNodeWrapper topLevelElementAsCompositeNodeWrapper(final NodeWrapper node, + final DataSchemaNode schemaNode) { + if (node instanceof CompositeNodeWrapper) { + return (CompositeNodeWrapper) node; + } else if (node instanceof SimpleNodeWrapper && isDataContainerNode(schemaNode)) { + final SimpleNodeWrapper simpleNodeWrapper = (SimpleNodeWrapper) node; + return new CompositeNodeWrapper(namespace(simpleNodeWrapper), localName(simpleNodeWrapper)); + } + + throw new RestconfDocumentedException(new RestconfError(ErrorType.APPLICATION, ErrorTag.INVALID_VALUE, + "Top level element has to be composite node or has to represent data container node.")); + } + + private boolean isDataContainerNode(final DataSchemaNode schemaNode) { + if (schemaNode instanceof ContainerSchemaNode || schemaNode instanceof ListSchemaNode) { + return true; + } + return false; + } } diff --git a/opendaylight/md-sal/sal-rest-connector/src/main/java/org/opendaylight/controller/sal/restconf/impl/StructuredData.java b/opendaylight/md-sal/sal-rest-connector/src/main/java/org/opendaylight/controller/sal/restconf/impl/StructuredData.java index c745a8009d..2935434967 100644 --- a/opendaylight/md-sal/sal-rest-connector/src/main/java/org/opendaylight/controller/sal/restconf/impl/StructuredData.java +++ b/opendaylight/md-sal/sal-rest-connector/src/main/java/org/opendaylight/controller/sal/restconf/impl/StructuredData.java @@ -7,7 +7,7 @@ */ package org.opendaylight.controller.sal.restconf.impl; -import org.opendaylight.controller.sal.core.api.mount.MountInstance; +import org.opendaylight.controller.md.sal.dom.api.DOMMountPoint; import org.opendaylight.yangtools.yang.data.api.CompositeNode; import org.opendaylight.yangtools.yang.model.api.DataSchemaNode; @@ -15,14 +15,14 @@ public class StructuredData { private final CompositeNode data; private final DataSchemaNode schema; - private final MountInstance mountPoint; + private final DOMMountPoint mountPoint; private final boolean prettyPrintMode; - public StructuredData(final CompositeNode data, final DataSchemaNode schema, final MountInstance mountPoint) { + public StructuredData(final CompositeNode data, final DataSchemaNode schema, final DOMMountPoint mountPoint) { this(data, schema, mountPoint, false); } - public StructuredData(final CompositeNode data, final DataSchemaNode schema, final MountInstance mountPoint, + public StructuredData(final CompositeNode data, final DataSchemaNode schema, final DOMMountPoint mountPoint, final boolean preattyPrintMode) { this.data = data; this.schema = schema; @@ -38,7 +38,7 @@ public class StructuredData { return schema; } - public MountInstance getMountPoint() { + public DOMMountPoint getMountPoint() { return mountPoint; } diff --git a/opendaylight/md-sal/sal-rest-connector/src/main/java/org/opendaylight/controller/sal/restconf/rpc/impl/MountPointRpcExecutor.java b/opendaylight/md-sal/sal-rest-connector/src/main/java/org/opendaylight/controller/sal/restconf/rpc/impl/MountPointRpcExecutor.java index 36502656c2..efb3e0a1d3 100644 --- a/opendaylight/md-sal/sal-rest-connector/src/main/java/org/opendaylight/controller/sal/restconf/rpc/impl/MountPointRpcExecutor.java +++ b/opendaylight/md-sal/sal-rest-connector/src/main/java/org/opendaylight/controller/sal/restconf/rpc/impl/MountPointRpcExecutor.java @@ -7,9 +7,12 @@ */ package org.opendaylight.controller.sal.restconf.rpc.impl; +import com.google.common.base.Optional; import com.google.common.base.Preconditions; import java.util.concurrent.Future; -import org.opendaylight.controller.sal.core.api.mount.MountInstance; +import org.opendaylight.controller.md.sal.dom.api.DOMMountPoint; +import org.opendaylight.controller.sal.core.api.RpcProvisionRegistry; +import org.opendaylight.controller.sal.restconf.impl.RestconfDocumentedException; import org.opendaylight.yangtools.yang.common.RpcResult; import org.opendaylight.yangtools.yang.data.api.CompositeNode; import org.opendaylight.yangtools.yang.model.api.RpcDefinition; @@ -21,9 +24,9 @@ import org.opendaylight.yangtools.yang.model.api.RpcDefinition; * */ public class MountPointRpcExecutor extends AbstractRpcExecutor { - private final MountInstance mountPoint; + private final DOMMountPoint mountPoint; - public MountPointRpcExecutor(RpcDefinition rpcDef, MountInstance mountPoint) { + public MountPointRpcExecutor(RpcDefinition rpcDef, DOMMountPoint mountPoint) { super(rpcDef); this.mountPoint = mountPoint; Preconditions.checkNotNull(mountPoint, "MountInstance can not be null."); @@ -31,6 +34,10 @@ public class MountPointRpcExecutor extends AbstractRpcExecutor { @Override protected Future> invokeRpcUnchecked(CompositeNode rpcRequest) { - return mountPoint.rpc(getRpcDefinition().getQName(), rpcRequest); + Optional service = mountPoint.getService(RpcProvisionRegistry.class); + if (service.isPresent()) { + return service.get().invokeRpc(getRpcDefinition().getQName(), rpcRequest); + } + throw new RestconfDocumentedException("Rpc service is missing."); } } \ No newline at end of file diff --git a/opendaylight/md-sal/sal-rest-connector/src/main/java/org/opendaylight/controller/sal/streams/listeners/ListenerAdapter.java b/opendaylight/md-sal/sal-rest-connector/src/main/java/org/opendaylight/controller/sal/streams/listeners/ListenerAdapter.java index 2b7b0246e3..a6e02632ce 100644 --- a/opendaylight/md-sal/sal-rest-connector/src/main/java/org/opendaylight/controller/sal/streams/listeners/ListenerAdapter.java +++ b/opendaylight/md-sal/sal-rest-connector/src/main/java/org/opendaylight/controller/sal/streams/listeners/ListenerAdapter.java @@ -38,8 +38,8 @@ import javax.xml.transform.TransformerException; import javax.xml.transform.TransformerFactory; import javax.xml.transform.dom.DOMSource; import javax.xml.transform.stream.StreamResult; -import org.opendaylight.controller.md.sal.common.api.data.DataChangeEvent; -import org.opendaylight.controller.sal.core.api.data.DataChangeListener; +import org.opendaylight.controller.md.sal.common.api.data.AsyncDataChangeEvent; +import org.opendaylight.controller.md.sal.dom.api.DOMDataChangeListener; import org.opendaylight.controller.sal.rest.impl.XmlMapper; import org.opendaylight.controller.sal.restconf.impl.ControllerContext; import org.opendaylight.yangtools.concepts.ListenerRegistration; @@ -49,6 +49,7 @@ import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier; import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier.NodeIdentifierWithPredicates; import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier.NodeWithValue; import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier.PathArgument; +import org.opendaylight.yangtools.yang.data.api.schema.NormalizedNode; import org.opendaylight.yangtools.yang.model.api.DataNodeContainer; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -59,7 +60,7 @@ import org.w3c.dom.Node; /** * {@link ListenerAdapter} is responsible to track events, which occurred by changing data in data source. */ -public class ListenerAdapter implements DataChangeListener { +public class ListenerAdapter implements DOMDataChangeListener { private static final Logger LOG = LoggerFactory.getLogger(ListenerAdapter.class); private static final DocumentBuilderFactory DBF = DocumentBuilderFactory.newInstance(); @@ -70,7 +71,7 @@ public class ListenerAdapter implements DataChangeListener { private final SimpleDateFormat rfc3339 = new SimpleDateFormat("yyyy-MM-dd'T'hh:mm:ssZ"); private final YangInstanceIdentifier path; - private ListenerRegistration registration; + private ListenerRegistration registration; private final String streamName; private Set subscribers = new ConcurrentSet<>(); private final EventBus eventBus; @@ -95,10 +96,11 @@ public class ListenerAdapter implements DataChangeListener { } @Override - public void onDataChanged(final DataChangeEvent change) { - if (!change.getCreatedConfigurationData().isEmpty() || !change.getCreatedOperationalData().isEmpty() - || !change.getUpdatedConfigurationData().isEmpty() || !change.getUpdatedOperationalData().isEmpty() - || !change.getRemovedConfigurationData().isEmpty() || !change.getRemovedOperationalData().isEmpty()) { + public void onDataChanged(AsyncDataChangeEvent> change) { + // TODO Auto-generated method stub + + if (!change.getCreatedData().isEmpty() || !change.getUpdatedData().isEmpty() + || !change.getRemovedPaths().isEmpty()) { String xml = prepareXmlFrom(change); Event event = new Event(EventType.NOTIFY); event.setData(xml); @@ -216,7 +218,7 @@ public class ListenerAdapter implements DataChangeListener { * DataChangeEvent * @return Data in printable form. */ - private String prepareXmlFrom(final DataChangeEvent change) { + private String prepareXmlFrom(AsyncDataChangeEvent> change) { Document doc = createDocument(); Element notificationElement = doc.createElementNS("urn:ietf:params:xml:ns:netconf:notification:1.0", "notification"); @@ -262,7 +264,6 @@ public class ListenerAdapter implements DataChangeListener { /** * Creates {@link Document} document. - * * @return {@link Document} document. */ private Document createDocument() { @@ -287,23 +288,15 @@ public class ListenerAdapter implements DataChangeListener { */ private void addValuesToDataChangedNotificationEventElement(final Document doc, final Element dataChangedNotificationEventElement, - final DataChangeEvent change) { - addValuesFromDataToElement(doc, change.getCreatedConfigurationData(), dataChangedNotificationEventElement, - Store.CONFIG, Operation.CREATED); - addValuesFromDataToElement(doc, change.getCreatedOperationalData(), dataChangedNotificationEventElement, - Store.OPERATION, Operation.CREATED); - if (change.getCreatedConfigurationData().isEmpty()) { - addValuesFromDataToElement(doc, change.getUpdatedConfigurationData(), dataChangedNotificationEventElement, - Store.CONFIG, Operation.UPDATED); - } - if (change.getCreatedOperationalData().isEmpty()) { - addValuesFromDataToElement(doc, change.getUpdatedOperationalData(), dataChangedNotificationEventElement, - Store.OPERATION, Operation.UPDATED); + AsyncDataChangeEvent> change) { + addValuesFromDataToElement(doc, change.getCreatedData().keySet(), dataChangedNotificationEventElement, + Operation.CREATED); + if (change.getCreatedData().isEmpty()) { + addValuesFromDataToElement(doc, change.getUpdatedData().keySet(), dataChangedNotificationEventElement, + Operation.UPDATED); } - addValuesFromDataToElement(doc, change.getRemovedConfigurationData(), dataChangedNotificationEventElement, - Store.CONFIG, Operation.DELETED); - addValuesFromDataToElement(doc, change.getRemovedOperationalData(), dataChangedNotificationEventElement, - Store.OPERATION, Operation.DELETED); + addValuesFromDataToElement(doc, change.getRemovedPaths(), dataChangedNotificationEventElement, + Operation.DELETED); } /** @@ -320,13 +313,13 @@ public class ListenerAdapter implements DataChangeListener { * @param operation * {@link Operation} */ - private void addValuesFromDataToElement(final Document doc, final Set data, - final Element element, final Store store, final Operation operation) { + private void addValuesFromDataToElement(Document doc, Set data, Element element, + Operation operation) { if (data == null || data.isEmpty()) { return; } for (YangInstanceIdentifier path : data) { - Node node = createDataChangeEventElement(doc, path, null, store, operation); + Node node = createDataChangeEventElement(doc, path, null, operation); element.appendChild(node); } } @@ -345,13 +338,13 @@ public class ListenerAdapter implements DataChangeListener { * @param operation * {@link Operation} */ - private void addValuesFromDataToElement(final Document doc, final Map data, - final Element element, final Store store, final Operation operation) { + private void addValuesFromDataToElement(Document doc, Map data, Element element, + Operation operation) { if (data == null || data.isEmpty()) { return; } for (Entry entry : data.entrySet()) { - Node node = createDataChangeEventElement(doc, entry.getKey(), entry.getValue(), store, operation); + Node node = createDataChangeEventElement(doc, entry.getKey(), entry.getValue(), operation); element.appendChild(node); } } @@ -371,17 +364,17 @@ public class ListenerAdapter implements DataChangeListener { * {@link Operation} * @return {@link Node} node represented by changed event element. */ - private Node createDataChangeEventElement(final Document doc, final YangInstanceIdentifier path, - final CompositeNode data, final Store store, final Operation operation) { + private Node createDataChangeEventElement(Document doc, YangInstanceIdentifier path, CompositeNode data, + Operation operation) { Element dataChangeEventElement = doc.createElement("data-change-event"); Element pathElement = doc.createElement("path"); addPathAsValueToElement(path, pathElement); dataChangeEventElement.appendChild(pathElement); - Element storeElement = doc.createElement("store"); - storeElement.setTextContent(store.value); - dataChangeEventElement.appendChild(storeElement); + // Element storeElement = doc.createElement("store"); + // storeElement.setTextContent(store.value); + // dataChangeEventElement.appendChild(storeElement); Element operationElement = doc.createElement("operation"); operationElement.setTextContent(operation.value); @@ -530,7 +523,7 @@ public class ListenerAdapter implements DataChangeListener { * @param registration * ListenerRegistration */ - public void setRegistration(final ListenerRegistration registration) { + public void setRegistration(final ListenerRegistration registration) { this.registration = registration; } diff --git a/opendaylight/md-sal/sal-rest-connector/src/main/java/org/opendaylight/controller/sal/streams/listeners/Notificator.java b/opendaylight/md-sal/sal-rest-connector/src/main/java/org/opendaylight/controller/sal/streams/listeners/Notificator.java index cf1bcd6a30..17565a6b8c 100644 --- a/opendaylight/md-sal/sal-rest-connector/src/main/java/org/opendaylight/controller/sal/streams/listeners/Notificator.java +++ b/opendaylight/md-sal/sal-rest-connector/src/main/java/org/opendaylight/controller/sal/streams/listeners/Notificator.java @@ -15,12 +15,12 @@ import java.util.concurrent.locks.ReentrantLock; import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier; /** - * {@link Notificator} is responsible to create, remove and find {@link ListenerAdapter} listener. + * {@link Notificator} is responsible to create, remove and find + * {@link ListenerAdapter} listener. */ public class Notificator { private static Map listenersByStreamName = new ConcurrentHashMap<>(); - private static Map listenersByInstanceIdentifier = new ConcurrentHashMap<>(); private static final Lock lock = new ReentrantLock(); private Notificator() { @@ -44,26 +44,14 @@ public class Notificator { return listenersByStreamName.get(streamName); } - /** - * Gets {@link ListenerAdapter} listener specified by {@link YangInstanceIdentifier} path. - * - * @param path - * Path to data in data repository. - * @return ListenerAdapter - */ - public static ListenerAdapter getListenerFor(YangInstanceIdentifier path) { - return listenersByInstanceIdentifier.get(path); - } - /** * Checks if the listener specified by {@link YangInstanceIdentifier} path exist. * - * @param path - * Path to data in data repository. + * @param streamName * @return True if the listener exist, false otherwise. */ - public static boolean existListenerFor(YangInstanceIdentifier path) { - return listenersByInstanceIdentifier.containsKey(path); + public static boolean existListenerFor(String streamName) { + return listenersByStreamName.containsKey(streamName); } /** @@ -79,7 +67,6 @@ public class Notificator { ListenerAdapter listener = new ListenerAdapter(path, streamName); try { lock.lock(); - listenersByInstanceIdentifier.put(path, listener); listenersByStreamName.put(streamName, listener); } finally { lock.unlock(); @@ -89,16 +76,6 @@ public class Notificator { /** * Looks for listener determined by {@link YangInstanceIdentifier} path and removes it. - * - * @param path - * InstanceIdentifier - */ - public static void removeListener(YangInstanceIdentifier path) { - ListenerAdapter listener = listenersByInstanceIdentifier.get(path); - deleteListener(listener); - } - - /** * Creates String representation of stream name from URI. Removes slash from URI in start and end position. * * @param uri @@ -114,7 +91,7 @@ public class Notificator { result = result.substring(1); } if (result.endsWith("/")) { - result = result.substring(0, result.length()); + result = result.substring(0, result.length()-1); } return result; } @@ -123,7 +100,7 @@ public class Notificator { * Removes all listeners. */ public static void removeAllListeners() { - for (ListenerAdapter listener : listenersByInstanceIdentifier.values()) { + for (ListenerAdapter listener : listenersByStreamName.values()) { try { listener.close(); } catch (Exception e) { @@ -132,7 +109,6 @@ public class Notificator { try { lock.lock(); listenersByStreamName = new ConcurrentHashMap<>(); - listenersByInstanceIdentifier = new ConcurrentHashMap<>(); } finally { lock.unlock(); } @@ -164,7 +140,6 @@ public class Notificator { } try { lock.lock(); - listenersByInstanceIdentifier.remove(listener.getPath()); listenersByStreamName.remove(listener.getStreamName()); } finally { lock.unlock(); diff --git a/opendaylight/md-sal/sal-rest-connector/src/main/yang/sal-remote-augment.yang b/opendaylight/md-sal/sal-rest-connector/src/main/yang/sal-remote-augment.yang new file mode 100644 index 0000000000..83934568cc --- /dev/null +++ b/opendaylight/md-sal/sal-rest-connector/src/main/yang/sal-remote-augment.yang @@ -0,0 +1,31 @@ +module sal-remote-augment { + + yang-version 1; + namespace "urn:sal:restconf:event:subscription"; + prefix "salrmt-aug-ev-subscr"; + + import sal-remote {prefix salrmt; revision-date "2014-01-14";} + + description + "Added input parameters to rpc create-data-change-event-subscription"; + + revision "2014-7-8" { + } + + augment "/salrmt:create-data-change-event-subscription/salrmt:input" { + leaf datastore { + type enumeration { + enum OPERATIONAL; + enum CONFIGURATION; + } + } + leaf scope { + type enumeration { + enum BASE; + enum ONE; + enum SUBTREE; + } + } + } + +} \ No newline at end of file diff --git a/opendaylight/md-sal/sal-rest-connector/src/test/java/org/opendaylight/controller/sal/restconf/impl/cnsn/to/json/test/CnSnJsonBasicYangTypesTest.java b/opendaylight/md-sal/sal-rest-connector/src/test/java/org/opendaylight/controller/sal/restconf/impl/cnsn/to/json/test/CnSnJsonBasicYangTypesTest.java index 0f059f5024..d9dc26d888 100644 --- a/opendaylight/md-sal/sal-rest-connector/src/test/java/org/opendaylight/controller/sal/restconf/impl/cnsn/to/json/test/CnSnJsonBasicYangTypesTest.java +++ b/opendaylight/md-sal/sal-rest-connector/src/test/java/org/opendaylight/controller/sal/restconf/impl/cnsn/to/json/test/CnSnJsonBasicYangTypesTest.java @@ -35,6 +35,7 @@ import org.opendaylight.yangtools.yang.data.api.CompositeNode; import org.opendaylight.yangtools.yang.data.api.ModifyAction; import org.opendaylight.yangtools.yang.data.api.MutableCompositeNode; import org.opendaylight.yangtools.yang.data.api.MutableSimpleNode; +import org.opendaylight.yangtools.yang.data.api.Node; import org.opendaylight.yangtools.yang.data.impl.NodeFactory; public class CnSnJsonBasicYangTypesTest extends YangAndXmlAndDataSchemaLoader { @@ -67,12 +68,12 @@ public class CnSnJsonBasicYangTypesTest extends YangAndXmlAndDataSchemaLoader { */ @Test public void xmlAndYangTypesWithJsonReaderTest() { - CompositeNode compositeNode = TestUtils.readInputToCnSn("/cnsn-to-json/simple-yang-types/xml/data.xml", + Node node = TestUtils.readInputToCnSn("/cnsn-to-json/simple-yang-types/xml/data.xml", XmlToCompositeNodeProvider.INSTANCE); - TestUtils.normalizeCompositeNode(compositeNode, modules, searchedModuleName + ":" + searchedDataSchemaName); + TestUtils.normalizeCompositeNode(node, modules, searchedModuleName + ":" + searchedDataSchemaName); String jsonOutput = null; try { - jsonOutput = TestUtils.writeCompNodeWithSchemaContextToOutput(compositeNode, modules, dataSchemaNode, + jsonOutput = TestUtils.writeCompNodeWithSchemaContextToOutput(node, modules, dataSchemaNode, StructuredDataToJsonProvider.INSTANCE); } catch (WebApplicationException | IOException e) { } diff --git a/opendaylight/md-sal/sal-rest-connector/src/test/java/org/opendaylight/controller/sal/restconf/impl/cnsn/to/json/test/CnSnJsonChoiceCaseTest.java b/opendaylight/md-sal/sal-rest-connector/src/test/java/org/opendaylight/controller/sal/restconf/impl/cnsn/to/json/test/CnSnJsonChoiceCaseTest.java index 0d0ce5cdd3..632d2490ee 100644 --- a/opendaylight/md-sal/sal-rest-connector/src/test/java/org/opendaylight/controller/sal/restconf/impl/cnsn/to/json/test/CnSnJsonChoiceCaseTest.java +++ b/opendaylight/md-sal/sal-rest-connector/src/test/java/org/opendaylight/controller/sal/restconf/impl/cnsn/to/json/test/CnSnJsonChoiceCaseTest.java @@ -17,7 +17,8 @@ import org.opendaylight.controller.sal.rest.impl.StructuredDataToJsonProvider; import org.opendaylight.controller.sal.rest.impl.XmlToCompositeNodeProvider; import org.opendaylight.controller.sal.restconf.impl.test.TestUtils; import org.opendaylight.controller.sal.restconf.impl.test.YangAndXmlAndDataSchemaLoader; -import org.opendaylight.yangtools.yang.data.api.CompositeNode; +import org.opendaylight.yangtools.yang.data.api.Node; +import org.opendaylight.yangtools.yang.data.impl.schema.builder.impl.valid.DataValidationException; public class CnSnJsonChoiceCaseTest extends YangAndXmlAndDataSchemaLoader { @@ -31,7 +32,7 @@ public class CnSnJsonChoiceCaseTest extends YangAndXmlAndDataSchemaLoader { * return error because nodes has to be from one case below concrete choice. * */ - @Test + @Test(expected=DataValidationException.class) public void nodeSchemasOnVariousChoiceCasePathTest() { testWrapper("/cnsn-to-json/choice/xml/data_various_path_err.xml", "choice-case-test:cont"); } @@ -42,7 +43,7 @@ public class CnSnJsonChoiceCaseTest extends YangAndXmlAndDataSchemaLoader { * choice. * */ - @Test + @Test(expected=DataValidationException.class) public void nodeSchemasOnVariousChoiceCasePathAndMultipleChoicesTest() { testWrapper("/cnsn-to-json/choice/xml/data_more_choices_same_level_various_paths_err.xml", "choice-case-test:cont"); @@ -116,10 +117,10 @@ public class CnSnJsonChoiceCaseTest extends YangAndXmlAndDataSchemaLoader { } private void testWrapper(String xmlPath, String pathToSchemaNode) { - CompositeNode compNode = TestUtils.readInputToCnSn(xmlPath, XmlToCompositeNodeProvider.INSTANCE); - TestUtils.normalizeCompositeNode(compNode, modules, pathToSchemaNode); + Node node = TestUtils.readInputToCnSn(xmlPath, XmlToCompositeNodeProvider.INSTANCE); + TestUtils.normalizeCompositeNode(node, modules, pathToSchemaNode); try { - TestUtils.writeCompNodeWithSchemaContextToOutput(compNode, modules, dataSchemaNode, + TestUtils.writeCompNodeWithSchemaContextToOutput(node, modules, dataSchemaNode, StructuredDataToJsonProvider.INSTANCE); } catch (WebApplicationException | IOException e) { // shouldn't end here diff --git a/opendaylight/md-sal/sal-rest-connector/src/test/java/org/opendaylight/controller/sal/restconf/impl/cnsn/to/json/test/CnSnToJsonBasicDataTypesTest.java b/opendaylight/md-sal/sal-rest-connector/src/test/java/org/opendaylight/controller/sal/restconf/impl/cnsn/to/json/test/CnSnToJsonBasicDataTypesTest.java index 4b8b71440a..11051cc733 100644 --- a/opendaylight/md-sal/sal-rest-connector/src/test/java/org/opendaylight/controller/sal/restconf/impl/cnsn/to/json/test/CnSnToJsonBasicDataTypesTest.java +++ b/opendaylight/md-sal/sal-rest-connector/src/test/java/org/opendaylight/controller/sal/restconf/impl/cnsn/to/json/test/CnSnToJsonBasicDataTypesTest.java @@ -27,7 +27,7 @@ import org.opendaylight.controller.sal.restconf.impl.RestconfDocumentedException import org.opendaylight.controller.sal.restconf.impl.RestconfError.ErrorTag; import org.opendaylight.controller.sal.restconf.impl.test.TestUtils; import org.opendaylight.controller.sal.restconf.impl.test.YangAndXmlAndDataSchemaLoader; -import org.opendaylight.yangtools.yang.data.api.CompositeNode; +import org.opendaylight.yangtools.yang.data.api.Node; public class CnSnToJsonBasicDataTypesTest extends YangAndXmlAndDataSchemaLoader { @@ -189,12 +189,12 @@ public class CnSnToJsonBasicDataTypesTest extends YangAndXmlAndDataSchemaLoader @Test public void simpleYangDataTest() throws Exception { - CompositeNode compositeNode = TestUtils.readInputToCnSn("/cnsn-to-json/simple-data-types/xml/data.xml", + Node node = TestUtils.readInputToCnSn("/cnsn-to-json/simple-data-types/xml/data.xml", XmlToCompositeNodeProvider.INSTANCE); - TestUtils.normalizeCompositeNode(compositeNode, modules, "simple-data-types:cont"); + TestUtils.normalizeCompositeNode(node, modules, "simple-data-types:cont"); - String jsonOutput = TestUtils.writeCompNodeWithSchemaContextToOutput(compositeNode, modules, dataSchemaNode, + String jsonOutput = TestUtils.writeCompNodeWithSchemaContextToOutput(node, modules, dataSchemaNode, StructuredDataToJsonProvider.INSTANCE); assertNotNull(jsonOutput); @@ -303,10 +303,10 @@ public class CnSnToJsonBasicDataTypesTest extends YangAndXmlAndDataSchemaLoader public void testBadData() throws Exception { try { - CompositeNode compositeNode = TestUtils.readInputToCnSn("/cnsn-to-json/simple-data-types/xml/bad-data.xml", + Node node = TestUtils.readInputToCnSn("/cnsn-to-json/simple-data-types/xml/bad-data.xml", XmlToCompositeNodeProvider.INSTANCE); - TestUtils.normalizeCompositeNode(compositeNode, modules, "simple-data-types:cont"); + TestUtils.normalizeCompositeNode(node, modules, "simple-data-types:cont"); fail("Expected RestconfDocumentedException"); } catch (RestconfDocumentedException e) { assertEquals("getErrorTag", ErrorTag.INVALID_VALUE, e.getErrors().get(0).getErrorTag()); diff --git a/opendaylight/md-sal/sal-rest-connector/src/test/java/org/opendaylight/controller/sal/restconf/impl/cnsn/to/json/test/CnSnToJsonIncorrectTopLevelTest.java b/opendaylight/md-sal/sal-rest-connector/src/test/java/org/opendaylight/controller/sal/restconf/impl/cnsn/to/json/test/CnSnToJsonIncorrectTopLevelTest.java index 50c834b1ff..3bd600dbf1 100644 --- a/opendaylight/md-sal/sal-rest-connector/src/test/java/org/opendaylight/controller/sal/restconf/impl/cnsn/to/json/test/CnSnToJsonIncorrectTopLevelTest.java +++ b/opendaylight/md-sal/sal-rest-connector/src/test/java/org/opendaylight/controller/sal/restconf/impl/cnsn/to/json/test/CnSnToJsonIncorrectTopLevelTest.java @@ -21,7 +21,7 @@ import org.opendaylight.controller.sal.rest.impl.XmlToCompositeNodeProvider; import org.opendaylight.controller.sal.restconf.impl.test.TestUtils; import org.opendaylight.controller.sal.restconf.impl.test.YangAndXmlAndDataSchemaLoader; import org.opendaylight.yangtools.yang.common.QName; -import org.opendaylight.yangtools.yang.data.api.CompositeNode; +import org.opendaylight.yangtools.yang.data.api.Node; import org.opendaylight.yangtools.yang.model.api.ConstraintDefinition; import org.opendaylight.yangtools.yang.model.api.DataNodeContainer; import org.opendaylight.yangtools.yang.model.api.DataSchemaNode; @@ -145,16 +145,15 @@ public class CnSnToJsonIncorrectTopLevelTest extends YangAndXmlAndDataSchemaLoad @Test public void incorrectTopLevelElementTest() { - CompositeNode compositeNode = TestUtils.readInputToCnSn("/cnsn-to-json/simple-data-types/xml/data.xml", - XmlToCompositeNodeProvider.INSTANCE); + Node node = TestUtils.readInputToCnSn("/cnsn-to-json/simple-data-types/xml/data.xml", XmlToCompositeNodeProvider.INSTANCE); DataSchemaNode incorrectDataSchema = null; incorrectDataSchema = new IncorrectDataSchema(); - TestUtils.normalizeCompositeNode(compositeNode, modules, "simple-data-types:cont"); + TestUtils.normalizeCompositeNode(node, modules, "simple-data-types:cont"); boolean exceptionRaised = false; try { - TestUtils.writeCompNodeWithSchemaContextToOutput(compositeNode, modules, incorrectDataSchema, + TestUtils.writeCompNodeWithSchemaContextToOutput(node, modules, incorrectDataSchema, StructuredDataToJsonProvider.INSTANCE); } catch (UnsupportedDataTypeException e) { exceptionRaised = true; diff --git a/opendaylight/md-sal/sal-rest-connector/src/test/java/org/opendaylight/controller/sal/restconf/impl/cnsn/to/json/test/CnSnToJsonLeafrefType.java b/opendaylight/md-sal/sal-rest-connector/src/test/java/org/opendaylight/controller/sal/restconf/impl/cnsn/to/json/test/CnSnToJsonLeafrefType.java index 6e41dcb577..b5d3528e95 100644 --- a/opendaylight/md-sal/sal-rest-connector/src/test/java/org/opendaylight/controller/sal/restconf/impl/cnsn/to/json/test/CnSnToJsonLeafrefType.java +++ b/opendaylight/md-sal/sal-rest-connector/src/test/java/org/opendaylight/controller/sal/restconf/impl/cnsn/to/json/test/CnSnToJsonLeafrefType.java @@ -20,7 +20,7 @@ import org.opendaylight.controller.sal.rest.impl.StructuredDataToJsonProvider; import org.opendaylight.controller.sal.rest.impl.XmlToCompositeNodeProvider; import org.opendaylight.controller.sal.restconf.impl.test.TestUtils; import org.opendaylight.controller.sal.restconf.impl.test.YangAndXmlAndDataSchemaLoader; -import org.opendaylight.yangtools.yang.data.api.CompositeNode; +import org.opendaylight.yangtools.yang.data.api.Node; /** * @@ -95,9 +95,9 @@ public class CnSnToJsonLeafrefType extends YangAndXmlAndDataSchemaLoader { private String toJson(String xmlDataPath) { try { - CompositeNode compositeNode = TestUtils.readInputToCnSn(xmlDataPath, XmlToCompositeNodeProvider.INSTANCE); - TestUtils.normalizeCompositeNode(compositeNode, modules, searchedModuleName + ":" + searchedDataSchemaName); - return TestUtils.writeCompNodeWithSchemaContextToOutput(compositeNode, modules, dataSchemaNode, + Node node = TestUtils.readInputToCnSn(xmlDataPath, XmlToCompositeNodeProvider.INSTANCE); + TestUtils.normalizeCompositeNode(node, modules, searchedModuleName + ":" + searchedDataSchemaName); + return TestUtils.writeCompNodeWithSchemaContextToOutput(node, modules, dataSchemaNode, StructuredDataToJsonProvider.INSTANCE); } catch (WebApplicationException | IOException e) { } diff --git a/opendaylight/md-sal/sal-rest-connector/src/test/java/org/opendaylight/controller/sal/restconf/impl/cnsn/to/json/test/CnSnToJsonWithAugmentTest.java b/opendaylight/md-sal/sal-rest-connector/src/test/java/org/opendaylight/controller/sal/restconf/impl/cnsn/to/json/test/CnSnToJsonWithAugmentTest.java index eb6a5b9e00..72b9ed93d4 100644 --- a/opendaylight/md-sal/sal-rest-connector/src/test/java/org/opendaylight/controller/sal/restconf/impl/cnsn/to/json/test/CnSnToJsonWithAugmentTest.java +++ b/opendaylight/md-sal/sal-rest-connector/src/test/java/org/opendaylight/controller/sal/restconf/impl/cnsn/to/json/test/CnSnToJsonWithAugmentTest.java @@ -19,7 +19,7 @@ import org.opendaylight.controller.sal.rest.impl.StructuredDataToJsonProvider; import org.opendaylight.controller.sal.rest.impl.XmlToCompositeNodeProvider; import org.opendaylight.controller.sal.restconf.impl.test.TestUtils; import org.opendaylight.controller.sal.restconf.impl.test.YangAndXmlAndDataSchemaLoader; -import org.opendaylight.yangtools.yang.data.api.CompositeNode; +import org.opendaylight.yangtools.yang.data.api.Node; public class CnSnToJsonWithAugmentTest extends YangAndXmlAndDataSchemaLoader { @@ -33,13 +33,13 @@ public class CnSnToJsonWithAugmentTest extends YangAndXmlAndDataSchemaLoader { */ @Test public void augmentedElementsToJson() { - CompositeNode compositeNode = TestUtils.readInputToCnSn("/cnsn-to-json/augmentation/xml/data.xml", + Node node = TestUtils.readInputToCnSn("/cnsn-to-json/augmentation/xml/data.xml", XmlToCompositeNodeProvider.INSTANCE); - TestUtils.normalizeCompositeNode(compositeNode, modules, searchedModuleName + ":" + searchedDataSchemaName); + TestUtils.normalizeCompositeNode(node, modules, searchedModuleName + ":" + searchedDataSchemaName); String jsonOutput = null; try { - jsonOutput = TestUtils.writeCompNodeWithSchemaContextToOutput(compositeNode, modules, dataSchemaNode, + jsonOutput = TestUtils.writeCompNodeWithSchemaContextToOutput(node, modules, dataSchemaNode, StructuredDataToJsonProvider.INSTANCE); } catch (WebApplicationException | IOException e) { } diff --git a/opendaylight/md-sal/sal-rest-connector/src/test/java/org/opendaylight/controller/sal/restconf/impl/input/to/cnsn/test/RestPutListDataTest.java b/opendaylight/md-sal/sal-rest-connector/src/test/java/org/opendaylight/controller/sal/restconf/impl/input/to/cnsn/test/RestPutListDataTest.java index 4210944de7..3adfee7f5b 100644 --- a/opendaylight/md-sal/sal-rest-connector/src/test/java/org/opendaylight/controller/sal/restconf/impl/input/to/cnsn/test/RestPutListDataTest.java +++ b/opendaylight/md-sal/sal-rest-connector/src/test/java/org/opendaylight/controller/sal/restconf/impl/input/to/cnsn/test/RestPutListDataTest.java @@ -13,12 +13,12 @@ import static org.mockito.Matchers.any; import static org.mockito.Mockito.mock; import static org.mockito.Mockito.when; +import com.google.common.util.concurrent.CheckedFuture; import java.io.FileNotFoundException; import java.net.URI; import java.util.List; import org.junit.Before; import org.junit.Test; -import org.opendaylight.controller.md.sal.common.api.TransactionStatus; import org.opendaylight.controller.sal.restconf.impl.BrokerFacade; import org.opendaylight.controller.sal.restconf.impl.CompositeNodeWrapper; import org.opendaylight.controller.sal.restconf.impl.ControllerContext; @@ -28,13 +28,10 @@ import org.opendaylight.controller.sal.restconf.impl.RestconfError.ErrorTag; import org.opendaylight.controller.sal.restconf.impl.RestconfError.ErrorType; import org.opendaylight.controller.sal.restconf.impl.RestconfImpl; import org.opendaylight.controller.sal.restconf.impl.SimpleNodeWrapper; -import org.opendaylight.controller.sal.restconf.impl.test.DummyFuture; -import org.opendaylight.controller.sal.restconf.impl.test.DummyFuture.Builder; -import org.opendaylight.controller.sal.restconf.impl.test.DummyRpcResult; import org.opendaylight.controller.sal.restconf.impl.test.TestUtils; import org.opendaylight.yangtools.yang.common.QName; -import org.opendaylight.yangtools.yang.data.api.CompositeNode; import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier; +import org.opendaylight.yangtools.yang.data.api.schema.NormalizedNode; import org.opendaylight.yangtools.yang.data.impl.ImmutableCompositeNode; import org.opendaylight.yangtools.yang.data.impl.util.CompositeNodeBuilder; import org.opendaylight.yangtools.yang.model.api.SchemaContext; @@ -62,11 +59,8 @@ public class RestPutListDataTest { restconfImpl = RestconfImpl.getInstance(); restconfImpl.setBroker(brokerFacade); restconfImpl.setControllerContext(controllerContext); - Builder futureBuilder = new DummyFuture.Builder(); - futureBuilder.rpcResult(new DummyRpcResult.Builder().result(TransactionStatus.COMMITED) - .build()); - when(brokerFacade.commitConfigurationDataPut(any(YangInstanceIdentifier.class), any(CompositeNode.class))) - .thenReturn(futureBuilder.build()); + when(brokerFacade.commitConfigurationDataPut(any(YangInstanceIdentifier.class), any(NormalizedNode.class))) + .thenReturn(mock(CheckedFuture.class)); } /** diff --git a/opendaylight/md-sal/sal-rest-connector/src/test/java/org/opendaylight/controller/sal/restconf/impl/json/to/cnsn/test/JsonIdentityrefToCnSnTest.java b/opendaylight/md-sal/sal-rest-connector/src/test/java/org/opendaylight/controller/sal/restconf/impl/json/to/cnsn/test/JsonIdentityrefToCnSnTest.java index 23b040a9a3..cda635e847 100644 --- a/opendaylight/md-sal/sal-rest-connector/src/test/java/org/opendaylight/controller/sal/restconf/impl/json/to/cnsn/test/JsonIdentityrefToCnSnTest.java +++ b/opendaylight/md-sal/sal-rest-connector/src/test/java/org/opendaylight/controller/sal/restconf/impl/json/to/cnsn/test/JsonIdentityrefToCnSnTest.java @@ -31,15 +31,16 @@ public class JsonIdentityrefToCnSnTest extends YangAndXmlAndDataSchemaLoader { @Test public void jsonIdentityrefToCompositeNode() { - CompositeNode compositeNode = TestUtils.readInputToCnSn("/json-to-cnsn/identityref/json/data.json", false, + Node node = TestUtils.readInputToCnSn("/json-to-cnsn/identityref/json/data.json", false, JsonToCompositeNodeProvider.INSTANCE); - assertNotNull(compositeNode); + assertNotNull(node); - TestUtils.normalizeCompositeNode(compositeNode, modules, searchedModuleName + ":" + searchedDataSchemaName); + TestUtils.normalizeCompositeNode(node, modules, searchedModuleName + ":" + searchedDataSchemaName); - assertEquals("cont", compositeNode.getNodeType().getLocalName()); + assertEquals("cont", node.getNodeType().getLocalName()); - List> childs = compositeNode.getValue(); + assert(node instanceof CompositeNode); + List> childs = ((CompositeNode)node).getValue(); assertEquals(1, childs.size()); Node nd = childs.iterator().next(); assertTrue(nd instanceof CompositeNode); diff --git a/opendaylight/md-sal/sal-rest-connector/src/test/java/org/opendaylight/controller/sal/restconf/impl/json/to/cnsn/test/JsonLeafrefToCnSnTest.java b/opendaylight/md-sal/sal-rest-connector/src/test/java/org/opendaylight/controller/sal/restconf/impl/json/to/cnsn/test/JsonLeafrefToCnSnTest.java index 913e9f2d70..59696bc534 100644 --- a/opendaylight/md-sal/sal-rest-connector/src/test/java/org/opendaylight/controller/sal/restconf/impl/json/to/cnsn/test/JsonLeafrefToCnSnTest.java +++ b/opendaylight/md-sal/sal-rest-connector/src/test/java/org/opendaylight/controller/sal/restconf/impl/json/to/cnsn/test/JsonLeafrefToCnSnTest.java @@ -32,15 +32,16 @@ public class JsonLeafrefToCnSnTest extends YangAndXmlAndDataSchemaLoader { */ @Test public void jsonIdentityrefToCompositeNode() { - CompositeNode compositeNode = TestUtils.readInputToCnSn("/json-to-cnsn/leafref/json/data.json", false, + Node node = TestUtils.readInputToCnSn("/json-to-cnsn/leafref/json/data.json", false, JsonToCompositeNodeProvider.INSTANCE); - assertNotNull(compositeNode); - TestUtils.normalizeCompositeNode(compositeNode, modules, searchedModuleName + ":" + searchedDataSchemaName); + assertNotNull(node); + TestUtils.normalizeCompositeNode(node, modules, searchedModuleName + ":" + searchedDataSchemaName); - assertEquals("cont", compositeNode.getNodeType().getLocalName()); + assertEquals("cont", node.getNodeType().getLocalName()); SimpleNode lf2 = null; - for (Node childNode : compositeNode.getValue()) { + assertTrue(node instanceof CompositeNode); + for (Node childNode : ((CompositeNode) node).getValue()) { if (childNode instanceof SimpleNode) { if (childNode.getNodeType().getLocalName().equals("lf2")) { lf2 = (SimpleNode) childNode; diff --git a/opendaylight/md-sal/sal-rest-connector/src/test/java/org/opendaylight/controller/sal/restconf/impl/json/to/cnsn/test/JsonToCnSnTest.java b/opendaylight/md-sal/sal-rest-connector/src/test/java/org/opendaylight/controller/sal/restconf/impl/json/to/cnsn/test/JsonToCnSnTest.java index 7b71e42ab8..3699e4924f 100644 --- a/opendaylight/md-sal/sal-rest-connector/src/test/java/org/opendaylight/controller/sal/restconf/impl/json/to/cnsn/test/JsonToCnSnTest.java +++ b/opendaylight/md-sal/sal-rest-connector/src/test/java/org/opendaylight/controller/sal/restconf/impl/json/to/cnsn/test/JsonToCnSnTest.java @@ -11,6 +11,7 @@ import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertNotNull; import static org.junit.Assert.assertNull; import static org.junit.Assert.assertTrue; +import static org.junit.Assert.fail; import java.io.ByteArrayInputStream; import java.io.InputStream; @@ -52,19 +53,21 @@ public class JsonToCnSnTest { */ @Test public void multipleItemsInLeafList() { - CompositeNode compositeNode = TestUtils.readInputToCnSn("/json-to-cnsn/multiple-leaflist-items.json", true, + Node node = TestUtils.readInputToCnSn("/json-to-cnsn/multiple-leaflist-items.json", true, JsonToCompositeNodeProvider.INSTANCE); - assertNotNull(compositeNode); + assertNotNull(node); + assertTrue(node instanceof CompositeNode); + CompositeNode compositeNode = (CompositeNode)node; assertEquals(3, compositeNode.getValue().size()); boolean lflst1_1 = false; boolean lflst1_2 = false; boolean lflst1_3 = false; - for (Node node : compositeNode.getValue()) { - assertEquals("lflst1", node.getNodeType().getLocalName()); - assertTrue(node instanceof SimpleNode); - SimpleNode simpleNode = (SimpleNode) node; + for (Node nd : compositeNode.getValue()) { + assertEquals("lflst1", nd.getNodeType().getLocalName()); + assertTrue(nd instanceof SimpleNode); + SimpleNode simpleNode = (SimpleNode) nd; if (simpleNode.getValue().equals("45")) { lflst1_1 = true; } else if (simpleNode.getValue().equals("55")) { @@ -86,9 +89,12 @@ public class JsonToCnSnTest { */ @Test public void multipleItemsInListTest() { - CompositeNode compositeNode = TestUtils.readInputToCnSn("/json-to-cnsn/multiple-items-in-list.json", true, + Node node = TestUtils.readInputToCnSn("/json-to-cnsn/multiple-items-in-list.json", true, JsonToCompositeNodeProvider.INSTANCE); + assertTrue(node instanceof CompositeNode); + CompositeNode compositeNode = (CompositeNode)node; + assertNotNull(compositeNode); assertEquals("lst", compositeNode.getNodeType().getLocalName()); @@ -97,9 +103,10 @@ public class JsonToCnSnTest { @Test public void nullArrayToSimpleNodeWithNullValueTest() { - CompositeNode compositeNode = TestUtils.readInputToCnSn("/json-to-cnsn/array-with-null.json", true, + Node node = TestUtils.readInputToCnSn("/json-to-cnsn/array-with-null.json", true, JsonToCompositeNodeProvider.INSTANCE); - assertNotNull(compositeNode); + assertTrue(node instanceof CompositeNode); + CompositeNode compositeNode = (CompositeNode)node; assertEquals("cont", compositeNode.getNodeType().getLocalName()); assertNotNull(compositeNode.getValue()); @@ -163,10 +170,10 @@ public class JsonToCnSnTest { */ @Test public void emptyDataReadTest() { - CompositeNode compositeNode = TestUtils.readInputToCnSn("/json-to-cnsn/empty-data.json", true, + Node node = TestUtils.readInputToCnSn("/json-to-cnsn/empty-data.json", true, JsonToCompositeNodeProvider.INSTANCE); - - assertNotNull(compositeNode); + assertTrue(node instanceof CompositeNode); + CompositeNode compositeNode = (CompositeNode)node; assertEquals("cont", compositeNode.getNodeType().getLocalName()); assertTrue(compositeNode instanceof CompositeNode); @@ -189,9 +196,9 @@ public class JsonToCnSnTest { @Test public void testJsonBlankInput() throws Exception { InputStream inputStream = new ByteArrayInputStream("".getBytes()); - CompositeNode compositeNode = JsonToCompositeNodeProvider.INSTANCE.readFrom(null, null, null, null, null, - inputStream); - assertNull(compositeNode); + Node node = + JsonToCompositeNodeProvider.INSTANCE.readFrom(null, null, null, null, null, inputStream); + assertNull( node ); } /** @@ -202,9 +209,10 @@ public class JsonToCnSnTest { @Test public void notSupplyNamespaceIfAlreadySupplied() { - CompositeNode compositeNode = TestUtils.readInputToCnSn("/json-to-cnsn/simple-list.json", false, + Node node = TestUtils.readInputToCnSn("/json-to-cnsn/simple-list.json", false, JsonToCompositeNodeProvider.INSTANCE); - assertNotNull(compositeNode); + assertTrue(node instanceof CompositeNode); + CompositeNode compositeNode = (CompositeNode)node; // supplement namespaces according to first data schema - // "simple:data:types1" @@ -223,15 +231,21 @@ public class JsonToCnSnTest { assertEquals("lst", compNode.getNodeType().getLocalName()); verifyCompositeNode(compNode, "simple:list:yang1"); - TestUtils.normalizeCompositeNode(compositeNode, modules2, "simple-list-yang2:lst"); + try { + TestUtils.normalizeCompositeNode(compositeNode, modules2, "simple-list-yang2:lst"); + fail("Conversion to normalized node shouldn't be successfull because of different namespaces"); + } catch (IllegalStateException e) { + } +// veryfing has still meaning. despite exception, first phase where normalization of NodeWrappers is called passed successfuly. verifyCompositeNode(compNode, "simple:list:yang1"); } @Test public void jsonIdentityrefToCompositeNode() { - CompositeNode compositeNode = TestUtils.readInputToCnSn("/json-to-cnsn/identityref/json/data.json", false, + Node node = TestUtils.readInputToCnSn("/json-to-cnsn/identityref/json/data.json", false, JsonToCompositeNodeProvider.INSTANCE); - assertNotNull(compositeNode); + assertTrue(node instanceof CompositeNode); + CompositeNode compositeNode = (CompositeNode)node; Set modules = TestUtils.loadModulesFrom("/json-to-cnsn/identityref"); assertEquals(2, modules.size()); @@ -298,8 +312,9 @@ public class JsonToCnSnTest { private CompositeNode loadAndNormalizeData(final String jsonPath, final String yangPath, final String topLevelElementName, final String moduleName) { - CompositeNode compositeNode = TestUtils.readInputToCnSn(jsonPath, false, JsonToCompositeNodeProvider.INSTANCE); - assertNotNull(compositeNode); + Node node = TestUtils.readInputToCnSn(jsonPath, false, JsonToCompositeNodeProvider.INSTANCE); + assertTrue(node instanceof CompositeNode); + CompositeNode compositeNode = (CompositeNode)node; Set modules = null; modules = TestUtils.loadModulesFrom(yangPath); diff --git a/opendaylight/md-sal/sal-rest-connector/src/test/java/org/opendaylight/controller/sal/restconf/impl/test/BrokerFacadeTest.java b/opendaylight/md-sal/sal-rest-connector/src/test/java/org/opendaylight/controller/sal/restconf/impl/test/BrokerFacadeTest.java index 73f828c646..146e88299a 100644 --- a/opendaylight/md-sal/sal-rest-connector/src/test/java/org/opendaylight/controller/sal/restconf/impl/test/BrokerFacadeTest.java +++ b/opendaylight/md-sal/sal-rest-connector/src/test/java/org/opendaylight/controller/sal/restconf/impl/test/BrokerFacadeTest.java @@ -12,29 +12,36 @@ import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertNotNull; import static org.junit.Assert.assertSame; import static org.mockito.Matchers.any; +import static org.mockito.Matchers.eq; import static org.mockito.Mockito.inOrder; import static org.mockito.Mockito.mock; import static org.mockito.Mockito.verify; import static org.mockito.Mockito.verifyNoMoreInteractions; import static org.mockito.Mockito.when; -import com.google.common.collect.ImmutableMap; +import com.google.common.base.Optional; +import com.google.common.util.concurrent.CheckedFuture; import com.google.common.util.concurrent.Futures; -import java.util.Map; import java.util.concurrent.Future; import org.junit.Before; +import org.junit.Ignore; import org.junit.Test; import org.mockito.InOrder; 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.AsyncDataBroker.DataChangeScope; +import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType; +import org.opendaylight.controller.md.sal.common.api.data.ReadFailedException; +import org.opendaylight.controller.md.sal.common.api.data.TransactionCommitFailedException; +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.sal.core.api.Broker.ConsumerSession; -import org.opendaylight.controller.sal.core.api.data.DataBrokerService; -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.mount.MountInstance; -import org.opendaylight.controller.sal.rest.impl.XmlToCompositeNodeProvider; import org.opendaylight.controller.sal.restconf.impl.BrokerFacade; +import org.opendaylight.controller.sal.restconf.impl.ControllerContext; import org.opendaylight.controller.sal.restconf.impl.RestconfDocumentedException; import org.opendaylight.controller.sal.restconf.impl.RestconfError; import org.opendaylight.controller.sal.streams.listeners.ListenerAdapter; @@ -44,7 +51,9 @@ 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.YangInstanceIdentifier; -import org.opendaylight.yangtools.yang.data.impl.ImmutableCompositeNode; +import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier.NodeIdentifier; +import org.opendaylight.yangtools.yang.data.api.schema.NormalizedNode; +import org.opendaylight.yangtools.yang.data.impl.schema.Builders; /** * Unit tests for BrokerFacade. @@ -54,73 +63,85 @@ import org.opendaylight.yangtools.yang.data.impl.ImmutableCompositeNode; public class BrokerFacadeTest { @Mock - DataBrokerService dataBroker; - - @Mock - DataModificationTransaction mockTransaction; + DOMDataBroker domDataBroker; @Mock ConsumerSession mockConsumerSession; @Mock - MountInstance mockMountInstance; + DOMMountPoint mockMountInstance; BrokerFacade brokerFacade = BrokerFacade.getInstance(); - CompositeNode dataNode = TestUtils.readInputToCnSn("/parts/ietf-interfaces_interfaces.xml", - XmlToCompositeNodeProvider.INSTANCE); + CompositeNode dataNode; - QName qname = QName.create("node"); + NormalizedNode dummyNode = createDummyNode("test:module", "2014-01-09", "interfaces"); + CheckedFuture>,ReadFailedException> dummyNodeInFuture = wrapDummyNode(dummyNode); + + QName qname = TestUtils.buildQName("interfaces","test:module", "2014-01-09"); YangInstanceIdentifier instanceID = YangInstanceIdentifier.builder().node(qname).toInstance(); + @Mock + DOMDataReadOnlyTransaction rTransaction; + + @Mock + DOMDataWriteTransaction wTransaction; + + @Mock + DOMDataReadWriteTransaction rwTransaction; + @Before public void setUp() throws Exception { MockitoAnnotations.initMocks(this); - - brokerFacade.setDataService(dataBroker); + // TODO it is started before every test method + brokerFacade.setDomDataBroker(domDataBroker); brokerFacade.setContext(mockConsumerSession); - } + when(domDataBroker.newReadOnlyTransaction()).thenReturn(rTransaction); + when(domDataBroker.newWriteOnlyTransaction()).thenReturn(wTransaction); + when(domDataBroker.newReadWriteTransaction()).thenReturn(rwTransaction); - @Test - public void testReadConfigurationData() { - when(dataBroker.readConfigurationData(instanceID)).thenReturn(dataNode); + dataNode = TestUtils.prepareCompositeNodeWithIetfInterfacesInterfacesData(); - CompositeNode actualNode = brokerFacade.readConfigurationData(instanceID); + ControllerContext.getInstance().setSchemas(TestUtils.loadSchemaContext("/full-versions/test-module")); - assertSame("readConfigurationData", dataNode, actualNode); } - @Test - public void testReadConfigurationDataBehindMountPoint() { - when(mockMountInstance.readConfigurationData(instanceID)).thenReturn(dataNode); - - CompositeNode actualNode = brokerFacade.readConfigurationDataBehindMountPoint(mockMountInstance, instanceID); + private CheckedFuture>,ReadFailedException> wrapDummyNode(final NormalizedNode dummyNode) { + return Futures.immediateCheckedFuture(Optional.> of(dummyNode)); + } - assertSame("readConfigurationDataBehindMountPoint", dataNode, actualNode); + /** + * Value of this node shouldn't be important for testing purposes + */ + private NormalizedNode createDummyNode(final String namespace, final String date, final String localName) { + return Builders.containerBuilder() + .withNodeIdentifier(new NodeIdentifier(QName.create(namespace, date, localName))).build(); } @Test - public void testReadOperationalData() { - when(dataBroker.readOperationalData(instanceID)).thenReturn(dataNode); + public void testReadConfigurationData() { + when(rTransaction.read(any(LogicalDatastoreType.class), any(YangInstanceIdentifier.class))).thenReturn( + dummyNodeInFuture); - CompositeNode actualNode = brokerFacade.readOperationalData(instanceID); + NormalizedNode actualNode = brokerFacade.readConfigurationData(instanceID); - assertSame("readOperationalData", dataNode, actualNode); + assertSame("readConfigurationData", dummyNode, actualNode); } @Test - public void testReadOperationalDataBehindMountPoint() { - when(mockMountInstance.readOperationalData(instanceID)).thenReturn(dataNode); + public void testReadOperationalData() { + when(rTransaction.read(any(LogicalDatastoreType.class), any(YangInstanceIdentifier.class))).thenReturn( + dummyNodeInFuture); - CompositeNode actualNode = brokerFacade.readOperationalDataBehindMountPoint(mockMountInstance, instanceID); + NormalizedNode actualNode = brokerFacade.readOperationalData(instanceID); - assertSame("readOperationalDataBehindMountPoint", dataNode, actualNode); + assertSame("readOperationalData", dummyNode, actualNode); } @Test(expected = RestconfDocumentedException.class) public void testReadOperationalDataWithNoDataBroker() { - brokerFacade.setDataService(null); + brokerFacade.setDomDataBroker(null); brokerFacade.readOperationalData(instanceID); } @@ -146,111 +167,49 @@ public class BrokerFacadeTest { brokerFacade.invokeRpc(qname, dataNode); } + @Ignore @Test public void testCommitConfigurationDataPut() { - Future> expFuture = Futures.immediateFuture(null); - - when(dataBroker.beginTransaction()).thenReturn(mockTransaction); - mockTransaction.putConfigurationData(instanceID, dataNode); - when(mockTransaction.commit()).thenReturn(expFuture); - - Future> actualFuture = brokerFacade.commitConfigurationDataPut(instanceID, - dataNode); + CheckedFuture expFuture = mock(CheckedFuture.class); - assertSame("invokeRpc", expFuture, actualFuture); + when(wTransaction.submit()).thenReturn(expFuture); - InOrder inOrder = inOrder(dataBroker, mockTransaction); - inOrder.verify(dataBroker).beginTransaction(); - inOrder.verify(mockTransaction).putConfigurationData(instanceID, dataNode); - inOrder.verify(mockTransaction).commit(); - } - - @Test - public void testCommitConfigurationDataPutBehindMountPoint() { - Future> expFuture = Futures.immediateFuture(null); - - when(mockMountInstance.beginTransaction()).thenReturn(mockTransaction); - mockTransaction.putConfigurationData(instanceID, dataNode); - when(mockTransaction.commit()).thenReturn(expFuture); + Future actualFuture = brokerFacade.commitConfigurationDataPut(instanceID, dummyNode); - Future> actualFuture = brokerFacade.commitConfigurationDataPutBehindMountPoint( - mockMountInstance, instanceID, dataNode); - - assertSame("invokeRpc", expFuture, actualFuture); + assertSame("commitConfigurationDataPut", expFuture, actualFuture); - InOrder inOrder = inOrder(mockMountInstance, mockTransaction); - inOrder.verify(mockMountInstance).beginTransaction(); - inOrder.verify(mockTransaction).putConfigurationData(instanceID, dataNode); - inOrder.verify(mockTransaction).commit(); + InOrder inOrder = inOrder(domDataBroker, wTransaction); + inOrder.verify(domDataBroker).newWriteOnlyTransaction(); + inOrder.verify(wTransaction).put(LogicalDatastoreType.CONFIGURATION, instanceID, dummyNode); + inOrder.verify(wTransaction).submit(); } @Test public void testCommitConfigurationDataPost() { - Future> expFuture = Futures.immediateFuture(null); + CheckedFuture expFuture = mock(CheckedFuture.class); - Map nodeMap = new ImmutableMap.Builder() - .put(instanceID, dataNode).build(); + NormalizedNode dummyNode2 = createDummyNode("dummy:namespace2", "2014-07-01", "dummy local name2"); + when(rwTransaction.read(eq(LogicalDatastoreType.CONFIGURATION), any(YangInstanceIdentifier.class))).thenReturn( + wrapDummyNode(dummyNode2)); + when(rwTransaction.submit()).thenReturn(expFuture); - when(dataBroker.beginTransaction()).thenReturn(mockTransaction); - mockTransaction.putConfigurationData(instanceID, dataNode); - when(mockTransaction.getCreatedConfigurationData()).thenReturn(nodeMap); - when(mockTransaction.commit()).thenReturn(expFuture); + CheckedFuture actualFuture = brokerFacade.commitConfigurationDataPost( + instanceID, dummyNode); - Future> actualFuture = brokerFacade.commitConfigurationDataPost(instanceID, - dataNode); + assertSame("commitConfigurationDataPost", expFuture, actualFuture); - assertSame("commitConfigurationDataPut", expFuture, actualFuture); - - InOrder inOrder = inOrder(dataBroker, mockTransaction); - inOrder.verify(dataBroker).beginTransaction(); - inOrder.verify(mockTransaction).putConfigurationData(instanceID, dataNode); - inOrder.verify(mockTransaction).commit(); + InOrder inOrder = inOrder(domDataBroker, rwTransaction); + inOrder.verify(domDataBroker).newReadWriteTransaction(); + inOrder.verify(rwTransaction).merge(LogicalDatastoreType.CONFIGURATION, instanceID, dummyNode); + inOrder.verify(rwTransaction).submit(); } @Test(expected = RestconfDocumentedException.class) public void testCommitConfigurationDataPostAlreadyExists() { - when(dataBroker.beginTransaction()).thenReturn(mockTransaction); - mockTransaction.putConfigurationData(instanceID, dataNode); - when(mockTransaction.readConfigurationData(instanceID)).thenReturn(dataNode); + when(rwTransaction.read(eq(LogicalDatastoreType.CONFIGURATION), any(YangInstanceIdentifier.class))).thenReturn( + dummyNodeInFuture); try { - brokerFacade.commitConfigurationDataPost(instanceID, dataNode); - } catch (RestconfDocumentedException e) { - assertEquals("getErrorTag", RestconfError.ErrorTag.DATA_EXISTS, e.getErrors().get(0).getErrorTag()); - throw e; - } - } - - @Test - public void testCommitConfigurationDataPostBehindMountPoint() { - Future> expFuture = Futures.immediateFuture(null); - - Map nodeMap = new ImmutableMap.Builder() - .put(instanceID, dataNode).build(); - - when(mockMountInstance.beginTransaction()).thenReturn(mockTransaction); - mockTransaction.putConfigurationData(instanceID, dataNode); - when(mockTransaction.getCreatedConfigurationData()).thenReturn(nodeMap); - when(mockTransaction.commit()).thenReturn(expFuture); - - Future> actualFuture = brokerFacade.commitConfigurationDataPostBehindMountPoint( - mockMountInstance, instanceID, dataNode); - - assertSame("commitConfigurationDataPostBehindMountPoint", expFuture, actualFuture); - - InOrder inOrder = inOrder(mockMountInstance, mockTransaction); - inOrder.verify(mockMountInstance).beginTransaction(); - inOrder.verify(mockTransaction).putConfigurationData(instanceID, dataNode); - inOrder.verify(mockTransaction).commit(); - } - - @Test(expected = RestconfDocumentedException.class) - public void testCommitConfigurationDataPostBehindMountPointAlreadyExists() { - - when(mockMountInstance.beginTransaction()).thenReturn(mockTransaction); - mockTransaction.putConfigurationData(instanceID, dataNode); - when(mockTransaction.readConfigurationData(instanceID)).thenReturn(dataNode); - try { - brokerFacade.commitConfigurationDataPostBehindMountPoint(mockMountInstance, instanceID, dataNode); + brokerFacade.commitConfigurationDataPost(instanceID, dummyNode); } catch (RestconfDocumentedException e) { assertEquals("getErrorTag", RestconfError.ErrorTag.DATA_EXISTS, e.getErrors().get(0).getErrorTag()); throw e; @@ -259,43 +218,19 @@ public class BrokerFacadeTest { @Test public void testCommitConfigurationDataDelete() { - Future> expFuture = Futures.immediateFuture(null); + CheckedFuture expFuture = mock(CheckedFuture.class); - when(dataBroker.beginTransaction()).thenReturn(mockTransaction); - when(mockTransaction.readConfigurationData(any(YangInstanceIdentifier.class))).thenReturn( - ImmutableCompositeNode.builder().toInstance()); - mockTransaction.removeConfigurationData(instanceID); - when(mockTransaction.commit()).thenReturn(expFuture); + when(wTransaction.submit()).thenReturn(expFuture); - Future> actualFuture = brokerFacade.commitConfigurationDataDelete(instanceID); + CheckedFuture actualFuture = brokerFacade + .commitConfigurationDataDelete(instanceID); assertSame("commitConfigurationDataDelete", expFuture, actualFuture); - InOrder inOrder = inOrder(dataBroker, mockTransaction); - inOrder.verify(dataBroker).beginTransaction(); - inOrder.verify(mockTransaction).removeConfigurationData(instanceID); - inOrder.verify(mockTransaction).commit(); - } - - @Test - public void testCommitConfigurationDataDeleteBehindMountPoint() { - Future> expFuture = Futures.immediateFuture(null); - - when(mockMountInstance.beginTransaction()).thenReturn(mockTransaction); - when(mockTransaction.readConfigurationData(any(YangInstanceIdentifier.class))).thenReturn( - ImmutableCompositeNode.builder().toInstance()); - mockTransaction.removeConfigurationData(instanceID); - when(mockTransaction.commit()).thenReturn(expFuture); - - Future> actualFuture = brokerFacade.commitConfigurationDataDeleteBehindMountPoint( - mockMountInstance, instanceID); - - assertSame("commitConfigurationDataDeleteBehindMountPoint", expFuture, actualFuture); - - InOrder inOrder = inOrder(mockMountInstance, mockTransaction); - inOrder.verify(mockMountInstance).beginTransaction(); - inOrder.verify(mockTransaction).removeConfigurationData(instanceID); - inOrder.verify(mockTransaction).commit(); + InOrder inOrder = inOrder(domDataBroker, wTransaction); + inOrder.verify(domDataBroker).newWriteOnlyTransaction(); + inOrder.verify(wTransaction).delete(eq(LogicalDatastoreType.CONFIGURATION), any(YangInstanceIdentifier.class)); + inOrder.verify(wTransaction).submit(); } @SuppressWarnings("unchecked") @@ -303,16 +238,21 @@ public class BrokerFacadeTest { public void testRegisterToListenDataChanges() { ListenerAdapter listener = Notificator.createListener(instanceID, "stream"); - ListenerRegistration mockRegistration = mock(ListenerRegistration.class); - when(dataBroker.registerDataChangeListener(instanceID, listener)).thenReturn(mockRegistration); + ListenerRegistration mockRegistration = mock(ListenerRegistration.class); + + when( + domDataBroker.registerDataChangeListener(any(LogicalDatastoreType.class), eq(instanceID), eq(listener), + eq(DataChangeScope.BASE))).thenReturn(mockRegistration); - brokerFacade.registerToListenDataChanges(listener); + brokerFacade.registerToListenDataChanges(LogicalDatastoreType.CONFIGURATION, DataChangeScope.BASE, listener); - verify(dataBroker).registerDataChangeListener(instanceID, listener); + verify(domDataBroker).registerDataChangeListener(LogicalDatastoreType.CONFIGURATION, instanceID, listener, + DataChangeScope.BASE); assertEquals("isListening", true, listener.isListening()); - brokerFacade.registerToListenDataChanges(listener); - verifyNoMoreInteractions(dataBroker); + brokerFacade.registerToListenDataChanges(LogicalDatastoreType.CONFIGURATION, DataChangeScope.BASE, listener); + verifyNoMoreInteractions(domDataBroker); + } } diff --git a/opendaylight/md-sal/sal-rest-connector/src/test/java/org/opendaylight/controller/sal/restconf/impl/test/InvokeRpcMethodTest.java b/opendaylight/md-sal/sal-rest-connector/src/test/java/org/opendaylight/controller/sal/restconf/impl/test/InvokeRpcMethodTest.java index 9aab841546..500baafab3 100644 --- a/opendaylight/md-sal/sal-rest-connector/src/test/java/org/opendaylight/controller/sal/restconf/impl/test/InvokeRpcMethodTest.java +++ b/opendaylight/md-sal/sal-rest-connector/src/test/java/org/opendaylight/controller/sal/restconf/impl/test/InvokeRpcMethodTest.java @@ -36,7 +36,8 @@ import javax.ws.rs.core.UriInfo; import org.junit.Before; import org.junit.BeforeClass; import org.junit.Test; -import org.opendaylight.controller.sal.core.api.mount.MountInstance; +import org.opendaylight.controller.md.sal.dom.api.DOMMountPoint; +import org.opendaylight.controller.sal.core.api.RpcProvisionRegistry; import org.opendaylight.controller.sal.restconf.impl.BrokerFacade; import org.opendaylight.controller.sal.restconf.impl.ControllerContext; import org.opendaylight.controller.sal.restconf.impl.InstanceIdWithSchemaNode; @@ -317,9 +318,10 @@ public class InvokeRpcMethodTest { RpcDefinition mockRpc = mock(RpcDefinition.class); when(mockRpc.getQName()).thenReturn(cancelToastQName); - MountInstance mockMountPoint = mock(MountInstance.class); - when(mockMountPoint.rpc(eq(cancelToastQName), any(CompositeNode.class))).thenReturn(mockListener); - + DOMMountPoint mockMountPoint = mock(DOMMountPoint.class); + RpcProvisionRegistry mockedRpcProvisionRegistry = mock(RpcProvisionRegistry.class); + when(mockedRpcProvisionRegistry.invokeRpc(eq(cancelToastQName), any(CompositeNode.class))).thenReturn(mockListener); + when(mockMountPoint.getService(eq(RpcProvisionRegistry.class))).thenReturn(Optional.of(mockedRpcProvisionRegistry)); when(mockMountPoint.getSchemaContext()).thenReturn(TestUtils.loadSchemaContext("/invoke-rpc")); InstanceIdWithSchemaNode mockedInstanceId = mock(InstanceIdWithSchemaNode.class); diff --git a/opendaylight/md-sal/sal-rest-connector/src/test/java/org/opendaylight/controller/sal/restconf/impl/test/MultipleEqualNamesForDataNodesTest.java b/opendaylight/md-sal/sal-rest-connector/src/test/java/org/opendaylight/controller/sal/restconf/impl/test/MultipleEqualNamesForDataNodesTest.java index 5fbfc45352..478565f033 100644 --- a/opendaylight/md-sal/sal-rest-connector/src/test/java/org/opendaylight/controller/sal/restconf/impl/test/MultipleEqualNamesForDataNodesTest.java +++ b/opendaylight/md-sal/sal-rest-connector/src/test/java/org/opendaylight/controller/sal/restconf/impl/test/MultipleEqualNamesForDataNodesTest.java @@ -21,7 +21,7 @@ import org.opendaylight.controller.sal.restconf.impl.RestconfDocumentedException import org.opendaylight.controller.sal.restconf.impl.RestconfError; import org.opendaylight.controller.sal.restconf.impl.RestconfError.ErrorTag; import org.opendaylight.controller.sal.restconf.impl.RestconfError.ErrorType; -import org.opendaylight.yangtools.yang.data.api.CompositeNode; +import org.opendaylight.yangtools.yang.data.api.Node; import org.opendaylight.yangtools.yang.model.api.Module; /** @@ -57,16 +57,16 @@ public class MultipleEqualNamesForDataNodesTest { } private void multipleEqualNameDataNodeTest(String path, ErrorType errorType, ErrorTag errorTag, - MessageBodyReader messageBodyReader) { + MessageBodyReader> messageBodyReader) { try { - CompositeNode compositeNode = TestUtils.readInputToCnSn(path, false, messageBodyReader); - assertNotNull(compositeNode); + Node node = TestUtils.readInputToCnSn(path, false, messageBodyReader); + assertNotNull(node); Set modules = null; modules = TestUtils.loadModulesFrom("/equal-data-node-names/yang"); assertNotNull(modules); - TestUtils.normalizeCompositeNode(compositeNode, modules, "equal-data-node-names" + ":" + "cont"); + TestUtils.normalizeCompositeNode(node, modules, "equal-data-node-names" + ":" + "cont"); fail("Exception RestconfDocumentedException should be raised"); } catch (RestconfDocumentedException e) { List errors = e.getErrors(); diff --git a/opendaylight/md-sal/sal-rest-connector/src/test/java/org/opendaylight/controller/sal/restconf/impl/test/RestDeleteOperationTest.java b/opendaylight/md-sal/sal-rest-connector/src/test/java/org/opendaylight/controller/sal/restconf/impl/test/RestDeleteOperationTest.java index 66ced81817..8d5cac0204 100644 --- a/opendaylight/md-sal/sal-rest-connector/src/test/java/org/opendaylight/controller/sal/restconf/impl/test/RestDeleteOperationTest.java +++ b/opendaylight/md-sal/sal-rest-connector/src/test/java/org/opendaylight/controller/sal/restconf/impl/test/RestDeleteOperationTest.java @@ -10,13 +10,14 @@ package org.opendaylight.controller.sal.restconf.impl.test; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertNotNull; import static org.mockito.Matchers.any; +import static org.mockito.Mockito.doThrow; import static org.mockito.Mockito.mock; import static org.mockito.Mockito.when; +import com.google.common.util.concurrent.CheckedFuture; import java.io.FileNotFoundException; import java.io.UnsupportedEncodingException; import java.util.Set; -import java.util.concurrent.Future; import javax.ws.rs.core.Application; import javax.ws.rs.core.MediaType; import javax.ws.rs.core.Response; @@ -24,13 +25,12 @@ import org.glassfish.jersey.server.ResourceConfig; import org.glassfish.jersey.test.JerseyTest; import org.junit.BeforeClass; import org.junit.Test; -import org.opendaylight.controller.md.sal.common.api.TransactionStatus; import org.opendaylight.controller.sal.rest.impl.StructuredDataToXmlProvider; import org.opendaylight.controller.sal.rest.impl.XmlToCompositeNodeProvider; import org.opendaylight.controller.sal.restconf.impl.BrokerFacade; import org.opendaylight.controller.sal.restconf.impl.ControllerContext; +import org.opendaylight.controller.sal.restconf.impl.RestconfDocumentedException; import org.opendaylight.controller.sal.restconf.impl.RestconfImpl; -import org.opendaylight.yangtools.yang.common.RpcResult; import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier; import org.opendaylight.yangtools.yang.model.api.Module; import org.opendaylight.yangtools.yang.model.api.SchemaContext; @@ -70,21 +70,14 @@ public class RestDeleteOperationTest extends JerseyTest { @Test public void deleteConfigStatusCodes() throws UnsupportedEncodingException { String uri = "/config/test-interface:interfaces"; - Future> dummyFuture = createFuture(TransactionStatus.COMMITED); - when(brokerFacade.commitConfigurationDataDelete(any(YangInstanceIdentifier.class))).thenReturn(dummyFuture); + when(brokerFacade.commitConfigurationDataDelete(any(YangInstanceIdentifier.class))).thenReturn( + mock(CheckedFuture.class)); Response response = target(uri).request(MediaType.APPLICATION_XML).delete(); assertEquals(200, response.getStatus()); - dummyFuture = createFuture(TransactionStatus.FAILED); - when(brokerFacade.commitConfigurationDataDelete(any(YangInstanceIdentifier.class))).thenReturn(dummyFuture); + doThrow(RestconfDocumentedException.class).when(brokerFacade).commitConfigurationDataDelete( + any(YangInstanceIdentifier.class)); response = target(uri).request(MediaType.APPLICATION_XML).delete(); assertEquals(500, response.getStatus()); } - - private Future> createFuture(TransactionStatus statusName) { - RpcResult rpcResult = new DummyRpcResult.Builder().result(statusName) - .build(); - return new DummyFuture.Builder().rpcResult(rpcResult).build(); - } - } diff --git a/opendaylight/md-sal/sal-rest-connector/src/test/java/org/opendaylight/controller/sal/restconf/impl/test/RestGetOperationTest.java b/opendaylight/md-sal/sal-rest-connector/src/test/java/org/opendaylight/controller/sal/restconf/impl/test/RestGetOperationTest.java index ac660e32bc..539248a147 100644 --- a/opendaylight/md-sal/sal-rest-connector/src/test/java/org/opendaylight/controller/sal/restconf/impl/test/RestGetOperationTest.java +++ b/opendaylight/md-sal/sal-rest-connector/src/test/java/org/opendaylight/controller/sal/restconf/impl/test/RestGetOperationTest.java @@ -18,8 +18,10 @@ import static org.mockito.Matchers.eq; import static org.mockito.Mockito.mock; import static org.mockito.Mockito.when; +import com.google.common.base.Optional; +import com.google.common.collect.Lists; +import com.google.common.collect.Maps; import java.io.FileNotFoundException; -import java.io.InputStream; import java.io.UnsupportedEncodingException; import java.net.URI; import java.net.URISyntaxException; @@ -33,40 +35,43 @@ import java.util.Map; import java.util.Set; import java.util.regex.Matcher; import java.util.regex.Pattern; - import javax.ws.rs.core.Application; import javax.ws.rs.core.MediaType; import javax.ws.rs.core.MultivaluedHashMap; import javax.ws.rs.core.MultivaluedMap; import javax.ws.rs.core.Response; import javax.ws.rs.core.UriInfo; - import org.glassfish.jersey.server.ResourceConfig; import org.glassfish.jersey.test.JerseyTest; import org.junit.BeforeClass; import org.junit.Test; import org.mockito.invocation.InvocationOnMock; import org.mockito.stubbing.Answer; -import org.opendaylight.controller.sal.core.api.mount.MountInstance; -import org.opendaylight.controller.sal.core.api.mount.MountService; +import org.opendaylight.controller.md.sal.dom.api.DOMMountPoint; +import org.opendaylight.controller.md.sal.dom.api.DOMMountPointService; import org.opendaylight.controller.sal.rest.impl.JsonToCompositeNodeProvider; import org.opendaylight.controller.sal.rest.impl.RestconfDocumentedExceptionMapper; import org.opendaylight.controller.sal.rest.impl.StructuredDataToJsonProvider; import org.opendaylight.controller.sal.rest.impl.StructuredDataToXmlProvider; import org.opendaylight.controller.sal.rest.impl.XmlToCompositeNodeProvider; import org.opendaylight.controller.sal.restconf.impl.BrokerFacade; -import org.opendaylight.controller.sal.restconf.impl.CompositeNodeWrapper; import org.opendaylight.controller.sal.restconf.impl.ControllerContext; import org.opendaylight.controller.sal.restconf.impl.RestconfDocumentedException; import org.opendaylight.controller.sal.restconf.impl.RestconfImpl; -import org.opendaylight.controller.sal.restconf.impl.SimpleNodeWrapper; import org.opendaylight.yangtools.yang.common.QName; import org.opendaylight.yangtools.yang.data.api.CompositeNode; import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier; +import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier.NodeIdentifier; import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier.PathArgument; -import org.opendaylight.yangtools.yang.data.api.Node; +import org.opendaylight.yangtools.yang.data.api.schema.ContainerNode; +import org.opendaylight.yangtools.yang.data.api.schema.NormalizedNode; import org.opendaylight.yangtools.yang.data.impl.ImmutableCompositeNode; +import org.opendaylight.yangtools.yang.data.impl.schema.Builders; +import org.opendaylight.yangtools.yang.data.impl.schema.builder.impl.ImmutableLeafNodeBuilder; +import org.opendaylight.yangtools.yang.data.impl.schema.builder.impl.ImmutableMapEntryNodeBuilder; import org.opendaylight.yangtools.yang.data.impl.util.CompositeNodeBuilder; +import org.opendaylight.yangtools.yang.model.api.DataNodeContainer; +import org.opendaylight.yangtools.yang.model.api.DataSchemaNode; import org.opendaylight.yangtools.yang.model.api.Module; import org.opendaylight.yangtools.yang.model.api.RpcDefinition; import org.opendaylight.yangtools.yang.model.api.SchemaContext; @@ -74,9 +79,6 @@ import org.w3c.dom.Document; import org.w3c.dom.Element; import org.w3c.dom.NodeList; -import com.google.common.collect.Lists; -import com.google.common.collect.Maps; - public class RestGetOperationTest extends JerseyTest { static class NodeData { @@ -93,7 +95,7 @@ public class RestGetOperationTest extends JerseyTest { private static RestconfImpl restconfImpl; private static SchemaContext schemaContextYangsIetf; private static SchemaContext schemaContextTestModule; - private static CompositeNode answerFromGet; + private static NormalizedNode answerFromGet; private static SchemaContext schemaContextModules; private static SchemaContext schemaContextBehindMountPoint; @@ -101,7 +103,7 @@ public class RestGetOperationTest extends JerseyTest { private static final String RESTCONF_NS = "urn:ietf:params:xml:ns:yang:ietf-restconf"; @BeforeClass - public static void init() throws FileNotFoundException { + public static void init() throws FileNotFoundException, ParseException { schemaContextYangsIetf = TestUtils.loadSchemaContext("/full-versions/yangs"); schemaContextTestModule = TestUtils.loadSchemaContext("/full-versions/test-module"); ControllerContext controllerContext = ControllerContext.getInstance(); @@ -110,7 +112,7 @@ public class RestGetOperationTest extends JerseyTest { restconfImpl = RestconfImpl.getInstance(); restconfImpl.setBroker(brokerFacade); restconfImpl.setControllerContext(controllerContext); - answerFromGet = prepareCompositeNodeWithIetfInterfacesInterfacesData(); + answerFromGet = TestUtils.prepareNormalizedNodeWithIetfInterfacesInterfacesData(); schemaContextModules = TestUtils.loadSchemaContext("/modules"); schemaContextBehindMountPoint = TestUtils.loadSchemaContext("/modules/modules-behind-mount-point"); @@ -161,14 +163,13 @@ public class RestGetOperationTest extends JerseyTest { * MountPoint test. URI represents mount point. */ @Test - public void getDataWithUrlMountPoint() throws UnsupportedEncodingException, URISyntaxException { - when( - brokerFacade.readConfigurationDataBehindMountPoint(any(MountInstance.class), - any(YangInstanceIdentifier.class))).thenReturn(prepareCnDataForMountPointTest()); - MountInstance mountInstance = mock(MountInstance.class); + public void getDataWithUrlMountPoint() throws UnsupportedEncodingException, URISyntaxException, ParseException { + when(brokerFacade.readConfigurationData(any(DOMMountPoint.class), any(YangInstanceIdentifier.class))).thenReturn( + prepareCnDataForMountPointTest(false)); + DOMMountPoint mountInstance = mock(DOMMountPoint.class); when(mountInstance.getSchemaContext()).thenReturn(schemaContextTestModule); - MountService mockMountService = mock(MountService.class); - when(mockMountService.getMountPoint(any(YangInstanceIdentifier.class))).thenReturn(mountInstance); + DOMMountPointService mockMountService = mock(DOMMountPointService.class); + when(mockMountService.getMountPoint(any(YangInstanceIdentifier.class))).thenReturn(Optional.of(mountInstance)); ControllerContext.getInstance().setMountService(mockMountService); @@ -188,20 +189,18 @@ public class RestGetOperationTest extends JerseyTest { * {@link BrokerFacade#readConfigurationDataBehindMountPoint(MountInstance, YangInstanceIdentifier)} which is called in * method {@link RestconfImpl#readConfigurationData} * - * * @throws ParseException */ @Test public void getDataWithSlashesBehindMountPoint() throws UnsupportedEncodingException, URISyntaxException, ParseException { YangInstanceIdentifier awaitedInstanceIdentifier = prepareInstanceIdentifierForList(); - when( - brokerFacade.readConfigurationDataBehindMountPoint(any(MountInstance.class), - eq(awaitedInstanceIdentifier))).thenReturn(prepareCnDataForMountPointTest()); - MountInstance mountInstance = mock(MountInstance.class); + when(brokerFacade.readConfigurationData(any(DOMMountPoint.class), eq(awaitedInstanceIdentifier))).thenReturn( + prepareCnDataForSlashesBehindMountPointTest()); + DOMMountPoint mountInstance = mock(DOMMountPoint.class); when(mountInstance.getSchemaContext()).thenReturn(schemaContextTestModule); - MountService mockMountService = mock(MountService.class); - when(mockMountService.getMountPoint(any(YangInstanceIdentifier.class))).thenReturn(mountInstance); + DOMMountPointService mockMountService = mock(DOMMountPointService.class); + when(mockMountService.getMountPoint(any(YangInstanceIdentifier.class))).thenReturn(Optional.of(mountInstance)); ControllerContext.getInstance().setMountService(mockMountService); @@ -219,24 +218,25 @@ public class RestGetOperationTest extends JerseyTest { QName qNameKeyList = QName.create(uri, revision, "lf11"); parameters.add(new YangInstanceIdentifier.NodeIdentifier(qNameCont)); + parameters.add(new YangInstanceIdentifier.NodeIdentifier(qNameList)); parameters.add(new YangInstanceIdentifier.NodeIdentifierWithPredicates(qNameList, qNameKeyList, "GigabitEthernet0/0/0/0")); return YangInstanceIdentifier.create(parameters); } @Test - public void getDataMountPointIntoHighestElement() throws UnsupportedEncodingException, URISyntaxException { - when( - brokerFacade.readConfigurationDataBehindMountPoint(any(MountInstance.class), - any(YangInstanceIdentifier.class))).thenReturn(prepareCnDataForMountPointTest()); - MountInstance mountInstance = mock(MountInstance.class); + public void getDataMountPointIntoHighestElement() throws UnsupportedEncodingException, URISyntaxException, + ParseException { + when(brokerFacade.readConfigurationData(any(DOMMountPoint.class), any(YangInstanceIdentifier.class))).thenReturn( + prepareCnDataForMountPointTest(true)); + DOMMountPoint mountInstance = mock(DOMMountPoint.class); when(mountInstance.getSchemaContext()).thenReturn(schemaContextTestModule); - MountService mockMountService = mock(MountService.class); - when(mockMountService.getMountPoint(any(YangInstanceIdentifier.class))).thenReturn(mountInstance); + DOMMountPointService mockMountService = mock(DOMMountPointService.class); + when(mockMountService.getMountPoint(any(YangInstanceIdentifier.class))).thenReturn(Optional.of(mountInstance)); ControllerContext.getInstance().setMountService(mockMountService); - String uri = "/config/ietf-interfaces:interfaces/interface/0/yang-ext:mount/"; + String uri = "/config/ietf-interfaces:interfaces/interface/0/yang-ext:mount/test-module:cont"; assertEquals(200, get(uri, MediaType.APPLICATION_XML)); } @@ -361,10 +361,10 @@ public class RestGetOperationTest extends JerseyTest { ControllerContext controllerContext = ControllerContext.getInstance(); controllerContext.setGlobalSchema(schemaContextModules); - MountInstance mountInstance = mock(MountInstance.class); + DOMMountPoint mountInstance = mock(DOMMountPoint.class); when(mountInstance.getSchemaContext()).thenReturn(schemaContextBehindMountPoint); - MountService mockMountService = mock(MountService.class); - when(mockMountService.getMountPoint(any(YangInstanceIdentifier.class))).thenReturn(mountInstance); + DOMMountPointService mockMountService = mock(DOMMountPointService.class); + when(mockMountService.getMountPoint(any(YangInstanceIdentifier.class))).thenReturn(Optional.of(mountInstance)); controllerContext.setMountService(mockMountService); @@ -450,10 +450,10 @@ public class RestGetOperationTest extends JerseyTest { ControllerContext controllerContext = ControllerContext.getInstance(); controllerContext.setGlobalSchema(schemaContextModules); - MountInstance mountInstance = mock(MountInstance.class); + DOMMountPoint mountInstance = mock(DOMMountPoint.class); when(mountInstance.getSchemaContext()).thenReturn(schemaContextBehindMountPoint); - MountService mockMountService = mock(MountService.class); - when(mockMountService.getMountPoint(any(YangInstanceIdentifier.class))).thenReturn(mountInstance); + DOMMountPointService mockMountService = mock(DOMMountPointService.class); + when(mockMountService.getMountPoint(any(YangInstanceIdentifier.class))).thenReturn(Optional.of(mountInstance)); controllerContext.setMountService(mockMountService); @@ -484,10 +484,10 @@ public class RestGetOperationTest extends JerseyTest { ControllerContext controllerContext = ControllerContext.getInstance(); controllerContext.setGlobalSchema(schemaContextModules); - MountInstance mountInstance = mock(MountInstance.class); + DOMMountPoint mountInstance = mock(DOMMountPoint.class); when(mountInstance.getSchemaContext()).thenReturn(schemaContextBehindMountPoint); - MountService mockMountService = mock(MountService.class); - when(mockMountService.getMountPoint(any(YangInstanceIdentifier.class))).thenReturn(mountInstance); + DOMMountPointService mockMountService = mock(DOMMountPointService.class); + when(mockMountService.getMountPoint(any(YangInstanceIdentifier.class))).thenReturn(Optional.of(mountInstance)); controllerContext.setMountService(mockMountService); @@ -636,11 +636,30 @@ public class RestGetOperationTest extends JerseyTest { return target(uri).request(mediaType).get().getStatus(); } - private CompositeNode prepareCnDataForMountPointTest() throws URISyntaxException { - CompositeNodeWrapper cont1 = new CompositeNodeWrapper(new URI("test:module"), "cont1"); - SimpleNodeWrapper lf11 = new SimpleNodeWrapper(new URI("test:module"), "lf11", "lf11 value"); - cont1.addValue(lf11); - return cont1.unwrap(); + /** + container cont { + container cont1 { + leaf lf11 { + type string; + } + */ + private NormalizedNode prepareCnDataForMountPointTest(boolean wrapToCont) throws URISyntaxException, ParseException { + String testModuleDate = "2014-01-09"; + ContainerNode contChild = Builders + .containerBuilder() + .withNodeIdentifier(TestUtils.getNodeIdentifier("cont1", "test:module", testModuleDate)) + .withChild( + Builders.leafBuilder() + .withNodeIdentifier(TestUtils.getNodeIdentifier("lf11", "test:module", testModuleDate)) + .withValue("lf11 value").build()).build(); + + if (wrapToCont) { + return Builders.containerBuilder() + .withNodeIdentifier(TestUtils.getNodeIdentifier("cont", "test:module", testModuleDate)) + .withChild(contChild).build(); + } + return contChild; + } private void mockReadOperationalDataMethod() { @@ -651,22 +670,17 @@ public class RestGetOperationTest extends JerseyTest { when(brokerFacade.readConfigurationData(any(YangInstanceIdentifier.class))).thenReturn(answerFromGet); } - private static CompositeNode prepareCompositeNodeWithIetfInterfacesInterfacesData() { - CompositeNode intface; - try { - intface = new CompositeNodeWrapper(new URI("interface"), "interface"); - List> childs = new ArrayList<>(); - - childs.add(new SimpleNodeWrapper(new URI("name"), "name", "eth0")); - childs.add(new SimpleNodeWrapper(new URI("type"), "type", "ethernetCsmacd")); - childs.add(new SimpleNodeWrapper(new URI("enabled"), "enabled", Boolean.FALSE)); - childs.add(new SimpleNodeWrapper(new URI("description"), "description", "some interface")); - intface.setValue(childs); - return intface; - } catch (URISyntaxException e) { - } + private NormalizedNode prepareCnDataForSlashesBehindMountPointTest() throws ParseException { + return ImmutableMapEntryNodeBuilder + .create() + .withNodeIdentifier( + TestUtils.getNodeIdentifierPredicate("lst1", "test:module", "2014-01-09", "lf11", + "GigabitEthernet0/0/0/0")) + .withChild( + ImmutableLeafNodeBuilder.create() + .withNodeIdentifier(TestUtils.getNodeIdentifier("lf11", "test:module", "2014-01-09")) + .withValue("GigabitEthernet0/0/0/0").build()).build(); - return null; } /** @@ -682,6 +696,7 @@ public class RestGetOperationTest extends JerseyTest { private void getDataWithUriIncludeWhiteCharsParameter(final String target) throws UnsupportedEncodingException { mockReadConfigurationDataMethod(); + mockReadOperationalDataMethod(); String uri = "/" + target + "/ietf-interfaces:interfaces/interface/eth0"; Response response = target(uri).queryParam("prettyPrint", "false").request("application/xml").get(); String xmlData = response.readEntity(String.class); @@ -726,7 +741,14 @@ public class RestGetOperationTest extends JerseyTest { toSimpleNodeData(toNestedQName("depth3-leaf2"), "depth3-leaf2-value")), toSimpleNodeData(toNestedQName("depth2-leaf1"), "depth2-leaf1-value"))); - when(brokerFacade.readConfigurationData(any(YangInstanceIdentifier.class))).thenReturn(depth1Cont); + Module module = TestUtils.findModule(schemaContextModules.getModules(), "nested-module"); + assertNotNull(module); + + DataSchemaNode dataSchemaNode = TestUtils.resolveDataSchemaNode("depth1-cont", module); + assertNotNull(dataSchemaNode); + + when(brokerFacade.readConfigurationData(any(YangInstanceIdentifier.class))).thenReturn( + TestUtils.compositeNodeToDatastoreNormalizedNode(depth1Cont, dataSchemaNode)); // Test config with depth 1 @@ -852,7 +874,18 @@ public class RestGetOperationTest extends JerseyTest { toSimpleNodeData(toNestedQName("depth4-leaf1"), "depth4-leaf1-value")), toSimpleNodeData(toNestedQName("depth3-leaf1"), "depth3-leaf1-value"))); - when(brokerFacade.readOperationalData(any(YangInstanceIdentifier.class))).thenReturn(depth2Cont1); + assertTrue(dataSchemaNode instanceof DataNodeContainer); + DataSchemaNode depth2cont1Schema = null; + for (DataSchemaNode childNode : ((DataNodeContainer) dataSchemaNode).getChildNodes()) { + if (childNode.getQName().getLocalName().equals("depth2-cont1")) { + depth2cont1Schema = childNode; + break; + } + } + assertNotNull(depth2Cont1); + + when(brokerFacade.readOperationalData(any(YangInstanceIdentifier.class))).thenReturn( + TestUtils.compositeNodeToDatastoreNormalizedNode(depth2Cont1, depth2cont1Schema)); response = target("/operational/nested-module:depth1-cont/depth2-cont1").queryParam("depth", "3") .request("application/xml").get(); @@ -866,6 +899,9 @@ public class RestGetOperationTest extends JerseyTest { expectLeaf("depth3-leaf1", "depth3-leaf1-value"))); } + /** + * Tests behavior when invalid value of depth URI parameter + */ @Test public void getDataWithInvalidDepthParameterTest() { @@ -876,7 +912,7 @@ public class RestGetOperationTest extends JerseyTest { UriInfo mockInfo = mock(UriInfo.class); when(mockInfo.getQueryParameters(false)).thenAnswer(new Answer>() { @Override - public MultivaluedMap answer(final InvocationOnMock invocation) { + public MultivaluedMap answer(InvocationOnMock invocation) { return paramMap; } }); @@ -892,6 +928,10 @@ public class RestGetOperationTest extends JerseyTest { private void getDataWithInvalidDepthParameterTest(final UriInfo uriInfo) { try { + QName qNameDepth1Cont = QName.create("urn:nested:module", "2014-06-3", "depth1-cont"); + YangInstanceIdentifier ii = YangInstanceIdentifier.builder().node(qNameDepth1Cont).build(); + NormalizedNode value = (NormalizedNode)(Builders.containerBuilder().withNodeIdentifier(new NodeIdentifier(qNameDepth1Cont)).build()); + when(brokerFacade.readConfigurationData(eq(ii))).thenReturn(value); restconfImpl.readConfigurationData("nested-module:depth1-cont", uriInfo); fail("Expected RestconfDocumentedException"); } catch (RestconfDocumentedException e) { @@ -901,8 +941,9 @@ public class RestGetOperationTest extends JerseyTest { } private void verifyXMLResponse(final Response response, final NodeData nodeData) { - - Document doc = TestUtils.loadDocumentFrom((InputStream) response.getEntity()); + Document doc = response.readEntity(Document.class); +// Document doc = TestUtils.loadDocumentFrom((InputStream) response.getEntity()); +// System.out.println(); assertNotNull("Could not parse XML document", doc); // System.out.println(TestUtils.getDocumentInPrintableForm( doc )); @@ -913,11 +954,11 @@ public class RestGetOperationTest extends JerseyTest { @SuppressWarnings("unchecked") private void verifyContainerElement(final Element element, final NodeData nodeData) { - assertEquals("Element local name", nodeData.key, element.getNodeName()); + assertEquals("Element local name", nodeData.key, element.getLocalName()); NodeList childNodes = element.getChildNodes(); if (nodeData.data == null) { // empty container - assertTrue("Expected no child elements for \"" + element.getNodeName() + "\"", childNodes.getLength() == 0); + assertTrue("Expected no child elements for \"" + element.getLocalName() + "\"", childNodes.getLength() == 0); return; } @@ -933,21 +974,21 @@ public class RestGetOperationTest extends JerseyTest { } Element actualElement = (Element) actualChild; - NodeData expChild = expChildMap.remove(actualElement.getNodeName()); + NodeData expChild = expChildMap.remove(actualElement.getLocalName()); assertNotNull( - "Unexpected child element for parent \"" + element.getNodeName() + "\": " - + actualElement.getNodeName(), expChild); + "Unexpected child element for parent \"" + element.getLocalName() + "\": " + + actualElement.getLocalName(), expChild); if (expChild.data == null || expChild.data instanceof List) { verifyContainerElement(actualElement, expChild); } else { - assertEquals("Text content for element: " + actualElement.getNodeName(), expChild.data, + assertEquals("Text content for element: " + actualElement.getLocalName(), expChild.data, actualElement.getTextContent()); } } if (!expChildMap.isEmpty()) { - fail("Missing elements for parent \"" + element.getNodeName() + "\": " + expChildMap.keySet()); + fail("Missing elements for parent \"" + element.getLocalName() + "\": " + expChildMap.keySet()); } } @@ -990,4 +1031,5 @@ public class RestGetOperationTest extends JerseyTest { private NodeData toSimpleNodeData(final QName key, final Object value) { return new NodeData(key, value); } + } diff --git a/opendaylight/md-sal/sal-rest-connector/src/test/java/org/opendaylight/controller/sal/restconf/impl/test/RestPostOperationTest.java b/opendaylight/md-sal/sal-rest-connector/src/test/java/org/opendaylight/controller/sal/restconf/impl/test/RestPostOperationTest.java index 979b58b78a..97cd67d34b 100644 --- a/opendaylight/md-sal/sal-rest-connector/src/test/java/org/opendaylight/controller/sal/restconf/impl/test/RestPostOperationTest.java +++ b/opendaylight/md-sal/sal-rest-connector/src/test/java/org/opendaylight/controller/sal/restconf/impl/test/RestPostOperationTest.java @@ -9,12 +9,16 @@ package org.opendaylight.controller.sal.restconf.impl.test; import static org.junit.Assert.assertEquals; import static org.mockito.Matchers.any; +import static org.mockito.Mockito.doReturn; +import static org.mockito.Mockito.doThrow; import static org.mockito.Mockito.mock; import static org.mockito.Mockito.times; import static org.mockito.Mockito.verify; import static org.mockito.Mockito.when; import static org.opendaylight.controller.sal.restconf.impl.test.RestOperationUtils.XML; +import com.google.common.base.Optional; +import com.google.common.util.concurrent.CheckedFuture; import com.google.common.util.concurrent.Futures; import java.io.IOException; import java.io.InputStream; @@ -27,7 +31,6 @@ import java.util.Collection; import java.util.Collections; import java.util.List; import java.util.Set; -import java.util.concurrent.Future; import javax.ws.rs.client.Entity; import javax.ws.rs.core.Application; import javax.ws.rs.core.MediaType; @@ -37,8 +40,8 @@ import org.junit.BeforeClass; import org.junit.Test; import org.mockito.ArgumentCaptor; import org.opendaylight.controller.md.sal.common.api.TransactionStatus; -import org.opendaylight.controller.sal.core.api.mount.MountInstance; -import org.opendaylight.controller.sal.core.api.mount.MountService; +import org.opendaylight.controller.md.sal.dom.api.DOMMountPoint; +import org.opendaylight.controller.md.sal.dom.api.DOMMountPointService; import org.opendaylight.controller.sal.rest.api.Draft02; import org.opendaylight.controller.sal.rest.impl.JsonToCompositeNodeProvider; import org.opendaylight.controller.sal.rest.impl.RestconfDocumentedExceptionMapper; @@ -48,14 +51,16 @@ import org.opendaylight.controller.sal.rest.impl.XmlToCompositeNodeProvider; import org.opendaylight.controller.sal.restconf.impl.BrokerFacade; import org.opendaylight.controller.sal.restconf.impl.CompositeNodeWrapper; import org.opendaylight.controller.sal.restconf.impl.ControllerContext; +import org.opendaylight.controller.sal.restconf.impl.RestconfDocumentedException; import org.opendaylight.controller.sal.restconf.impl.RestconfImpl; import org.opendaylight.yangtools.yang.common.QName; import org.opendaylight.yangtools.yang.common.RpcError; -import org.opendaylight.yangtools.yang.common.RpcResultBuilder; import org.opendaylight.yangtools.yang.common.RpcError.ErrorType; import org.opendaylight.yangtools.yang.common.RpcResult; +import org.opendaylight.yangtools.yang.common.RpcResultBuilder; import org.opendaylight.yangtools.yang.data.api.CompositeNode; import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier; +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; @@ -77,7 +82,7 @@ public class RestPostOperationTest extends JerseyTest { private static SchemaContext schemaContextTestModule; private static SchemaContext schemaContext; - private static MountService mountService; + private static DOMMountPointService mountService; @BeforeClass public static void init() throws URISyntaxException, IOException { @@ -124,10 +129,9 @@ public class RestPostOperationTest extends JerseyTest { assertEquals(500, post(uri, MediaType.APPLICATION_XML, xmlDataRpcInput)); List rpcErrors = new ArrayList<>(); - rpcErrors.add( RpcResultBuilder.newError( ErrorType.RPC, "tag1", "message1", - "applicationTag1", "info1", null ) ); - rpcErrors.add( RpcResultBuilder.newWarning( ErrorType.PROTOCOL, "tag2", "message2", - "applicationTag2", "info2", null ) ); + rpcErrors.add(RpcResultBuilder.newError(ErrorType.RPC, "tag1", "message1", "applicationTag1", "info1", null)); + rpcErrors.add(RpcResultBuilder.newWarning(ErrorType.PROTOCOL, "tag2", "message2", "applicationTag2", "info2", + null)); mockInvokeRpc(null, false, rpcErrors); assertEquals(500, post(uri, MediaType.APPLICATION_XML, xmlDataRpcInput)); @@ -138,28 +142,25 @@ public class RestPostOperationTest extends JerseyTest { @Test public void postConfigOnlyStatusCodes() throws UnsupportedEncodingException { controllerContext.setSchemas(schemaContextYangsIetf); - mockCommitConfigurationDataPostMethod(TransactionStatus.COMMITED); String uri = "/config"; + mockCommitConfigurationDataPostMethod(true); assertEquals(204, post(uri, MediaType.APPLICATION_XML, xmlDataAbsolutePath)); - mockCommitConfigurationDataPostMethod(null); - assertEquals(202, post(uri, MediaType.APPLICATION_XML, xmlDataAbsolutePath)); - - mockCommitConfigurationDataPostMethod(TransactionStatus.FAILED); + mockCommitConfigurationDataPostMethod(false); assertEquals(500, post(uri, MediaType.APPLICATION_XML, xmlDataAbsolutePath)); + + assertEquals(400, post(uri, MediaType.APPLICATION_XML, "")); } @Test public void postConfigStatusCodes() throws UnsupportedEncodingException { controllerContext.setSchemas(schemaContextYangsIetf); - mockCommitConfigurationDataPostMethod(TransactionStatus.COMMITED); String uri = "/config/ietf-interfaces:interfaces"; - assertEquals(204, post(uri, MediaType.APPLICATION_XML, xmlDataInterfaceAbsolutePath)); - mockCommitConfigurationDataPostMethod(null); - assertEquals(202, post(uri, MediaType.APPLICATION_XML, xmlDataInterfaceAbsolutePath)); + mockCommitConfigurationDataPostMethod(true); + assertEquals(204, post(uri, MediaType.APPLICATION_XML, xmlDataInterfaceAbsolutePath)); - mockCommitConfigurationDataPostMethod(TransactionStatus.FAILED); + mockCommitConfigurationDataPostMethod(false); assertEquals(500, post(uri, MediaType.APPLICATION_XML, xmlDataInterfaceAbsolutePath)); assertEquals(400, post(uri, MediaType.APPLICATION_JSON, "")); @@ -168,18 +169,14 @@ public class RestPostOperationTest extends JerseyTest { @Test public void postDataViaUrlMountPoint() throws UnsupportedEncodingException { controllerContext.setSchemas(schemaContextYangsIetf); - RpcResult rpcResult = new DummyRpcResult.Builder().result( - TransactionStatus.COMMITED).build(); - Future> dummyFuture = new DummyFuture.Builder().rpcResult( - rpcResult).build(); when( - brokerFacade.commitConfigurationDataPostBehindMountPoint(any(MountInstance.class), - any(YangInstanceIdentifier.class), any(CompositeNode.class))).thenReturn(dummyFuture); + brokerFacade.commitConfigurationDataPost(any(DOMMountPoint.class), any(YangInstanceIdentifier.class), + any(NormalizedNode.class))).thenReturn(mock(CheckedFuture.class)); - MountInstance mountInstance = mock(MountInstance.class); + DOMMountPoint mountInstance = mock(DOMMountPoint.class); when(mountInstance.getSchemaContext()).thenReturn(schemaContextTestModule); - MountService mockMountService = mock(MountService.class); - when(mockMountService.getMountPoint(any(YangInstanceIdentifier.class))).thenReturn(mountInstance); + DOMMountPointService mockMountService = mock(DOMMountPointService.class); + when(mockMountService.getMountPoint(any(YangInstanceIdentifier.class))).thenReturn(Optional.of(mountInstance)); ControllerContext.getInstance().setMountService(mockMountService); @@ -207,18 +204,13 @@ public class RestPostOperationTest extends JerseyTest { mockInvokeRpc(result, sucessful, Collections. emptyList()); } - private void mockCommitConfigurationDataPostMethod(TransactionStatus statusName) { - RpcResult rpcResult = new DummyRpcResult.Builder().result(statusName) - .build(); - Future> dummyFuture = null; - if (statusName != null) { - dummyFuture = new DummyFuture.Builder().rpcResult(rpcResult).build(); + private void mockCommitConfigurationDataPostMethod(final boolean succesfulComit) { + if (succesfulComit) { + doReturn(mock(CheckedFuture.class)).when(brokerFacade).commitConfigurationDataPost(any(YangInstanceIdentifier.class), any(NormalizedNode.class)); } else { - dummyFuture = new DummyFuture.Builder().build(); + doThrow(RestconfDocumentedException.class).when(brokerFacade).commitConfigurationDataPost( + any(YangInstanceIdentifier.class), any(NormalizedNode.class)); } - - when(brokerFacade.commitConfigurationDataPost(any(YangInstanceIdentifier.class), any(CompositeNode.class))) - .thenReturn(dummyFuture); } @Test @@ -226,14 +218,12 @@ public class RestPostOperationTest extends JerseyTest { initMocking(); RpcResult rpcResult = new DummyRpcResult.Builder().result( TransactionStatus.COMMITED).build(); - Future> dummyFuture = new DummyFuture.Builder().rpcResult( - rpcResult).build(); - when(brokerFacade.commitConfigurationDataPost(any(YangInstanceIdentifier.class), any(CompositeNode.class))) - .thenReturn(dummyFuture); + when(brokerFacade.commitConfigurationDataPost(any(YangInstanceIdentifier.class), any(NormalizedNode.class))) + .thenReturn(mock(CheckedFuture.class)); ArgumentCaptor instanceIdCaptor = ArgumentCaptor.forClass(YangInstanceIdentifier.class); - ArgumentCaptor compNodeCaptor = ArgumentCaptor.forClass(CompositeNode.class); + ArgumentCaptor compNodeCaptor = ArgumentCaptor.forClass(NormalizedNode.class); String URI_1 = "/config"; assertEquals(204, post(URI_1, Draft02.MediaTypes.DATA + XML, xmlTestInterface)); @@ -253,20 +243,20 @@ public class RestPostOperationTest extends JerseyTest { public void createConfigurationDataNullTest() throws UnsupportedEncodingException { initMocking(); - when(brokerFacade.commitConfigurationDataPost(any(YangInstanceIdentifier.class), any(CompositeNode.class))) + when(brokerFacade.commitConfigurationDataPost(any(YangInstanceIdentifier.class), any(NormalizedNode.class))) .thenReturn(null); String URI_1 = "/config"; - assertEquals(202, post(URI_1, Draft02.MediaTypes.DATA + XML, xmlTestInterface)); + assertEquals(204, post(URI_1, Draft02.MediaTypes.DATA + XML, xmlTestInterface)); String URI_2 = "/config/test-interface:interfaces"; - assertEquals(202, post(URI_2, Draft02.MediaTypes.DATA + XML, xmlBlockData)); + assertEquals(204, post(URI_2, Draft02.MediaTypes.DATA + XML, xmlBlockData)); } private static void initMocking() { controllerContext = ControllerContext.getInstance(); controllerContext.setSchemas(schemaContext); - mountService = mock(MountService.class); + mountService = mock(DOMMountPointService.class); controllerContext.setMountService(mountService); brokerFacade = mock(BrokerFacade.class); restconfImpl = RestconfImpl.getInstance(); diff --git a/opendaylight/md-sal/sal-rest-connector/src/test/java/org/opendaylight/controller/sal/restconf/impl/test/RestPutOperationTest.java b/opendaylight/md-sal/sal-rest-connector/src/test/java/org/opendaylight/controller/sal/restconf/impl/test/RestPutOperationTest.java index 5d837f42bd..3284546dcb 100644 --- a/opendaylight/md-sal/sal-rest-connector/src/test/java/org/opendaylight/controller/sal/restconf/impl/test/RestPutOperationTest.java +++ b/opendaylight/md-sal/sal-rest-connector/src/test/java/org/opendaylight/controller/sal/restconf/impl/test/RestPutOperationTest.java @@ -9,15 +9,18 @@ package org.opendaylight.controller.sal.restconf.impl.test; import static org.junit.Assert.assertEquals; import static org.mockito.Matchers.any; +import static org.mockito.Mockito.doReturn; +import static org.mockito.Mockito.doThrow; import static org.mockito.Mockito.mock; import static org.mockito.Mockito.when; +import com.google.common.base.Optional; +import com.google.common.util.concurrent.CheckedFuture; import java.io.FileNotFoundException; import java.io.IOException; import java.io.InputStream; import java.io.UnsupportedEncodingException; import java.net.URISyntaxException; -import java.util.concurrent.Future; import javax.ws.rs.client.Entity; import javax.ws.rs.core.Application; import javax.ws.rs.core.MediaType; @@ -26,9 +29,9 @@ import org.glassfish.jersey.server.ResourceConfig; import org.glassfish.jersey.test.JerseyTest; import org.junit.BeforeClass; import org.junit.Test; -import org.opendaylight.controller.md.sal.common.api.TransactionStatus; -import org.opendaylight.controller.sal.core.api.mount.MountInstance; -import org.opendaylight.controller.sal.core.api.mount.MountService; +import org.opendaylight.controller.md.sal.common.api.data.TransactionCommitFailedException; +import org.opendaylight.controller.md.sal.dom.api.DOMMountPoint; +import org.opendaylight.controller.md.sal.dom.api.DOMMountPointService; import org.opendaylight.controller.sal.rest.impl.JsonToCompositeNodeProvider; import org.opendaylight.controller.sal.rest.impl.RestconfDocumentedExceptionMapper; import org.opendaylight.controller.sal.rest.impl.StructuredDataToJsonProvider; @@ -36,10 +39,10 @@ import org.opendaylight.controller.sal.rest.impl.StructuredDataToXmlProvider; import org.opendaylight.controller.sal.rest.impl.XmlToCompositeNodeProvider; import org.opendaylight.controller.sal.restconf.impl.BrokerFacade; import org.opendaylight.controller.sal.restconf.impl.ControllerContext; +import org.opendaylight.controller.sal.restconf.impl.RestconfDocumentedException; import org.opendaylight.controller.sal.restconf.impl.RestconfImpl; -import org.opendaylight.yangtools.yang.common.RpcResult; -import org.opendaylight.yangtools.yang.data.api.CompositeNode; import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier; +import org.opendaylight.yangtools.yang.data.api.schema.NormalizedNode; import org.opendaylight.yangtools.yang.model.api.SchemaContext; public class RestPutOperationTest extends JerseyTest { @@ -96,10 +99,10 @@ public class RestPutOperationTest extends JerseyTest { @Test public void putConfigStatusCodes() throws UnsupportedEncodingException { String uri = "/config/ietf-interfaces:interfaces/interface/eth0"; - mockCommitConfigurationDataPutMethod(TransactionStatus.COMMITED); + mockCommitConfigurationDataPutMethod(true); assertEquals(200, put(uri, MediaType.APPLICATION_XML, xmlData)); - mockCommitConfigurationDataPutMethod(TransactionStatus.FAILED); + mockCommitConfigurationDataPutMethod(false); assertEquals(500, put(uri, MediaType.APPLICATION_XML, xmlData)); assertEquals(400, put(uri, MediaType.APPLICATION_JSON, "")); @@ -117,18 +120,16 @@ public class RestPutOperationTest extends JerseyTest { public void testRpcResultCommitedToStatusCodesWithMountPoint() throws UnsupportedEncodingException, FileNotFoundException, URISyntaxException { - RpcResult rpcResult = new DummyRpcResult.Builder().result( - TransactionStatus.COMMITED).build(); - Future> dummyFuture = new DummyFuture.Builder().rpcResult( - rpcResult).build(); + CheckedFuture dummyFuture = mock(CheckedFuture.class); + when( - brokerFacade.commitConfigurationDataPutBehindMountPoint(any(MountInstance.class), - any(YangInstanceIdentifier.class), any(CompositeNode.class))).thenReturn(dummyFuture); + brokerFacade.commitConfigurationDataPut(any(DOMMountPoint.class), any(YangInstanceIdentifier.class), + any(NormalizedNode.class))).thenReturn(dummyFuture); - MountInstance mountInstance = mock(MountInstance.class); + DOMMountPoint mountInstance = mock(DOMMountPoint.class); when(mountInstance.getSchemaContext()).thenReturn(schemaContextTestModule); - MountService mockMountService = mock(MountService.class); - when(mockMountService.getMountPoint(any(YangInstanceIdentifier.class))).thenReturn(mountInstance); + DOMMountPointService mockMountService = mock(DOMMountPointService.class); + when(mockMountService.getMountPoint(any(YangInstanceIdentifier.class))).thenReturn(Optional.of(mountInstance)); ControllerContext.getInstance().setMountService(mockMountService); @@ -141,18 +142,15 @@ public class RestPutOperationTest extends JerseyTest { @Test public void putDataMountPointIntoHighestElement() throws UnsupportedEncodingException, URISyntaxException { - RpcResult rpcResult = new DummyRpcResult.Builder().result( - TransactionStatus.COMMITED).build(); - Future> dummyFuture = new DummyFuture.Builder().rpcResult( - rpcResult).build(); + CheckedFuture dummyFuture = mock(CheckedFuture.class); when( - brokerFacade.commitConfigurationDataPutBehindMountPoint(any(MountInstance.class), - any(YangInstanceIdentifier.class), any(CompositeNode.class))).thenReturn(dummyFuture); + brokerFacade.commitConfigurationDataPut(any(DOMMountPoint.class), any(YangInstanceIdentifier.class), + any(NormalizedNode.class))).thenReturn(dummyFuture); - MountInstance mountInstance = mock(MountInstance.class); + DOMMountPoint mountInstance = mock(DOMMountPoint.class); when(mountInstance.getSchemaContext()).thenReturn(schemaContextTestModule); - MountService mockMountService = mock(MountService.class); - when(mockMountService.getMountPoint(any(YangInstanceIdentifier.class))).thenReturn(mountInstance); + DOMMountPointService mockMountService = mock(DOMMountPointService.class); + when(mockMountService.getMountPoint(any(YangInstanceIdentifier.class))).thenReturn(Optional.of(mountInstance)); ControllerContext.getInstance().setMountService(mockMountService); @@ -164,13 +162,14 @@ public class RestPutOperationTest extends JerseyTest { return target(uri).request(mediaType).put(Entity.entity(data, mediaType)).getStatus(); } - private void mockCommitConfigurationDataPutMethod(TransactionStatus statusName) { - RpcResult rpcResult = new DummyRpcResult.Builder().result(statusName) - .build(); - Future> dummyFuture = new DummyFuture.Builder().rpcResult( - rpcResult).build(); - when(brokerFacade.commitConfigurationDataPut(any(YangInstanceIdentifier.class), any(CompositeNode.class))) - .thenReturn(dummyFuture); + private void mockCommitConfigurationDataPutMethod(final boolean noErrors) { + if (noErrors) { + doReturn(mock(CheckedFuture.class)).when(brokerFacade).commitConfigurationDataPut( + any(YangInstanceIdentifier.class), any(NormalizedNode.class)); + } else { + doThrow(RestconfDocumentedException.class).when(brokerFacade).commitConfigurationDataPut( + any(YangInstanceIdentifier.class), any(NormalizedNode.class)); + } } } diff --git a/opendaylight/md-sal/sal-rest-connector/src/test/java/org/opendaylight/controller/sal/restconf/impl/test/RestconfImplTest.java b/opendaylight/md-sal/sal-rest-connector/src/test/java/org/opendaylight/controller/sal/restconf/impl/test/RestconfImplTest.java index 236712b454..906695b3aa 100644 --- a/opendaylight/md-sal/sal-rest-connector/src/test/java/org/opendaylight/controller/sal/restconf/impl/test/RestconfImplTest.java +++ b/opendaylight/md-sal/sal-rest-connector/src/test/java/org/opendaylight/controller/sal/restconf/impl/test/RestconfImplTest.java @@ -15,16 +15,16 @@ import static org.mockito.Mockito.spy; import static org.mockito.Mockito.when; import java.io.FileNotFoundException; +import java.text.ParseException; import java.util.Set; import org.junit.Before; import org.junit.BeforeClass; import org.junit.Test; -import org.opendaylight.controller.sal.rest.impl.XmlToCompositeNodeProvider; import org.opendaylight.controller.sal.restconf.impl.BrokerFacade; import org.opendaylight.controller.sal.restconf.impl.ControllerContext; import org.opendaylight.controller.sal.restconf.impl.RestconfImpl; -import org.opendaylight.yangtools.yang.data.api.CompositeNode; import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier; +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; @@ -54,12 +54,12 @@ public class RestconfImplTest { } @Test - public void testExample() throws FileNotFoundException { - CompositeNode loadedCompositeNode = TestUtils.readInputToCnSn("/parts/ietf-interfaces_interfaces.xml", - XmlToCompositeNodeProvider.INSTANCE); + public void testExample() throws FileNotFoundException, ParseException { + NormalizedNode normalizedNodeData = TestUtils.prepareNormalizedNodeWithIetfInterfacesInterfacesData(); BrokerFacade brokerFacade = mock(BrokerFacade.class); - when(brokerFacade.readOperationalData(any(YangInstanceIdentifier.class))).thenReturn(loadedCompositeNode); - assertEquals(loadedCompositeNode, brokerFacade.readOperationalData(null)); + when(brokerFacade.readOperationalData(any(YangInstanceIdentifier.class))).thenReturn(normalizedNodeData); + assertEquals(normalizedNodeData, + brokerFacade.readOperationalData(null)); } } diff --git a/opendaylight/md-sal/sal-rest-connector/src/test/java/org/opendaylight/controller/sal/restconf/impl/test/TestUtils.java b/opendaylight/md-sal/sal-rest-connector/src/test/java/org/opendaylight/controller/sal/restconf/impl/test/TestUtils.java index 67d98f6b55..c2b153f02b 100644 --- a/opendaylight/md-sal/sal-rest-connector/src/test/java/org/opendaylight/controller/sal/restconf/impl/test/TestUtils.java +++ b/opendaylight/md-sal/sal-rest-connector/src/test/java/org/opendaylight/controller/sal/restconf/impl/test/TestUtils.java @@ -14,6 +14,7 @@ import static org.mockito.Mockito.mock; import static org.mockito.Mockito.when; import com.google.common.base.Preconditions; +import com.google.common.util.concurrent.CheckedFuture; import java.io.BufferedReader; import java.io.ByteArrayOutputStream; import java.io.File; @@ -25,8 +26,12 @@ import java.io.OutputStreamWriter; import java.net.URI; import java.net.URISyntaxException; import java.sql.Date; +import java.text.ParseException; +import java.text.SimpleDateFormat; import java.util.ArrayList; +import java.util.HashMap; import java.util.List; +import java.util.Map; import java.util.Set; import java.util.regex.Matcher; import java.util.regex.Pattern; @@ -42,20 +47,34 @@ import javax.xml.transform.TransformerException; import javax.xml.transform.TransformerFactory; import javax.xml.transform.dom.DOMSource; import javax.xml.transform.stream.StreamResult; -import org.opendaylight.controller.md.sal.common.api.TransactionStatus; import org.opendaylight.controller.sal.restconf.impl.BrokerFacade; import org.opendaylight.controller.sal.restconf.impl.CompositeNodeWrapper; import org.opendaylight.controller.sal.restconf.impl.ControllerContext; import org.opendaylight.controller.sal.restconf.impl.NodeWrapper; +import org.opendaylight.controller.sal.restconf.impl.RestconfDocumentedException; +import org.opendaylight.controller.sal.restconf.impl.RestconfError; +import org.opendaylight.controller.sal.restconf.impl.RestconfError.ErrorTag; +import org.opendaylight.controller.sal.restconf.impl.RestconfError.ErrorType; import org.opendaylight.controller.sal.restconf.impl.RestconfImpl; import org.opendaylight.controller.sal.restconf.impl.StructuredData; import org.opendaylight.yangtools.yang.common.QName; import org.opendaylight.yangtools.yang.data.api.CompositeNode; +import org.opendaylight.yangtools.yang.data.api.Node; import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier; +import org.opendaylight.yangtools.yang.data.api.schema.MapEntryNode; +import org.opendaylight.yangtools.yang.data.api.schema.NormalizedNode; +import org.opendaylight.yangtools.yang.data.composite.node.schema.cnsn.parser.CnSnToNormalizedNodeParserFactory; +import org.opendaylight.yangtools.yang.data.impl.ImmutableCompositeNode; +import org.opendaylight.yangtools.yang.data.impl.schema.builder.api.DataContainerNodeAttrBuilder; +import org.opendaylight.yangtools.yang.data.impl.schema.builder.impl.ImmutableLeafNodeBuilder; +import org.opendaylight.yangtools.yang.data.impl.schema.builder.impl.ImmutableMapEntryNodeBuilder; +import org.opendaylight.yangtools.yang.data.impl.util.CompositeNodeBuilder; +import org.opendaylight.yangtools.yang.model.api.ContainerSchemaNode; import org.opendaylight.yangtools.yang.model.api.DataSchemaNode; +import org.opendaylight.yangtools.yang.model.api.ListSchemaNode; import org.opendaylight.yangtools.yang.model.api.Module; import org.opendaylight.yangtools.yang.model.api.SchemaContext; -import org.opendaylight.yangtools.yang.model.parser.api.YangModelParser; +import org.opendaylight.yangtools.yang.model.parser.api.YangContextParser; import org.opendaylight.yangtools.yang.parser.impl.YangParserImpl; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -66,7 +85,7 @@ public final class TestUtils { private static final Logger LOG = LoggerFactory.getLogger(TestUtils.class); - private final static YangModelParser parser = new YangParserImpl(); + private final static YangContextParser parser = new YangParserImpl(); private static Set loadModules(String resourceDirectory) throws FileNotFoundException { final File testDir = new File(resourceDirectory); @@ -151,12 +170,12 @@ public final class TestUtils { * {@code dataSchemaNode}. The method {@link RestconfImpl#createConfigurationData createConfigurationData} is used * because it contains calling of method {code normalizeNode} */ - public static void normalizeCompositeNode(CompositeNode compositeNode, Set modules, String schemaNodePath) { + public static void normalizeCompositeNode(Node node, Set modules, String schemaNodePath) { RestconfImpl restconf = RestconfImpl.getInstance(); ControllerContext.getInstance().setSchemas(TestUtils.loadSchemaContext(modules)); prepareMocksForRestconf(modules, restconf); - restconf.updateConfigurationData(schemaNodePath, compositeNode); + restconf.updateConfigurationData(schemaNodePath, node); } /** @@ -229,33 +248,30 @@ public final class TestUtils { controllerContext.setSchemas(TestUtils.loadSchemaContext(modules)); - when(mockedBrokerFacade.commitConfigurationDataPut(any(YangInstanceIdentifier.class), any(CompositeNode.class))) - .thenReturn( - new DummyFuture.Builder().rpcResult( - new DummyRpcResult.Builder().result(TransactionStatus.COMMITED) - .build()).build()); + when(mockedBrokerFacade.commitConfigurationDataPut(any(YangInstanceIdentifier.class), any(NormalizedNode.class))) + .thenReturn(mock(CheckedFuture.class)); restconf.setControllerContext(controllerContext); restconf.setBroker(mockedBrokerFacade); } - public static CompositeNode readInputToCnSn(String path, boolean dummyNamespaces, - MessageBodyReader reader) throws WebApplicationException { + public static Node readInputToCnSn(String path, boolean dummyNamespaces, + MessageBodyReader> reader) throws WebApplicationException { InputStream inputStream = TestUtils.class.getResourceAsStream(path); try { - CompositeNode compositeNode = reader.readFrom(null, null, null, null, null, inputStream); - assertTrue(compositeNode instanceof CompositeNodeWrapper); + final Node node = reader.readFrom(null, null, null, null, null, inputStream); + assertTrue(node instanceof CompositeNodeWrapper); if (dummyNamespaces) { try { - TestUtils.addDummyNamespaceToAllNodes((CompositeNodeWrapper) compositeNode); - return ((CompositeNodeWrapper) compositeNode).unwrap(); + TestUtils.addDummyNamespaceToAllNodes((CompositeNodeWrapper) node); + return ((CompositeNodeWrapper) node).unwrap(); } catch (URISyntaxException e) { LOG.error(e.getMessage()); assertTrue(e.getMessage(), false); } } - return compositeNode; + return node; } catch (IOException e) { LOG.error(e.getMessage()); assertTrue(e.getMessage(), false); @@ -263,21 +279,33 @@ public final class TestUtils { return null; } - public static CompositeNode readInputToCnSn(String path, MessageBodyReader reader) { +// public static Node readInputToCnSnNew(String path, MessageBodyReader> reader) throws WebApplicationException { +// InputStream inputStream = TestUtils.class.getResourceAsStream(path); +// try { +// return reader.readFrom(null, null, null, null, null, inputStream); +// } catch (IOException e) { +// LOG.error(e.getMessage()); +// assertTrue(e.getMessage(), false); +// } +// return null; +// } + + public static Node readInputToCnSn(String path, MessageBodyReader> reader) { return readInputToCnSn(path, false, reader); } - public static String writeCompNodeWithSchemaContextToOutput(CompositeNode compositeNode, Set modules, + public static String writeCompNodeWithSchemaContextToOutput(Node node, Set modules, DataSchemaNode dataSchemaNode, MessageBodyWriter messageBodyWriter) throws IOException, WebApplicationException { assertNotNull(dataSchemaNode); - assertNotNull("Composite node can't be null", compositeNode); + assertNotNull("Composite node can't be null", node); ByteArrayOutputStream byteArrayOS = new ByteArrayOutputStream(); ControllerContext.getInstance().setSchemas(loadSchemaContext(modules)); - messageBodyWriter.writeTo(new StructuredData(compositeNode, dataSchemaNode, null), null, null, null, null, + assertTrue(node instanceof CompositeNode); + messageBodyWriter.writeTo(new StructuredData((CompositeNode)node, dataSchemaNode, null), null, null, null, null, null, byteArrayOS); return byteArrayOS.toString(); @@ -312,4 +340,92 @@ public final class TestUtils { Matcher matcher = pattern.matcher(jsonOutput); return matcher.matches(); } + + public static NormalizedNode compositeNodeToDatastoreNormalizedNode(final CompositeNode compositeNode, + final DataSchemaNode schema) { + List> lst = new ArrayList>(); + lst.add(compositeNode); + if (schema instanceof ContainerSchemaNode) { + return CnSnToNormalizedNodeParserFactory.getInstance().getContainerNodeParser() + .parse(lst, (ContainerSchemaNode) schema); + } else if (schema instanceof ListSchemaNode) { + return CnSnToNormalizedNodeParserFactory.getInstance().getMapNodeParser() + .parse(lst, (ListSchemaNode) schema); + } + + LOG.error("Top level isn't of type container, list, leaf schema node but " + schema.getClass().getSimpleName()); + + throw new RestconfDocumentedException(new RestconfError(ErrorType.APPLICATION, ErrorTag.INVALID_VALUE, + "It wasn't possible to translate specified data to datastore readable form.")); + } + + public static YangInstanceIdentifier.NodeIdentifier getNodeIdentifier(String localName, String namespace, + String revision) throws ParseException { + return new YangInstanceIdentifier.NodeIdentifier(QName.create(namespace, revision, localName)); + } + + public static YangInstanceIdentifier.NodeIdentifierWithPredicates getNodeIdentifierPredicate(String localName, + String namespace, String revision, Map keys) throws ParseException { + Map predicate = new HashMap<>(); + for (String key : keys.keySet()) { + predicate.put(QName.create(namespace, revision, key), keys.get(key)); + } + + return new YangInstanceIdentifier.NodeIdentifierWithPredicates( + + QName.create(namespace, revision, localName), predicate); + } + + public static YangInstanceIdentifier.NodeIdentifierWithPredicates getNodeIdentifierPredicate(String localName, + String namespace, String revision, String... keysAndValues) throws ParseException { + java.util.Date date = new SimpleDateFormat("yyyy-MM-dd").parse(revision); + if (keysAndValues.length % 2 != 0) { + new IllegalArgumentException("number of keys argument have to be divisible by 2 (map)"); + } + Map predicate = new HashMap<>(); + + int i = 0; + while (i < keysAndValues.length) { + predicate.put(QName.create(namespace, revision, keysAndValues[i++]), keysAndValues[i++]); + } + + return new YangInstanceIdentifier.NodeIdentifierWithPredicates(QName.create(namespace, revision, localName), + predicate); + } + + public static CompositeNode prepareCompositeNodeWithIetfInterfacesInterfacesData() { + CompositeNodeBuilder interfaceBuilder = ImmutableCompositeNode.builder(); + interfaceBuilder.addLeaf(buildQName("name", "dummy", "2014-07-29"), "eth0"); + interfaceBuilder.addLeaf(buildQName("type", "dummy", "2014-07-29"), "ethernetCsmacd"); + interfaceBuilder.addLeaf(buildQName("enabled", "dummy", "2014-07-29"), "false"); + interfaceBuilder.addLeaf(buildQName("description", "dummy", "2014-07-29"), "some interface"); + return interfaceBuilder.toInstance(); + } + + static NormalizedNode prepareNormalizedNodeWithIetfInterfacesInterfacesData() throws ParseException { + String ietfInterfacesDate = "2013-07-04"; + String namespace = "urn:ietf:params:xml:ns:yang:ietf-interfaces"; + DataContainerNodeAttrBuilder mapEntryNode = ImmutableMapEntryNodeBuilder.create(); + + Map predicates = new HashMap<>(); + predicates.put("name", "eth0"); + + mapEntryNode.withNodeIdentifier(getNodeIdentifierPredicate("interface", namespace, ietfInterfacesDate, + predicates)); + mapEntryNode + .withChild(new ImmutableLeafNodeBuilder() + .withNodeIdentifier(getNodeIdentifier("name", namespace, ietfInterfacesDate)).withValue("eth0") + .build()); + mapEntryNode.withChild(new ImmutableLeafNodeBuilder() + .withNodeIdentifier(getNodeIdentifier("type", namespace, ietfInterfacesDate)) + .withValue("ethernetCsmacd").build()); + mapEntryNode.withChild(new ImmutableLeafNodeBuilder() + .withNodeIdentifier(getNodeIdentifier("enabled", namespace, ietfInterfacesDate)) + .withValue(Boolean.FALSE).build()); + mapEntryNode.withChild(new ImmutableLeafNodeBuilder() + .withNodeIdentifier(getNodeIdentifier("description", namespace, ietfInterfacesDate)) + .withValue("some interface").build()); + + return mapEntryNode.build(); + } } diff --git a/opendaylight/md-sal/sal-rest-connector/src/test/java/org/opendaylight/controller/sal/restconf/impl/test/URIParametersParsing.java b/opendaylight/md-sal/sal-rest-connector/src/test/java/org/opendaylight/controller/sal/restconf/impl/test/URIParametersParsing.java new file mode 100644 index 0000000000..3c954f840a --- /dev/null +++ b/opendaylight/md-sal/sal-rest-connector/src/test/java/org/opendaylight/controller/sal/restconf/impl/test/URIParametersParsing.java @@ -0,0 +1,101 @@ +/* + * 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.restconf.impl.test; + +import static org.junit.Assert.assertNotNull; +import static org.mockito.Matchers.eq; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.when; + +import java.io.FileNotFoundException; +import javax.ws.rs.core.MultivaluedMap; +import javax.ws.rs.core.UriBuilder; +import javax.ws.rs.core.UriInfo; +import org.junit.Before; +import org.junit.Test; +import org.opendaylight.controller.md.sal.common.api.data.AsyncDataBroker.DataChangeScope; +import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType; +import org.opendaylight.controller.sal.restconf.impl.BrokerFacade; +import org.opendaylight.controller.sal.restconf.impl.ControllerContext; +import org.opendaylight.controller.sal.restconf.impl.RestconfImpl; +import org.opendaylight.controller.sal.streams.listeners.ListenerAdapter; +import org.opendaylight.controller.sal.streams.listeners.Notificator; +import org.opendaylight.yangtools.yang.common.QName; +import org.opendaylight.yangtools.yang.data.api.CompositeNode; +import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier; +import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier.InstanceIdentifierBuilder; +import org.opendaylight.yangtools.yang.data.impl.ImmutableCompositeNode; +import org.opendaylight.yangtools.yang.data.impl.util.CompositeNodeBuilder; + +public class URIParametersParsing { + + private RestconfImpl restconf; + private BrokerFacade mockedBrokerFacade; + + @Before + public void init() throws FileNotFoundException { + restconf = RestconfImpl.getInstance(); + mockedBrokerFacade = mock(BrokerFacade.class); + ControllerContext controllerContext = ControllerContext.getInstance(); + controllerContext.setSchemas(TestUtils.loadSchemaContext("/datastore-and-scope-specification")); + restconf.setControllerContext(controllerContext); + restconf.setBroker(mockedBrokerFacade); + } + + @Test + public void resolveURIParametersConcreteValues() { + resolveURIParameters("OPERATIONAL", "SUBTREE", LogicalDatastoreType.OPERATIONAL, DataChangeScope.SUBTREE); + } + + @Test + public void resolveURIParametersDefaultValues() { + resolveURIParameters(null, null, LogicalDatastoreType.CONFIGURATION, DataChangeScope.BASE); + } + + private void resolveURIParameters(final String datastore, final String scope, + final LogicalDatastoreType datastoreExpected, final DataChangeScope scopeExpected) { + + InstanceIdentifierBuilder iiBuilder = YangInstanceIdentifier.builder(); + iiBuilder.node(QName.create("dummyStreamName")); + + final String datastoreValue = datastore == null ? "CONFIGURATION" : datastore; + final String scopeValue = scope == null ? "BASE" : scope + ""; + Notificator.createListener(iiBuilder.build(), "dummyStreamName/datastore=" + datastoreValue + "/scope=" + + scopeValue); + + UriInfo mockedUriInfo = mock(UriInfo.class); + MultivaluedMap mockedMultivaluedMap = mock(MultivaluedMap.class); + when(mockedMultivaluedMap.getFirst(eq("datastore"))).thenReturn(datastoreValue); + when(mockedMultivaluedMap.getFirst(eq("scope"))).thenReturn(scopeValue); + + when(mockedUriInfo.getQueryParameters(eq(false))).thenReturn(mockedMultivaluedMap); + + UriBuilder uriBuilder = UriBuilder.fromUri("www.whatever.com"); + when(mockedUriInfo.getAbsolutePathBuilder()).thenReturn(uriBuilder); + + restconf.invokeRpc("sal-remote:create-data-change-event-subscription", prepareRpcNode(datastore, scope), + mockedUriInfo); + + ListenerAdapter listener = Notificator.getListenerFor("opendaylight-inventory:nodes/datastore=" + + datastoreValue + "/scope=" + scopeValue); + assertNotNull(listener); + + } + + private CompositeNode prepareRpcNode(final String datastore, final String scope) { + CompositeNodeBuilder inputBuilder = ImmutableCompositeNode.builder(); + inputBuilder.setQName(QName.create("urn:opendaylight:params:xml:ns:yang:controller:md:sal:remote", + "2014-01-14", "input")); + inputBuilder.addLeaf( + QName.create("urn:opendaylight:params:xml:ns:yang:controller:md:sal:remote", "2014-01-14", "path"), + YangInstanceIdentifier.builder().node(QName.create("urn:opendaylight:inventory", "2013-08-19", "nodes")).build()); + inputBuilder.addLeaf(QName.create("urn:sal:restconf:event:subscription", "2014-7-8", "datastore"), datastore); + inputBuilder.addLeaf(QName.create("urn:sal:restconf:event:subscription", "2014-7-8", "scope"), scope); + return inputBuilder.toInstance(); + } +} diff --git a/opendaylight/md-sal/sal-rest-connector/src/test/java/org/opendaylight/controller/sal/restconf/impl/test/URITest.java b/opendaylight/md-sal/sal-rest-connector/src/test/java/org/opendaylight/controller/sal/restconf/impl/test/URITest.java index 655aba267f..ed871bb527 100644 --- a/opendaylight/md-sal/sal-rest-connector/src/test/java/org/opendaylight/controller/sal/restconf/impl/test/URITest.java +++ b/opendaylight/md-sal/sal-rest-connector/src/test/java/org/opendaylight/controller/sal/restconf/impl/test/URITest.java @@ -14,6 +14,7 @@ import static org.mockito.Matchers.any; import static org.mockito.Mockito.mock; import static org.mockito.Mockito.when; +import com.google.common.base.Optional; import com.google.common.collect.Iterables; import java.io.FileNotFoundException; import java.util.Set; @@ -21,8 +22,8 @@ import org.junit.BeforeClass; import org.junit.Rule; import org.junit.Test; import org.junit.rules.ExpectedException; -import org.opendaylight.controller.sal.core.api.mount.MountInstance; -import org.opendaylight.controller.sal.core.api.mount.MountService; +import org.opendaylight.controller.md.sal.dom.api.DOMMountPoint; +import org.opendaylight.controller.md.sal.dom.api.DOMMountPointService; import org.opendaylight.controller.sal.restconf.impl.BrokerFacade; import org.opendaylight.controller.sal.restconf.impl.ControllerContext; import org.opendaylight.controller.sal.restconf.impl.InstanceIdWithSchemaNode; @@ -153,7 +154,7 @@ public class URITest { } public void initMountService(final boolean withSchema) { - MountService mountService = mock(MountService.class); + DOMMountPointService mountService = mock(DOMMountPointService.class); controllerContext.setMountService(mountService); BrokerFacade brokerFacade = mock(BrokerFacade.class); RestconfImpl restconfImpl = RestconfImpl.getInstance(); @@ -162,12 +163,12 @@ public class URITest { Set modules2 = TestUtils.loadModulesFrom("/test-config-data/yang2"); SchemaContext schemaContext2 = TestUtils.loadSchemaContext(modules2); - MountInstance mountInstance = mock(MountInstance.class); + DOMMountPoint mountInstance = mock(DOMMountPoint.class); if (withSchema) { when(mountInstance.getSchemaContext()).thenReturn(schemaContext2); } else { when(mountInstance.getSchemaContext()).thenReturn(null); } - when(mountService.getMountPoint(any(YangInstanceIdentifier.class))).thenReturn(mountInstance); + when(mountService.getMountPoint(any(YangInstanceIdentifier.class))).thenReturn(Optional.of(mountInstance)); } } diff --git a/opendaylight/md-sal/sal-rest-connector/src/test/java/org/opendaylight/controller/sal/restconf/impl/test/XmlAndJsonToCnSnInstanceIdentifierTest.java b/opendaylight/md-sal/sal-rest-connector/src/test/java/org/opendaylight/controller/sal/restconf/impl/test/XmlAndJsonToCnSnInstanceIdentifierTest.java index f4e869f99f..23e868c8b2 100644 --- a/opendaylight/md-sal/sal-rest-connector/src/test/java/org/opendaylight/controller/sal/restconf/impl/test/XmlAndJsonToCnSnInstanceIdentifierTest.java +++ b/opendaylight/md-sal/sal-rest-connector/src/test/java/org/opendaylight/controller/sal/restconf/impl/test/XmlAndJsonToCnSnInstanceIdentifierTest.java @@ -26,6 +26,7 @@ import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier; import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier.NodeIdentifierWithPredicates; import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier.NodeWithValue; import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier.PathArgument; +import org.opendaylight.yangtools.yang.data.api.Node; import org.opendaylight.yangtools.yang.data.api.SimpleNode; public class XmlAndJsonToCnSnInstanceIdentifierTest extends YangAndXmlAndDataSchemaLoader { @@ -37,32 +38,44 @@ public class XmlAndJsonToCnSnInstanceIdentifierTest extends YangAndXmlAndDataSch @Test public void loadXmlToCnSn() throws WebApplicationException, IOException, URISyntaxException { - CompositeNode cnSn = TestUtils.readInputToCnSn("/instanceidentifier/xml/xmldata.xml", + Node node = TestUtils.readInputToCnSn("/instanceidentifier/xml/xmldata.xml", XmlToCompositeNodeProvider.INSTANCE); + + assertTrue(node instanceof CompositeNode); + CompositeNode cnSn = (CompositeNode)node; TestUtils.normalizeCompositeNode(cnSn, modules, schemaNodePath); verifyListPredicate(cnSn); } @Test public void loadXmlLeafListToCnSn() throws WebApplicationException, IOException, URISyntaxException { - CompositeNode cnSn = TestUtils.readInputToCnSn("/instanceidentifier/xml/xmldata_leaf_list.xml", + Node node = TestUtils.readInputToCnSn("/instanceidentifier/xml/xmldata_leaf_list.xml", XmlToCompositeNodeProvider.INSTANCE); + + assertTrue(node instanceof CompositeNode); + CompositeNode cnSn = (CompositeNode)node; TestUtils.normalizeCompositeNode(cnSn, modules, schemaNodePath); verifyLeafListPredicate(cnSn); } @Test public void loadJsonToCnSn() throws WebApplicationException, IOException, URISyntaxException { - CompositeNode cnSn = TestUtils.readInputToCnSn("/instanceidentifier/json/jsondata.json", + Node node = TestUtils.readInputToCnSn("/instanceidentifier/json/jsondata.json", JsonToCompositeNodeProvider.INSTANCE); + + assertTrue(node instanceof CompositeNode); + CompositeNode cnSn = (CompositeNode)node; TestUtils.normalizeCompositeNode(cnSn, modules, schemaNodePath); verifyListPredicate(cnSn); } @Test public void loadJsonLeafListToCnSn() throws WebApplicationException, IOException, URISyntaxException { - CompositeNode cnSn = TestUtils.readInputToCnSn("/instanceidentifier/json/jsondata_leaf_list.json", + Node node = TestUtils.readInputToCnSn("/instanceidentifier/json/jsondata_leaf_list.json", JsonToCompositeNodeProvider.INSTANCE); + assertTrue(node instanceof CompositeNode); + CompositeNode cnSn = (CompositeNode)node; + TestUtils.normalizeCompositeNode(cnSn, modules, schemaNodePath); verifyLeafListPredicate(cnSn); } diff --git a/opendaylight/md-sal/sal-rest-connector/src/test/java/org/opendaylight/controller/sal/restconf/impl/test/XmlAndJsonToCnSnLeafRefTest.java b/opendaylight/md-sal/sal-rest-connector/src/test/java/org/opendaylight/controller/sal/restconf/impl/test/XmlAndJsonToCnSnLeafRefTest.java index 483d90da0d..1c8e53e69f 100644 --- a/opendaylight/md-sal/sal-rest-connector/src/test/java/org/opendaylight/controller/sal/restconf/impl/test/XmlAndJsonToCnSnLeafRefTest.java +++ b/opendaylight/md-sal/sal-rest-connector/src/test/java/org/opendaylight/controller/sal/restconf/impl/test/XmlAndJsonToCnSnLeafRefTest.java @@ -8,6 +8,7 @@ package org.opendaylight.controller.sal.restconf.impl.test; import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertTrue; import java.io.IOException; import java.net.URISyntaxException; @@ -29,15 +30,22 @@ public class XmlAndJsonToCnSnLeafRefTest extends YangAndXmlAndDataSchemaLoader { @Test public void loadXmlToCnSn() throws WebApplicationException, IOException, URISyntaxException { - CompositeNode cnSn = TestUtils.readInputToCnSn("/leafref/xml/xmldata.xml", XmlToCompositeNodeProvider.INSTANCE); + Node node = TestUtils.readInputToCnSn("/leafref/xml/xmldata.xml", XmlToCompositeNodeProvider.INSTANCE); + + assertTrue(node instanceof CompositeNode); + CompositeNode cnSn = (CompositeNode)node; + TestUtils.normalizeCompositeNode(cnSn, modules, schemaNodePath); verifyContPredicate(cnSn, "/ns:cont/ns:lf1", "/cont/lf1", "/ns:cont/ns:lf1", "../lf1"); } @Test public void loadJsonToCnSn() throws WebApplicationException, IOException, URISyntaxException { - CompositeNode cnSn = TestUtils.readInputToCnSn("/leafref/json/jsondata.json", + Node node = TestUtils.readInputToCnSn("/leafref/json/jsondata.json", JsonToCompositeNodeProvider.INSTANCE); + assertTrue(node instanceof CompositeNode); + CompositeNode cnSn = (CompositeNode)node; + TestUtils.normalizeCompositeNode(cnSn, modules, schemaNodePath); verifyContPredicate(cnSn, "/leafref-module:cont/leafref-module:lf1", "/leafref-module:cont/leafref-module:lf1", "/referenced-module:cont/referenced-module:lf1", "/leafref-module:cont/leafref-module:lf1"); diff --git a/opendaylight/md-sal/sal-rest-connector/src/test/java/org/opendaylight/controller/sal/restconf/impl/websockets/test/RestStream.java b/opendaylight/md-sal/sal-rest-connector/src/test/java/org/opendaylight/controller/sal/restconf/impl/websockets/test/RestStream.java index 70f0f050dc..121a3865bd 100644 --- a/opendaylight/md-sal/sal-rest-connector/src/test/java/org/opendaylight/controller/sal/restconf/impl/websockets/test/RestStream.java +++ b/opendaylight/md-sal/sal-rest-connector/src/test/java/org/opendaylight/controller/sal/restconf/impl/websockets/test/RestStream.java @@ -32,6 +32,9 @@ import org.opendaylight.controller.sal.restconf.impl.ControllerContext; import org.opendaylight.controller.sal.restconf.impl.RestconfImpl; import org.opendaylight.controller.sal.restconf.impl.test.TestUtils; import org.opendaylight.yangtools.yang.model.api.SchemaContext; +import org.w3c.dom.Document; +import org.w3c.dom.Element; +import org.w3c.dom.Node; public class RestStream extends JerseyTest { @@ -68,17 +71,20 @@ public class RestStream extends JerseyTest { public void testCallRpcCallGet() throws UnsupportedEncodingException, InterruptedException { String uri = "/operations/sal-remote:create-data-change-event-subscription"; Response responseWithStreamName = post(uri, MediaType.APPLICATION_XML, getRpcInput()); - String xmlResponse = responseWithStreamName.readEntity(String.class); + Document xmlResponse = responseWithStreamName.readEntity(Document.class); assertNotNull(xmlResponse); - assertTrue(xmlResponse - .contains("ietf-interfaces:interfaces/ietf-interfaces:interface/eth0")); + Element outputElement = xmlResponse.getDocumentElement(); + assertEquals("output",outputElement.getLocalName()); - uri = "/streams/stream/ietf-interfaces:interfaces/ietf-interfaces:interface/eth0"; + Node streamNameElement = outputElement.getFirstChild(); + assertEquals("stream-name",streamNameElement.getLocalName()); + assertEquals("ietf-interfaces:interfaces/ietf-interfaces:interface/eth0/datastore=CONFIGURATION/scope=BASE",streamNameElement.getTextContent()); + + uri = "/streams/stream/ietf-interfaces:interfaces/ietf-interfaces:interface/eth0/datastore=CONFIGURATION/scope=BASE"; Response responseWithRedirectionUri = get(uri, MediaType.APPLICATION_XML); final URI websocketServerUri = responseWithRedirectionUri.getLocation(); assertNotNull(websocketServerUri); - assertEquals(websocketServerUri.toString(), - "http://localhost:8181/ietf-interfaces:interfaces/ietf-interfaces:interface/eth0"); + assertTrue(websocketServerUri.toString().matches(".*http://localhost:[\\d]+/ietf-interfaces:interfaces/ietf-interfaces:interface/eth0.*")); } private Response post(String uri, String mediaType, String data) { diff --git a/opendaylight/md-sal/sal-rest-connector/src/test/java/org/opendaylight/controller/sal/restconf/impl/xml/to/cnsn/test/XmlAugmentedElementToCnSnTest.java b/opendaylight/md-sal/sal-rest-connector/src/test/java/org/opendaylight/controller/sal/restconf/impl/xml/to/cnsn/test/XmlAugmentedElementToCnSnTest.java index 5a5a621d93..e992e1214e 100644 --- a/opendaylight/md-sal/sal-rest-connector/src/test/java/org/opendaylight/controller/sal/restconf/impl/xml/to/cnsn/test/XmlAugmentedElementToCnSnTest.java +++ b/opendaylight/md-sal/sal-rest-connector/src/test/java/org/opendaylight/controller/sal/restconf/impl/xml/to/cnsn/test/XmlAugmentedElementToCnSnTest.java @@ -8,12 +8,14 @@ package org.opendaylight.controller.sal.restconf.impl.xml.to.cnsn.test; import static org.junit.Assert.assertNotNull; +import static org.junit.Assert.assertTrue; import java.util.Set; import org.junit.Test; import org.opendaylight.controller.sal.rest.impl.XmlToCompositeNodeProvider; import org.opendaylight.controller.sal.restconf.impl.test.TestUtils; import org.opendaylight.yangtools.yang.data.api.CompositeNode; +import org.opendaylight.yangtools.yang.data.api.Node; import org.opendaylight.yangtools.yang.model.api.Module; public class XmlAugmentedElementToCnSnTest { @@ -25,12 +27,15 @@ public class XmlAugmentedElementToCnSnTest { } private void loadAndNormalizeData(String xmlPath, String yangPath, String topLevelElementName, String moduleName) { - CompositeNode compNode = TestUtils.readInputToCnSn(xmlPath, false, XmlToCompositeNodeProvider.INSTANCE); - assertNotNull(compNode); + Node node = TestUtils.readInputToCnSn(xmlPath, false, + XmlToCompositeNodeProvider.INSTANCE); + assertTrue(node instanceof CompositeNode); + CompositeNode cnSn = (CompositeNode)node; + Set modules = TestUtils.loadModulesFrom(yangPath); assertNotNull(modules); - TestUtils.normalizeCompositeNode(compNode, modules, topLevelElementName + ":" + moduleName); + TestUtils.normalizeCompositeNode(cnSn, modules, topLevelElementName + ":" + moduleName); } } diff --git a/opendaylight/md-sal/sal-rest-connector/src/test/java/org/opendaylight/controller/sal/restconf/impl/xml/to/cnsn/test/XmlLeafrefToCnSnTest.java b/opendaylight/md-sal/sal-rest-connector/src/test/java/org/opendaylight/controller/sal/restconf/impl/xml/to/cnsn/test/XmlLeafrefToCnSnTest.java index 6c11bc1861..1c62b7fbdb 100644 --- a/opendaylight/md-sal/sal-rest-connector/src/test/java/org/opendaylight/controller/sal/restconf/impl/xml/to/cnsn/test/XmlLeafrefToCnSnTest.java +++ b/opendaylight/md-sal/sal-rest-connector/src/test/java/org/opendaylight/controller/sal/restconf/impl/xml/to/cnsn/test/XmlLeafrefToCnSnTest.java @@ -33,8 +33,11 @@ public class XmlLeafrefToCnSnTest { */ @Test public void testXmlDataContainer() { - CompositeNode compNode = TestUtils.readInputToCnSn("/xml-to-cnsn/data-container.xml", false, + Node node = TestUtils.readInputToCnSn("/xml-to-cnsn/data-container.xml", false, XmlToCompositeNodeProvider.INSTANCE); + assertTrue(node instanceof CompositeNode); + CompositeNode compNode = (CompositeNode)node; + assertNotNull(compNode); Set modules = TestUtils.loadModulesFrom("/xml-to-cnsn/data-container-yang"); @@ -76,9 +79,11 @@ public class XmlLeafrefToCnSnTest { @Test public void testXmlDataList() { - CompositeNode compNode = TestUtils.readInputToCnSn("/xml-to-cnsn/data-list.xml", false, + Node node = TestUtils.readInputToCnSn("/xml-to-cnsn/data-list.xml", false, XmlToCompositeNodeProvider.INSTANCE); - assertNotNull(compNode); + assertTrue(node instanceof CompositeNode); + CompositeNode compNode = (CompositeNode)node; + Set modules = TestUtils.loadModulesFrom("/xml-to-cnsn/data-list-yang"); assertNotNull(modules); @@ -93,22 +98,22 @@ public class XmlLeafrefToCnSnTest { CompositeNode lst1_1 = null; CompositeNode lst1_2 = null; int loopCount = 0; - for (Node node : compNode.getValue()) { - if (node.getNodeType().getLocalName().equals("lf1")) { - assertEquals(nameSpaceList, node.getNodeType().getNamespace().toString()); - assertTrue(node instanceof SimpleNode); - assertEquals("lf1", node.getValue()); + for (Node nd : compNode.getValue()) { + if (nd.getNodeType().getLocalName().equals("lf1")) { + assertEquals(nameSpaceList, nd.getNodeType().getNamespace().toString()); + assertTrue(nd instanceof SimpleNode); + assertEquals("lf1", nd.getValue()); } else { - assertTrue(node instanceof CompositeNode); + assertTrue(nd instanceof CompositeNode); switch (loopCount++) { case 0: - lst1_1 = (CompositeNode) node; + lst1_1 = (CompositeNode) nd; break; case 1: - lst1_2 = (CompositeNode) node; + lst1_2 = (CompositeNode) nd; break; } - assertEquals(nameSpaceCont, node.getNodeType().getNamespace().toString()); + assertEquals(nameSpaceCont, nd.getNodeType().getNamespace().toString()); } } // lst1_1 @@ -118,15 +123,15 @@ public class XmlLeafrefToCnSnTest { // lst1_2 SimpleNode lflst11 = null; CompositeNode cont11 = null; - for (Node node : lst1_2.getValue()) { - String nodeName = node.getNodeType().getLocalName(); + for (Node nd : lst1_2.getValue()) { + String nodeName = nd.getNodeType().getLocalName(); if (nodeName.equals("lflst11")) { - assertTrue(node instanceof SimpleNode); - lflst11 = (SimpleNode) node; + assertTrue(nd instanceof SimpleNode); + lflst11 = (SimpleNode) nd; } else if (nodeName.equals("cont11")) { - assertTrue(node instanceof CompositeNode); - cont11 = (CompositeNode) node; + assertTrue(nd instanceof CompositeNode); + cont11 = (CompositeNode) nd; } assertEquals(nameSpaceCont, compNode.getNodeType().getNamespace().toString()); } @@ -144,32 +149,35 @@ public class XmlLeafrefToCnSnTest { @Test public void testXmlEmptyData() { - CompositeNode compNode = TestUtils.readInputToCnSn("/xml-to-cnsn/empty-data.xml", true, + Node node = TestUtils.readInputToCnSn("/xml-to-cnsn/empty-data.xml", true, XmlToCompositeNodeProvider.INSTANCE); + assertTrue(node instanceof CompositeNode); + CompositeNode compNode = (CompositeNode)node; + assertEquals("cont", compNode.getNodeType().getLocalName()); SimpleNode lf1 = null; SimpleNode lflst1_1 = null; SimpleNode lflst1_2 = null; CompositeNode lst1 = null; int lflst1Count = 0; - for (Node node : compNode.getValue()) { - if (node.getNodeType().getLocalName().equals("lf1")) { - assertTrue(node instanceof SimpleNode); - lf1 = (SimpleNode) node; - } else if (node.getNodeType().getLocalName().equals("lflst1")) { - assertTrue(node instanceof SimpleNode); + for (Node nd : compNode.getValue()) { + if (nd.getNodeType().getLocalName().equals("lf1")) { + assertTrue(nd instanceof SimpleNode); + lf1 = (SimpleNode) nd; + } else if (nd.getNodeType().getLocalName().equals("lflst1")) { + assertTrue(nd instanceof SimpleNode); switch (lflst1Count++) { case 0: - lflst1_1 = (SimpleNode) node; + lflst1_1 = (SimpleNode) nd; break; case 1: - lflst1_2 = (SimpleNode) node; + lflst1_2 = (SimpleNode) nd; break; } - } else if (node.getNodeType().getLocalName().equals("lst1")) { - assertTrue(node instanceof CompositeNode); - lst1 = (CompositeNode) node; + } else if (nd.getNodeType().getLocalName().equals("lst1")) { + assertTrue(nd instanceof CompositeNode); + lst1 = (CompositeNode) nd; } } @@ -317,8 +325,10 @@ public class XmlLeafrefToCnSnTest { private void testIdentityrefToCnSn(final String xmlPath, final String yangPath, final String moduleName, final String schemaName, final int moduleCount, final String resultLocalName, final String resultNamespace) { - CompositeNode compositeNode = TestUtils.readInputToCnSn(xmlPath, false, XmlToCompositeNodeProvider.INSTANCE); - assertNotNull(compositeNode); + Node node = TestUtils.readInputToCnSn(xmlPath, false, XmlToCompositeNodeProvider.INSTANCE); + assertTrue(node instanceof CompositeNode); + CompositeNode compositeNode = (CompositeNode)node; + Set modules = TestUtils.loadModulesFrom(yangPath); assertEquals(moduleCount, modules.size()); diff --git a/opendaylight/md-sal/sal-rest-connector/src/test/java/org/opendaylight/controller/sal/restconf/impl/xml/to/cnsn/test/XmlToCnSnTest.java b/opendaylight/md-sal/sal-rest-connector/src/test/java/org/opendaylight/controller/sal/restconf/impl/xml/to/cnsn/test/XmlToCnSnTest.java index e2621d635b..d0af29e913 100644 --- a/opendaylight/md-sal/sal-rest-connector/src/test/java/org/opendaylight/controller/sal/restconf/impl/xml/to/cnsn/test/XmlToCnSnTest.java +++ b/opendaylight/md-sal/sal-rest-connector/src/test/java/org/opendaylight/controller/sal/restconf/impl/xml/to/cnsn/test/XmlToCnSnTest.java @@ -32,9 +32,12 @@ public class XmlToCnSnTest extends YangAndXmlAndDataSchemaLoader { @Test public void testXmlLeafrefToCnSn() { - CompositeNode compositeNode = TestUtils.readInputToCnSn("/xml-to-cnsn/leafref/xml/data.xml", false, + Node node = TestUtils.readInputToCnSn("/xml-to-cnsn/leafref/xml/data.xml", false, XmlToCompositeNodeProvider.INSTANCE); - assertNotNull(compositeNode); + assertTrue(node instanceof CompositeNode); + CompositeNode compositeNode = (CompositeNode)node; + + assertNotNull(dataSchemaNode); TestUtils.normalizeCompositeNode(compositeNode, modules, schemaNodePath); @@ -58,10 +61,10 @@ public class XmlToCnSnTest extends YangAndXmlAndDataSchemaLoader { @Test public void testXmlBlankInput() throws Exception { InputStream inputStream = new ByteArrayInputStream("".getBytes()); - CompositeNode compositeNode = XmlToCompositeNodeProvider.INSTANCE.readFrom(null, null, null, null, null, - inputStream); + Node node = + XmlToCompositeNodeProvider.INSTANCE.readFrom(null, null, null, null, null, inputStream); - assertNull(compositeNode); + assertNull( node ); } @Test @@ -72,10 +75,10 @@ public class XmlToCnSnTest extends YangAndXmlAndDataSchemaLoader { return false; } }; - CompositeNode compositeNode = XmlToCompositeNodeProvider.INSTANCE.readFrom(null, null, null, null, null, - inputStream); + Node node = + XmlToCompositeNodeProvider.INSTANCE.readFrom(null, null, null, null, null, inputStream); - assertNull(compositeNode); + assertNull( node ); } } diff --git a/opendaylight/md-sal/sal-rest-connector/src/test/resources/datastore-and-scope-specification/opendaylight-inventory.yang b/opendaylight/md-sal/sal-rest-connector/src/test/resources/datastore-and-scope-specification/opendaylight-inventory.yang new file mode 100644 index 0000000000..e4247bee1e --- /dev/null +++ b/opendaylight/md-sal/sal-rest-connector/src/test/resources/datastore-and-scope-specification/opendaylight-inventory.yang @@ -0,0 +1,19 @@ +module opendaylight-inventory { + namespace "urn:opendaylight:inventory"; + prefix inv; + + revision "2013-08-19" { + description "Initial revision of Inventory model"; + } + + + container nodes { + list node { + key "id"; + leaf id { + type string; + } + } + } + +} diff --git a/opendaylight/md-sal/sal-rest-connector/src/test/resources/datastore-and-scope-specification/sal-remote-augment.yang b/opendaylight/md-sal/sal-rest-connector/src/test/resources/datastore-and-scope-specification/sal-remote-augment.yang new file mode 100644 index 0000000000..83934568cc --- /dev/null +++ b/opendaylight/md-sal/sal-rest-connector/src/test/resources/datastore-and-scope-specification/sal-remote-augment.yang @@ -0,0 +1,31 @@ +module sal-remote-augment { + + yang-version 1; + namespace "urn:sal:restconf:event:subscription"; + prefix "salrmt-aug-ev-subscr"; + + import sal-remote {prefix salrmt; revision-date "2014-01-14";} + + description + "Added input parameters to rpc create-data-change-event-subscription"; + + revision "2014-7-8" { + } + + augment "/salrmt:create-data-change-event-subscription/salrmt:input" { + leaf datastore { + type enumeration { + enum OPERATIONAL; + enum CONFIGURATION; + } + } + leaf scope { + type enumeration { + enum BASE; + enum ONE; + enum SUBTREE; + } + } + } + +} \ No newline at end of file diff --git a/opendaylight/md-sal/sal-rest-connector/src/test/resources/datastore-and-scope-specification/sal-remote@2014-01-14.yang b/opendaylight/md-sal/sal-rest-connector/src/test/resources/datastore-and-scope-specification/sal-remote@2014-01-14.yang new file mode 100644 index 0000000000..d12e252711 --- /dev/null +++ b/opendaylight/md-sal/sal-rest-connector/src/test/resources/datastore-and-scope-specification/sal-remote@2014-01-14.yang @@ -0,0 +1,98 @@ +module sal-remote { + + yang-version 1; + namespace "urn:opendaylight:params:xml:ns:yang:controller:md:sal:remote"; + prefix "sal-remote"; + + + organization "Cisco Systems, Inc."; + contact "Martin Bobak "; + + description + "This module contains the definition of methods related to + sal remote model. + + Copyright (c)2013 Cisco Systems, Inc. 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"; + + revision "2014-01-14" { + description + "Initial revision"; + } + + + typedef q-name { + type string; + reference + "http://www.w3.org/TR/2004/REC-xmlschema-2-20041028/#QName"; + } + + rpc create-data-change-event-subscription { + input { + leaf path { + type instance-identifier; + description "Subtree path. "; + } + } + output { + leaf stream-name { + type string; + description "Notification stream name."; + } + } + } + + notification data-changed-notification { + description "Data change notification."; + list data-change-event { + key path; + leaf path { + type instance-identifier; + } + leaf store { + type enumeration { + enum config; + enum operation; + } + } + leaf operation { + type enumeration { + enum created; + enum updated; + enum deleted; + } + } + anyxml data{ + description "DataObject "; + } + } + } + + rpc create-notification-stream { + input { + leaf-list notifications { + type q-name; + description "Notification QNames"; + } + } + output { + leaf notification-stream-identifier { + type string; + description "Unique notification stream identifier, in which notifications will be propagated"; + } + } + } + + rpc begin-transaction{ + output{ + anyxml data-modification-transaction{ + description "DataModificationTransaction xml"; + } + } + } + +} \ No newline at end of file diff --git a/opendaylight/md-sal/sal-rest-docgen/src/test/resources/yang/toaster_short.yang b/opendaylight/md-sal/sal-rest-docgen/src/test/resources/yang/toaster_short.yang index 9995a8f127..a1d5ab0a12 100644 --- a/opendaylight/md-sal/sal-rest-docgen/src/test/resources/yang/toaster_short.yang +++ b/opendaylight/md-sal/sal-rest-docgen/src/test/resources/yang/toaster_short.yang @@ -3,7 +3,7 @@ yang-version 1; namespace - "http://netconfcentral.org/ns/toaster"; + "http://netconfcentral.org/ns/toaster2"; prefix toast; diff --git a/opendaylight/md-sal/sal-test-model/src/main/java/org/opendaylight/controller/md/sal/test/model/util/ListsBindingUtils.java b/opendaylight/md-sal/sal-test-model/src/main/java/org/opendaylight/controller/md/sal/test/model/util/ListsBindingUtils.java index a0c23aecb4..af7a32924b 100644 --- a/opendaylight/md-sal/sal-test-model/src/main/java/org/opendaylight/controller/md/sal/test/model/util/ListsBindingUtils.java +++ b/opendaylight/md-sal/sal-test-model/src/main/java/org/opendaylight/controller/md/sal/test/model/util/ListsBindingUtils.java @@ -7,10 +7,11 @@ */ package org.opendaylight.controller.md.sal.test.model.util; -import java.util.Arrays; - +import com.google.common.collect.ImmutableList; import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.controller.md.sal.test.augment.rev140709.TreeComplexUsesAugment; import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.controller.md.sal.test.augment.rev140709.TreeComplexUsesAugmentBuilder; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.controller.md.sal.test.augment.rev140709.TreeLeafOnlyUsesAugment; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.controller.md.sal.test.augment.rev140709.TreeLeafOnlyUsesAugmentBuilder; import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.controller.md.sal.test.augment.rev140709.complex.from.grouping.ListViaUses; import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.controller.md.sal.test.augment.rev140709.complex.from.grouping.ListViaUsesBuilder; import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.controller.md.sal.test.augment.rev140709.complex.from.grouping.ListViaUsesKey; @@ -25,7 +26,7 @@ import org.opendaylight.yangtools.yang.binding.Augmentation; import org.opendaylight.yangtools.yang.binding.DataObject; import org.opendaylight.yangtools.yang.binding.InstanceIdentifier; -import com.google.common.collect.ImmutableList; +import java.util.Arrays; public class ListsBindingUtils { @@ -79,4 +80,9 @@ public class ListsBindingUtils { return new TreeComplexUsesAugmentBuilder().setListViaUses(listViaUses.build()).build(); } + public static TreeLeafOnlyUsesAugment leafOnlyUsesAugment(String leafFromGroupingValue) { + + return new TreeLeafOnlyUsesAugmentBuilder().setLeafFromGrouping(leafFromGroupingValue).build(); + } + } diff --git a/opendaylight/md-sal/samples/pom.xml b/opendaylight/md-sal/samples/pom.xml index c601647a2e..ae7d323480 100644 --- a/opendaylight/md-sal/samples/pom.xml +++ b/opendaylight/md-sal/samples/pom.xml @@ -15,6 +15,7 @@ toaster toaster-consumer toaster-provider + toaster-config l2switch diff --git a/opendaylight/md-sal/samples/toaster-config/pom.xml b/opendaylight/md-sal/samples/toaster-config/pom.xml new file mode 100644 index 0000000000..b30c4ba12f --- /dev/null +++ b/opendaylight/md-sal/samples/toaster-config/pom.xml @@ -0,0 +1,46 @@ + + + + + 4.0.0 + + org.opendaylight.controller.samples + sal-samples + 1.1-SNAPSHOT + + toaster-config + Configuration files for toaster + jar + + + + org.codehaus.mojo + build-helper-maven-plugin + + + attach-artifacts + + attach-artifact + + package + + + + ${project.build.directory}/classes/initial/03-toaster-sample.xml + xml + config + + + + + + + + + diff --git a/opendaylight/distribution/opendaylight/src/main/resources/configuration/initial/03-toaster-sample.xml b/opendaylight/md-sal/samples/toaster-config/src/main/resources/initial/03-toaster-sample.xml similarity index 99% rename from opendaylight/distribution/opendaylight/src/main/resources/configuration/initial/03-toaster-sample.xml rename to opendaylight/md-sal/samples/toaster-config/src/main/resources/initial/03-toaster-sample.xml index 3958e18560..2e8c7d5ce6 100644 --- a/opendaylight/distribution/opendaylight/src/main/resources/configuration/initial/03-toaster-sample.xml +++ b/opendaylight/md-sal/samples/toaster-config/src/main/resources/initial/03-toaster-sample.xml @@ -26,7 +26,7 @@ binding:binding-async-data-broker binding-data-broker - + binding:binding-notification-service @@ -54,7 +54,7 @@ - + diff --git a/opendaylight/md-sal/topology-lldp-discovery/pom.xml b/opendaylight/md-sal/topology-lldp-discovery/pom.xml index 2c8571ca64..e01a0d5dcb 100644 --- a/opendaylight/md-sal/topology-lldp-discovery/pom.xml +++ b/opendaylight/md-sal/topology-lldp-discovery/pom.xml @@ -45,10 +45,6 @@ org.opendaylight.controller.model model-flow-base - - org.opendaylight.controller.model - model-flow-management - org.opendaylight.controller.model model-flow-service diff --git a/opendaylight/netconf/config-persister-impl/src/main/java/org/opendaylight/controller/netconf/persist/impl/ConfigPusher.java b/opendaylight/netconf/config-persister-impl/src/main/java/org/opendaylight/controller/netconf/persist/impl/ConfigPusher.java index eddad8b4c7..fff8d611b7 100644 --- a/opendaylight/netconf/config-persister-impl/src/main/java/org/opendaylight/controller/netconf/persist/impl/ConfigPusher.java +++ b/opendaylight/netconf/config-persister-impl/src/main/java/org/opendaylight/controller/netconf/persist/impl/ConfigPusher.java @@ -65,9 +65,11 @@ public class ConfigPusher { LinkedHashMap result = new LinkedHashMap<>(); // start pushing snapshots: for (ConfigSnapshotHolder configSnapshotHolder : configs) { - EditAndCommitResponse editAndCommitResponseWithRetries = pushConfigWithConflictingVersionRetries(configSnapshotHolder); - logger.debug("Config snapshot pushed successfully: {}, result: {}", configSnapshotHolder, result); - result.put(configSnapshotHolder, editAndCommitResponseWithRetries); + if(configSnapshotHolder != null) { + EditAndCommitResponse editAndCommitResponseWithRetries = pushConfigWithConflictingVersionRetries(configSnapshotHolder); + logger.debug("Config snapshot pushed successfully: {}, result: {}", configSnapshotHolder, result); + result.put(configSnapshotHolder, editAndCommitResponseWithRetries); + } } logger.debug("All configuration snapshots have been pushed successfully."); return result; diff --git a/opendaylight/netconf/netconf-cli/pom.xml b/opendaylight/netconf/netconf-cli/pom.xml index cd7a1aacf2..55a8715000 100644 --- a/opendaylight/netconf/netconf-cli/pom.xml +++ b/opendaylight/netconf/netconf-cli/pom.xml @@ -52,12 +52,10 @@ org.opendaylight.yangtools yang-data-impl - org.opendaylight.yangtools - yang-data-json - 0.6.2-SNAPSHOT + yang-data-composite-node org.opendaylight.yangtools diff --git a/opendaylight/netconf/netconf-cli/src/main/java/org/opendaylight/controller/netconf/cli/writer/impl/NormalizedNodeWriter.java b/opendaylight/netconf/netconf-cli/src/main/java/org/opendaylight/controller/netconf/cli/writer/impl/NormalizedNodeWriter.java index c101db9ef8..ef29a76fff 100644 --- a/opendaylight/netconf/netconf-cli/src/main/java/org/opendaylight/controller/netconf/cli/writer/impl/NormalizedNodeWriter.java +++ b/opendaylight/netconf/netconf-cli/src/main/java/org/opendaylight/controller/netconf/cli/writer/impl/NormalizedNodeWriter.java @@ -18,7 +18,7 @@ import org.opendaylight.yangtools.yang.data.api.Node; import org.opendaylight.yangtools.yang.data.api.schema.DataContainerChild; import org.opendaylight.yangtools.yang.data.impl.schema.transform.base.serializer.NodeSerializerDispatcher; import org.opendaylight.yangtools.yang.data.impl.schema.transform.dom.DomUtils; -import org.opendaylight.yangtools.yang.data.json.schema.cnsn.parser.CnSnToNormalizedNodeParserFactory; +import org.opendaylight.yangtools.yang.data.composite.node.schema.cnsn.parser.CnSnToNormalizedNodeParserFactory; import org.opendaylight.yangtools.yang.model.api.AugmentationSchema; import org.opendaylight.yangtools.yang.model.api.ChoiceNode; import org.opendaylight.yangtools.yang.model.api.ContainerSchemaNode; diff --git a/opendaylight/netconf/netconf-config/pom.xml b/opendaylight/netconf/netconf-config/pom.xml new file mode 100644 index 0000000000..db5d14d75a --- /dev/null +++ b/opendaylight/netconf/netconf-config/pom.xml @@ -0,0 +1,46 @@ + + + + + 4.0.0 + + org.opendaylight.controller + netconf-subsystem + 0.2.5-SNAPSHOT + + netconf-config + Configuration files for netconf + jar + + + + org.codehaus.mojo + build-helper-maven-plugin + + + attach-artifacts + + attach-artifact + + package + + + + ${project.build.directory}/classes/initial/01-netconf.xml + xml + config + + + + + + + + + diff --git a/opendaylight/distribution/opendaylight/src/main/resources/configuration/initial/01-netconf.xml b/opendaylight/netconf/netconf-config/src/main/resources/initial/01-netconf.xml similarity index 100% rename from opendaylight/distribution/opendaylight/src/main/resources/configuration/initial/01-netconf.xml rename to opendaylight/netconf/netconf-config/src/main/resources/initial/01-netconf.xml diff --git a/opendaylight/netconf/netconf-connector-config/pom.xml b/opendaylight/netconf/netconf-connector-config/pom.xml new file mode 100644 index 0000000000..d9cc5eab43 --- /dev/null +++ b/opendaylight/netconf/netconf-connector-config/pom.xml @@ -0,0 +1,46 @@ + + + + + 4.0.0 + + org.opendaylight.controller + netconf-subsystem + 0.2.5-SNAPSHOT + + netconf-connector-config + Configuration files for netconf-connector + jar + + + + org.codehaus.mojo + build-helper-maven-plugin + + + attach-artifacts + + attach-artifact + + package + + + + ${project.build.directory}/classes/initial/99-netconf-connector.xml + xml + config + + + + + + + + + diff --git a/opendaylight/distribution/opendaylight/src/main/resources/configuration/initial/99-netconf-connector.xml b/opendaylight/netconf/netconf-connector-config/src/main/resources/initial/99-netconf-connector.xml similarity index 100% rename from opendaylight/distribution/opendaylight/src/main/resources/configuration/initial/99-netconf-connector.xml rename to opendaylight/netconf/netconf-connector-config/src/main/resources/initial/99-netconf-connector.xml diff --git a/opendaylight/netconf/netconf-it/pom.xml b/opendaylight/netconf/netconf-it/pom.xml index 0e9589d2d2..272b686fc0 100644 --- a/opendaylight/netconf/netconf-it/pom.xml +++ b/opendaylight/netconf/netconf-it/pom.xml @@ -143,34 +143,6 @@ - - org.apache.maven.plugins - maven-surefire-plugin - - 1 - false - false - - - - default-test - - true - - - - integration-tests - - test - - integration-test - - false - -Dlogback.configurationFile=${maven.test.dest}/logback.xml - - - - org.ops4j.pax.exam maven-paxexam-plugin diff --git a/opendaylight/netconf/pom.xml b/opendaylight/netconf/pom.xml index 937949a17e..c72705d50e 100644 --- a/opendaylight/netconf/pom.xml +++ b/opendaylight/netconf/pom.xml @@ -20,6 +20,7 @@ netconf-api netconf-cli + netconf-config netconf-impl config-netconf-connector netconf-util @@ -32,6 +33,7 @@ netconf-monitoring ietf-netconf-monitoring ietf-netconf-monitoring-extension + netconf-connector-config diff --git a/opendaylight/networkconfiguration/neutron/implementation/src/main/java/org/opendaylight/controller/networkconfig/neutron/implementation/Activator.java b/opendaylight/networkconfiguration/neutron/implementation/src/main/java/org/opendaylight/controller/networkconfig/neutron/implementation/Activator.java index 1e2cd47c9c..45070ca8b0 100644 --- a/opendaylight/networkconfiguration/neutron/implementation/src/main/java/org/opendaylight/controller/networkconfig/neutron/implementation/Activator.java +++ b/opendaylight/networkconfiguration/neutron/implementation/src/main/java/org/opendaylight/controller/networkconfig/neutron/implementation/Activator.java @@ -8,23 +8,26 @@ package org.opendaylight.controller.networkconfig.neutron.implementation; -import java.util.Hashtable; -import java.util.Dictionary; - import org.apache.felix.dm.Component; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; import org.opendaylight.controller.clustering.services.IClusterContainerServices; import org.opendaylight.controller.configuration.IConfigurationContainerAware; import org.opendaylight.controller.configuration.IConfigurationContainerService; +import org.opendaylight.controller.networkconfig.neutron.INeutronFirewallCRUD; +import org.opendaylight.controller.networkconfig.neutron.INeutronFirewallPolicyCRUD; +import org.opendaylight.controller.networkconfig.neutron.INeutronFirewallRuleCRUD; import org.opendaylight.controller.networkconfig.neutron.INeutronFloatingIPCRUD; import org.opendaylight.controller.networkconfig.neutron.INeutronNetworkCRUD; import org.opendaylight.controller.networkconfig.neutron.INeutronPortCRUD; import org.opendaylight.controller.networkconfig.neutron.INeutronRouterCRUD; -import org.opendaylight.controller.networkconfig.neutron.INeutronSubnetCRUD; import org.opendaylight.controller.networkconfig.neutron.INeutronSecurityGroupCRUD; import org.opendaylight.controller.networkconfig.neutron.INeutronSecurityRuleCRUD; +import org.opendaylight.controller.networkconfig.neutron.INeutronSubnetCRUD; import org.opendaylight.controller.sal.core.ComponentActivatorAbstractBase; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import java.util.Dictionary; +import java.util.Hashtable; public class Activator extends ComponentActivatorAbstractBase { protected static final Logger logger = LoggerFactory @@ -68,7 +71,10 @@ public class Activator extends ComponentActivatorAbstractBase { NeutronSubnetInterface.class, NeutronNetworkInterface.class, NeutronSecurityGroupInterface.class, - NeutronSecurityRuleInterface.class}; + NeutronSecurityRuleInterface.class, + NeutronFirewallInterface.class, + NeutronFirewallPolicyInterface.class, + NeutronFirewallRuleInterface.class}; return res; } @@ -199,5 +205,53 @@ public class Activator extends ComponentActivatorAbstractBase { "setConfigurationContainerService", "unsetConfigurationContainerService").setRequired(true)); } + if (imp.equals(NeutronFirewallInterface.class)) { + // export the service + c.setInterface( + new String[] { INeutronFirewallCRUD.class.getName(), + IConfigurationContainerAware.class.getName()}, null); + Dictionary props = new Hashtable(); + props.put("salListenerName", "neutron"); + c.add(createContainerServiceDependency(containerName) + .setService(IClusterContainerServices.class) + .setCallbacks("setClusterContainerService", + "unsetClusterContainerService").setRequired(true)); + c.add(createContainerServiceDependency(containerName).setService( + IConfigurationContainerService.class).setCallbacks( + "setConfigurationContainerService", + "unsetConfigurationContainerService").setRequired(true)); + } + if (imp.equals(NeutronFirewallPolicyInterface.class)) { + // export the service + c.setInterface( + new String[] { INeutronFirewallPolicyCRUD.class.getName(), + IConfigurationContainerAware.class.getName()}, null); + Dictionary props = new Hashtable(); + props.put("salListenerName", "neutron"); + c.add(createContainerServiceDependency(containerName) + .setService(IClusterContainerServices.class) + .setCallbacks("setClusterContainerService", + "unsetClusterContainerService").setRequired(true)); + c.add(createContainerServiceDependency(containerName).setService( + IConfigurationContainerService.class).setCallbacks( + "setConfigurationContainerService", + "unsetConfigurationContainerService").setRequired(true)); + } + if (imp.equals(NeutronFirewallRuleInterface.class)) { + // export the service + c.setInterface( + new String[] { INeutronFirewallRuleCRUD.class.getName(), + IConfigurationContainerAware.class.getName()}, null); + Dictionary props = new Hashtable(); + props.put("salListenerName", "neutron"); + c.add(createContainerServiceDependency(containerName) + .setService(IClusterContainerServices.class) + .setCallbacks("setClusterContainerService", + "unsetClusterContainerService").setRequired(true)); + c.add(createContainerServiceDependency(containerName).setService( + IConfigurationContainerService.class).setCallbacks( + "setConfigurationContainerService", + "unsetConfigurationContainerService").setRequired(true)); + } } } diff --git a/opendaylight/networkconfiguration/neutron/implementation/src/main/java/org/opendaylight/controller/networkconfig/neutron/implementation/NeutronFirewallInterface.java b/opendaylight/networkconfiguration/neutron/implementation/src/main/java/org/opendaylight/controller/networkconfig/neutron/implementation/NeutronFirewallInterface.java new file mode 100644 index 0000000000..60476a1d34 --- /dev/null +++ b/opendaylight/networkconfiguration/neutron/implementation/src/main/java/org/opendaylight/controller/networkconfig/neutron/implementation/NeutronFirewallInterface.java @@ -0,0 +1,264 @@ +/* + * Copyright (C) 2014 Red Hat, Inc. + * + * 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.networkconfig.neutron.implementation; + +import org.apache.felix.dm.Component; +import org.opendaylight.controller.clustering.services.CacheConfigException; +import org.opendaylight.controller.clustering.services.CacheExistException; +import org.opendaylight.controller.clustering.services.IClusterContainerServices; +import org.opendaylight.controller.clustering.services.IClusterServices; +import org.opendaylight.controller.configuration.ConfigurationObject; +import org.opendaylight.controller.configuration.IConfigurationContainerAware; +import org.opendaylight.controller.configuration.IConfigurationContainerService; +import org.opendaylight.controller.networkconfig.neutron.INeutronFirewallCRUD; +import org.opendaylight.controller.networkconfig.neutron.NeutronFirewall; +import org.opendaylight.controller.sal.utils.IObjectReader; +import org.opendaylight.controller.sal.utils.Status; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import java.io.FileNotFoundException; +import java.io.IOException; +import java.io.ObjectInputStream; +import java.lang.reflect.Method; +import java.util.ArrayList; +import java.util.Dictionary; +import java.util.EnumSet; +import java.util.HashSet; +import java.util.List; +import java.util.Map.Entry; +import java.util.Set; +import java.util.concurrent.ConcurrentMap; + +public class NeutronFirewallInterface implements INeutronFirewallCRUD, IConfigurationContainerAware, IObjectReader { + private static final Logger logger = LoggerFactory.getLogger(NeutronFirewallInterface.class); + private static final String FILE_NAME = "neutron.firewall.conf"; + private String containerName = null; + + private IClusterContainerServices clusterContainerService = null; + private IConfigurationContainerService configurationService; + private ConcurrentMap firewallDB; + + // methods needed for creating caches + void setClusterContainerService(IClusterContainerServices s) { + logger.debug("Cluster Service set"); + clusterContainerService = s; + } + + void unsetClusterContainerService(IClusterContainerServices s) { + if (clusterContainerService == s) { + logger.debug("Cluster Service removed!"); + clusterContainerService = null; + } + } + + public void setConfigurationContainerService(IConfigurationContainerService service) { + logger.trace("Configuration service set: {}", service); + configurationService = service; + } + + public void unsetConfigurationContainerService(IConfigurationContainerService service) { + logger.trace("Configuration service removed: {}", service); + configurationService = null; + } + + private void allocateCache() { + if (this.clusterContainerService == null) { + logger.error("un-initialized clusterContainerService, can't create cache"); + return; + } + logger.debug("Creating Cache for Neutron Firewall"); + try { + // neutron caches + this.clusterContainerService.createCache("neutronFirewalls", + EnumSet.of(IClusterServices.cacheMode.NON_TRANSACTIONAL)); + } catch (CacheConfigException cce) { + logger.error("Cache couldn't be created for Neutron Firewall - check cache mode"); + } catch (CacheExistException cce) { + logger.error("Cache for Neutron Firewall already exists, destroy and recreate"); + } + logger.debug("Cache successfully created for Neutron Firewall"); + } + + @SuppressWarnings ({"unchecked"}) + private void retrieveCache() { + if (clusterContainerService == null) { + logger.error("un-initialized clusterContainerService, can't retrieve cache"); + return; + } + + logger.debug("Retrieving cache for Neutron Firewall"); + firewallDB = (ConcurrentMap) clusterContainerService + .getCache("neutronFirewalls"); + if (firewallDB == null) { + logger.error("Cache couldn't be retrieved for Neutron Firewall"); + } + logger.debug("Cache was successfully retrieved for Neutron Firewall"); + } + + private void destroyCache() { + if (clusterContainerService == null) { + logger.error("un-initialized clusterMger, can't destroy cache"); + return; + } + logger.debug("Destroying Cache for HostTracker"); + clusterContainerService.destroyCache("neutronFirewalls"); + } + + private void startUp() { + allocateCache(); + retrieveCache(); + loadConfiguration(); + } + + /** + * Function called by the dependency manager when all the required + * dependencies are satisfied + */ + void init(Component c) { + Dictionary props = c.getServiceProperties(); + if (props != null) { + this.containerName = (String) props.get("containerName"); + logger.debug("Running containerName: {}", this.containerName); + } else { + // In the Global instance case the containerName is empty + this.containerName = ""; + } + startUp(); + } + + /** + * Function called by the dependency manager when at least one dependency + * become unsatisfied or when the component is shutting down because for + * example bundle is being stopped. + */ + void destroy() { + destroyCache(); + } + + /** + * Function called by dependency manager after "init ()" is called and after + * the services provided by the class are registered in the service registry + */ + void start() { + } + + /** + * Function called by the dependency manager before the services exported by + * the component are unregistered, this will be followed by a "destroy ()" + * calls + */ + void stop() { + } + + // this method uses reflection to update an object from it's delta. + + private boolean overwrite(Object target, Object delta) { + Method[] methods = target.getClass().getMethods(); + + for (Method toMethod : methods) { + if (toMethod.getDeclaringClass().equals(target.getClass()) + && toMethod.getName().startsWith("set")) { + + String toName = toMethod.getName(); + String fromName = toName.replace("set", "get"); + + try { + Method fromMethod = delta.getClass().getMethod(fromName); + Object value = fromMethod.invoke(delta, (Object[]) null); + if (value != null) { + toMethod.invoke(target, value); + } + } catch (Exception e) { + e.printStackTrace(); + return false; + } + } + } + return true; + } + + @Override + public boolean neutronFirewallExists(String uuid) { + return firewallDB.containsKey(uuid); + } + + @Override + public NeutronFirewall getNeutronFirewall(String uuid) { + if (!neutronFirewallExists(uuid)) { + logger.debug("No Firewall Have Been Defined"); + return null; + } + return firewallDB.get(uuid); + } + + @Override + public List getAllNeutronFirewalls() { + Set allFirewalls = new HashSet(); + for (Entry entry : firewallDB.entrySet()) { + NeutronFirewall firewall = entry.getValue(); + allFirewalls.add(firewall); + } + logger.debug("Exiting getFirewalls, Found {} OpenStackFirewall", allFirewalls.size()); + List ans = new ArrayList(); + ans.addAll(allFirewalls); + return ans; + } + + @Override + public boolean addNeutronFirewall(NeutronFirewall input) { + if (neutronFirewallExists(input.getFirewallUUID())) { + return false; + } + firewallDB.putIfAbsent(input.getFirewallUUID(), input); + return true; + } + + @Override + public boolean removeNeutronFirewall(String uuid) { + if (!neutronFirewallExists(uuid)) { + return false; + } + firewallDB.remove(uuid); + return true; + } + + @Override + public boolean updateNeutronFirewall(String uuid, NeutronFirewall delta) { + if (!neutronFirewallExists(uuid)) { + return false; + } + NeutronFirewall target = firewallDB.get(uuid); + return overwrite(target, delta); + } + + @Override + public boolean neutronFirewallInUse(String firewallUUID) { + return !neutronFirewallExists(firewallUUID); + } + + private void loadConfiguration() { + for (ConfigurationObject conf : configurationService.retrieveConfiguration(this, FILE_NAME)) { + NeutronFirewall nn = (NeutronFirewall) conf; + firewallDB.put(nn.getFirewallUUID(), nn); + } + } + + @Override + public Status saveConfiguration() { + return configurationService.persistConfiguration(new ArrayList(firewallDB.values()), + FILE_NAME); + } + + @Override + public Object readObject(ObjectInputStream ois) throws FileNotFoundException, IOException, ClassNotFoundException { + return ois.readObject(); + } + +} \ No newline at end of file diff --git a/opendaylight/networkconfiguration/neutron/implementation/src/main/java/org/opendaylight/controller/networkconfig/neutron/implementation/NeutronFirewallPolicyInterface.java b/opendaylight/networkconfiguration/neutron/implementation/src/main/java/org/opendaylight/controller/networkconfig/neutron/implementation/NeutronFirewallPolicyInterface.java new file mode 100644 index 0000000000..84592628f0 --- /dev/null +++ b/opendaylight/networkconfiguration/neutron/implementation/src/main/java/org/opendaylight/controller/networkconfig/neutron/implementation/NeutronFirewallPolicyInterface.java @@ -0,0 +1,268 @@ +/* + * Copyright (C) 2014 Red Hat, Inc. + * + * 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.networkconfig.neutron.implementation; + +import org.apache.felix.dm.Component; +import org.opendaylight.controller.clustering.services.CacheConfigException; +import org.opendaylight.controller.clustering.services.CacheExistException; +import org.opendaylight.controller.clustering.services.IClusterContainerServices; +import org.opendaylight.controller.clustering.services.IClusterServices; +import org.opendaylight.controller.configuration.ConfigurationObject; +import org.opendaylight.controller.configuration.IConfigurationContainerAware; +import org.opendaylight.controller.configuration.IConfigurationContainerService; +import org.opendaylight.controller.networkconfig.neutron.INeutronFirewallPolicyCRUD; +import org.opendaylight.controller.networkconfig.neutron.NeutronFirewallPolicy; +import org.opendaylight.controller.sal.utils.IObjectReader; +import org.opendaylight.controller.sal.utils.Status; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import java.io.FileNotFoundException; +import java.io.IOException; +import java.io.ObjectInputStream; +import java.lang.reflect.Method; +import java.util.ArrayList; +import java.util.Dictionary; +import java.util.EnumSet; +import java.util.HashSet; +import java.util.List; +import java.util.Map.Entry; +import java.util.Set; +import java.util.concurrent.ConcurrentMap; + +public class NeutronFirewallPolicyInterface implements INeutronFirewallPolicyCRUD, IConfigurationContainerAware, IObjectReader { + private static final Logger logger = LoggerFactory.getLogger(NeutronFirewallPolicyInterface.class); + private static final String FILE_NAME ="neutron.firewallpolicy.conf"; + private String containerName = null; + + private IClusterContainerServices clusterContainerService = null; + private IConfigurationContainerService configurationService; + private ConcurrentMap firewallPolicyDB; + + // methods needed for creating caches + void setClusterContainerService(IClusterContainerServices s) { + logger.debug("Cluster Service set"); + clusterContainerService = s; + } + + void unsetClusterContainerService(IClusterContainerServices s) { + if (clusterContainerService == s) { + logger.debug("Cluster Service removed!"); + clusterContainerService = null; + } + } + + public void setConfigurationContainerService(IConfigurationContainerService service) { + logger.trace("Configuration service set: {}", service); + configurationService = service; + } + + public void unsetConfigurationContainerService(IConfigurationContainerService service) { + logger.trace("Configuration service removed: {}", service); + configurationService = null; + } + + private void allocateCache() { + if (this.clusterContainerService == null) { + logger.error("un-initialized clusterContainerService, can't create cache"); + return; + } + logger.debug("Creating Cache for Neutron Firewall Rule"); + try { + // neutron caches + this.clusterContainerService.createCache("neutronFirewallPolicies", + EnumSet.of(IClusterServices.cacheMode.NON_TRANSACTIONAL)); + } catch (CacheConfigException cce) { + logger.error("Cache couldn't be created for Neutron Firewall Rule - check cache mode"); + } catch (CacheExistException cce) { + logger.error("Cache for Neutron Firewall Rule already exists, destroy and recreate"); + } + logger.debug("Cache successfully created for Neutron Firewall Rule"); + } + + @SuppressWarnings({ "unchecked" }) + private void retrieveCache() { + if (clusterContainerService == null) { + logger.error("un-initialized clusterContainerService, can't retrieve cache"); + return; + } + + logger.debug("Retrieving cache for Neutron Firewall Rule"); + firewallPolicyDB = (ConcurrentMap) clusterContainerService + .getCache("neutronFirewallPolicies"); + if (firewallPolicyDB == null) { + logger.error("Cache couldn't be retrieved for Neutron Firewall Rule"); + } + logger.debug("Cache was successfully retrieved for Neutron Firewall Rule"); + } + + private void destroyCache() { + if (clusterContainerService == null) { + logger.error("un-initialized clusterMger, can't destroy cache"); + return; + } + logger.debug("Destroying Cache for HostTracker"); + clusterContainerService.destroyCache("neutronFirewallPolicies"); + } + + private void startUp() { + allocateCache(); + retrieveCache(); + loadConfiguration(); + } + + /** + * Function called by the dependency manager when all the required + * dependencies are satisfied + * + */ + void init(Component c) { + Dictionary props = c.getServiceProperties(); + if (props != null) { + this.containerName = (String) props.get("containerName"); + logger.debug("Running containerName: {}", this.containerName); + } else { + // In the Global instance case the containerName is empty + this.containerName = ""; + } + startUp(); + } + + /** + * Function called by the dependency manager when at least one dependency + * become unsatisfied or when the component is shutting down because for + * example bundle is being stopped. + * + */ + void destroy() { + destroyCache(); + } + + /** + * Function called by dependency manager after "init ()" is called and after + * the services provided by the class are registered in the service registry + * + */ + void start() { + } + + /** + * Function called by the dependency manager before the services exported by + * the component are unregistered, this will be followed by a "destroy ()" + * calls + * + */ + void stop() { + } + + // this method uses reflection to update an object from it's delta. + + private boolean overwrite(Object target, Object delta) { + Method[] methods = target.getClass().getMethods(); + + for(Method toMethod: methods){ + if(toMethod.getDeclaringClass().equals(target.getClass()) + && toMethod.getName().startsWith("set")){ + + String toName = toMethod.getName(); + String fromName = toName.replace("set", "get"); + + try { + Method fromMethod = delta.getClass().getMethod(fromName); + Object value = fromMethod.invoke(delta, (Object[])null); + if(value != null){ + toMethod.invoke(target, value); + } + } catch (Exception e) { + e.printStackTrace(); + return false; + } + } + } + return true; + } + + @Override + public boolean neutronFirewallPolicyExists(String uuid) { + return firewallPolicyDB.containsKey(uuid); + } + + @Override + public NeutronFirewallPolicy getNeutronFirewallPolicy(String uuid) { + if (!neutronFirewallPolicyExists(uuid)) { + logger.debug("No Firewall Rule Have Been Defined"); + return null; + } + return firewallPolicyDB.get(uuid); + } + + @Override + public List getAllNeutronFirewallPolicies() { + Set allFirewallPolicies = new HashSet(); + for (Entry entry : firewallPolicyDB.entrySet()) { + NeutronFirewallPolicy firewallPolicy = entry.getValue(); + allFirewallPolicies.add(firewallPolicy); + } + logger.debug("Exiting getFirewallPolicies, Found {} OpenStackFirewallPolicy", allFirewallPolicies.size()); + List ans = new ArrayList(); + ans.addAll(allFirewallPolicies); + return ans; + } + + @Override + public boolean addNeutronFirewallPolicy(NeutronFirewallPolicy input) { + if (neutronFirewallPolicyExists(input.getFirewallPolicyUUID())) { + return false; + } + firewallPolicyDB.putIfAbsent(input.getFirewallPolicyUUID(), input); + return true; + } + + @Override + public boolean removeNeutronFirewallPolicy(String uuid) { + if (!neutronFirewallPolicyExists(uuid)) { + return false; + } + firewallPolicyDB.remove(uuid); + return true; + } + + @Override + public boolean updateNeutronFirewallPolicy(String uuid, NeutronFirewallPolicy delta) { + if (!neutronFirewallPolicyExists(uuid)) { + return false; + } + NeutronFirewallPolicy target = firewallPolicyDB.get(uuid); + return overwrite(target, delta); + } + + @Override + public boolean neutronFirewallPolicyInUse(String firewallPolicyUUID) { + return !neutronFirewallPolicyExists(firewallPolicyUUID); + } + + private void loadConfiguration() { + for (ConfigurationObject conf : configurationService.retrieveConfiguration(this, FILE_NAME)) { + NeutronFirewallPolicy nn = (NeutronFirewallPolicy) conf; + firewallPolicyDB.put(nn.getFirewallPolicyUUID(), nn); + } + } + + @Override + public Status saveConfiguration() { + return configurationService.persistConfiguration(new ArrayList(firewallPolicyDB.values()), + FILE_NAME); + } + + @Override + public Object readObject(ObjectInputStream ois) throws FileNotFoundException, IOException, ClassNotFoundException { + return ois.readObject(); + } + +} \ No newline at end of file diff --git a/opendaylight/networkconfiguration/neutron/implementation/src/main/java/org/opendaylight/controller/networkconfig/neutron/implementation/NeutronFirewallRuleInterface.java b/opendaylight/networkconfiguration/neutron/implementation/src/main/java/org/opendaylight/controller/networkconfig/neutron/implementation/NeutronFirewallRuleInterface.java new file mode 100644 index 0000000000..ba84500cd7 --- /dev/null +++ b/opendaylight/networkconfiguration/neutron/implementation/src/main/java/org/opendaylight/controller/networkconfig/neutron/implementation/NeutronFirewallRuleInterface.java @@ -0,0 +1,267 @@ +/* + * Copyright (C) 2014 Red Hat, Inc. + * + * 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.networkconfig.neutron.implementation; + +import org.apache.felix.dm.Component; +import org.opendaylight.controller.clustering.services.CacheConfigException; +import org.opendaylight.controller.clustering.services.CacheExistException; +import org.opendaylight.controller.clustering.services.IClusterContainerServices; +import org.opendaylight.controller.clustering.services.IClusterServices; +import org.opendaylight.controller.configuration.ConfigurationObject; +import org.opendaylight.controller.configuration.IConfigurationContainerAware; +import org.opendaylight.controller.configuration.IConfigurationContainerService; +import org.opendaylight.controller.networkconfig.neutron.INeutronFirewallRuleCRUD; +import org.opendaylight.controller.networkconfig.neutron.NeutronFirewallRule; +import org.opendaylight.controller.sal.utils.IObjectReader; +import org.opendaylight.controller.sal.utils.Status; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import java.io.FileNotFoundException; +import java.io.IOException; +import java.io.ObjectInputStream; +import java.lang.reflect.Method; +import java.util.ArrayList; +import java.util.Dictionary; +import java.util.EnumSet; +import java.util.HashSet; +import java.util.List; +import java.util.Map.Entry; +import java.util.Set; +import java.util.concurrent.ConcurrentMap; + +public class NeutronFirewallRuleInterface implements INeutronFirewallRuleCRUD, IConfigurationContainerAware, IObjectReader { + private static final Logger logger = LoggerFactory.getLogger(NeutronFirewallRuleInterface.class); + private static final String FILE_NAME ="neutron.firewallrules.conf"; + private String containerName = null; + + private IClusterContainerServices clusterContainerService = null; + private IConfigurationContainerService configurationService; + private ConcurrentMap firewallRuleDB; + + // methods needed for creating caches + void setClusterContainerService(IClusterContainerServices s) { + logger.debug("Cluster Service set"); + clusterContainerService = s; + } + + void unsetClusterContainerService(IClusterContainerServices s) { + if (clusterContainerService == s) { + logger.debug("Cluster Service removed!"); + clusterContainerService = null; + } + } + + public void setConfigurationContainerService(IConfigurationContainerService service) { + logger.trace("Configuration service set: {}", service); + configurationService = service; + } + + public void unsetConfigurationContainerService(IConfigurationContainerService service) { + logger.trace("Configuration service removed: {}", service); + configurationService = null; + } + + private void allocateCache() { + if (this.clusterContainerService == null) { + logger.error("un-initialized clusterContainerService, can't create cache"); + return; + } + logger.debug("Creating Cache for Neutron Firewall Rule"); + try { + // neutron caches + this.clusterContainerService.createCache("neutronFirewallRules", + EnumSet.of(IClusterServices.cacheMode.NON_TRANSACTIONAL)); + } catch (CacheConfigException cce) { + logger.error("Cache couldn't be created for Neutron Firewall Rule - check cache mode"); + } catch (CacheExistException cce) { + logger.error("Cache for Neutron Firewall Rule already exists, destroy and recreate"); + } + logger.debug("Cache successfully created for Neutron Firewall Rule"); + } + + @SuppressWarnings({ "unchecked" }) + private void retrieveCache() { + if (clusterContainerService == null) { + logger.error("un-initialized clusterContainerService, can't retrieve cache"); + return; + } + + logger.debug("Retrieving cache for Neutron Firewall Rule"); + firewallRuleDB = (ConcurrentMap) clusterContainerService + .getCache("neutronFirewallRules"); + if (firewallRuleDB == null) { + logger.error("Cache couldn't be retrieved for Neutron Firewall Rule"); + } + logger.debug("Cache was successfully retrieved for Neutron Firewall Rule"); + } + + private void destroyCache() { + if (clusterContainerService == null) { + logger.error("un-initialized clusterMger, can't destroy cache"); + return; + } + logger.debug("Destroying Cache for HostTracker"); + clusterContainerService.destroyCache("neutronFirewallRules"); + } + + private void startUp() { + allocateCache(); + retrieveCache(); + loadConfiguration(); + } + + /** + * Function called by the dependency manager when all the required + * dependencies are satisfied + * + */ + void init(Component c) { + Dictionary props = c.getServiceProperties(); + if (props != null) { + this.containerName = (String) props.get("containerName"); + logger.debug("Running containerName: {}", this.containerName); + } else { + // In the Global instance case the containerName is empty + this.containerName = ""; + } + startUp(); + } + + /** + * Function called by the dependency manager when at least one dependency + * become unsatisfied or when the component is shutting down because for + * example bundle is being stopped. + * + */ + void destroy() { + destroyCache(); + } + + /** + * Function called by dependency manager after "init ()" is called and after + * the services provided by the class are registered in the service registry + * + */ + void start() { + } + + /** + * Function called by the dependency manager before the services exported by + * the component are unregistered, this will be followed by a "destroy ()" + * calls + * + */ + void stop() { + } + + // this method uses reflection to update an object from it's delta. + + private boolean overwrite(Object target, Object delta) { + Method[] methods = target.getClass().getMethods(); + + for(Method toMethod: methods){ + if(toMethod.getDeclaringClass().equals(target.getClass()) + && toMethod.getName().startsWith("set")){ + + String toName = toMethod.getName(); + String fromName = toName.replace("set", "get"); + + try { + Method fromMethod = delta.getClass().getMethod(fromName); + Object value = fromMethod.invoke(delta, (Object[])null); + if(value != null){ + toMethod.invoke(target, value); + } + } catch (Exception e) { + e.printStackTrace(); + return false; + } + } + } + return true; + } + + @Override + public boolean neutronFirewallRuleExists(String uuid) { + return firewallRuleDB.containsKey(uuid); + } + + @Override + public NeutronFirewallRule getNeutronFirewallRule(String uuid) { + if (!neutronFirewallRuleExists(uuid)) { + logger.debug("No Firewall Rule Have Been Defined"); + return null; + } + return firewallRuleDB.get(uuid); + } + + @Override + public List getAllNeutronFirewallRules() { + Set allFirewallRules = new HashSet(); + for (Entry entry : firewallRuleDB.entrySet()) { + NeutronFirewallRule firewallRule = entry.getValue(); + allFirewallRules.add(firewallRule); + } + logger.debug("Exiting getFirewallRules, Found {} OpenStackFirewallRule", allFirewallRules.size()); + List ans = new ArrayList(); + ans.addAll(allFirewallRules); + return ans; + } + + @Override + public boolean addNeutronFirewallRule(NeutronFirewallRule input) { + if (neutronFirewallRuleExists(input.getFirewallRuleUUID())) { + return false; + } + firewallRuleDB.putIfAbsent(input.getFirewallRuleUUID(), input); + return true; + } + + @Override + public boolean removeNeutronFirewallRule(String uuid) { + if (!neutronFirewallRuleExists(uuid)) { + return false; + } + firewallRuleDB.remove(uuid); + return true; + } + + @Override + public boolean updateNeutronFirewallRule(String uuid, NeutronFirewallRule delta) { + if (!neutronFirewallRuleExists(uuid)) { + return false; + } + NeutronFirewallRule target = firewallRuleDB.get(uuid); + return overwrite(target, delta); + } + + @Override + public boolean neutronFirewallRuleInUse(String firewallRuleUUID) { + return !neutronFirewallRuleExists(firewallRuleUUID); + } + + private void loadConfiguration() { + for (ConfigurationObject conf : configurationService.retrieveConfiguration(this, FILE_NAME)) { + NeutronFirewallRule nn = (NeutronFirewallRule) conf; + firewallRuleDB.put(nn.getFirewallRuleUUID(), nn); + } + } + + @Override + public Status saveConfiguration() { + return configurationService.persistConfiguration(new ArrayList(firewallRuleDB.values()), + FILE_NAME); + } + + @Override + public Object readObject(ObjectInputStream ois) throws FileNotFoundException, IOException, ClassNotFoundException { + return ois.readObject(); + } + +} \ No newline at end of file diff --git a/opendaylight/networkconfiguration/neutron/src/main/java/org/opendaylight/controller/networkconfig/neutron/INeutronFirewallAware.java b/opendaylight/networkconfiguration/neutron/src/main/java/org/opendaylight/controller/networkconfig/neutron/INeutronFirewallAware.java new file mode 100644 index 0000000000..9b4f579025 --- /dev/null +++ b/opendaylight/networkconfiguration/neutron/src/main/java/org/opendaylight/controller/networkconfig/neutron/INeutronFirewallAware.java @@ -0,0 +1,83 @@ +/* + * Copyright (C) 2014 Red Hat, Inc. + * + * 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.networkconfig.neutron; + +/** + * This interface defines the methods a service that wishes to be aware of Firewall Rules needs to implement + * + */ + +public interface INeutronFirewallAware { + + /** + * Services provide this interface method to indicate if the specified firewall can be created + * + * @param firewall + * instance of proposed new Firewall object + * @return integer + * the return value is understood to be a HTTP status code. A return value outside of 200 through 299 + * results in the create operation being interrupted and the returned status value reflected in the + * HTTP response. + */ + public int canCreateNeutronFirewall(NeutronFirewall firewall); + + /** + * Services provide this interface method for taking action after a firewall has been created + * + * @param firewall + * instance of new Firewall object + * @return void + */ + public void neutronFirewallCreated(NeutronFirewall firewall); + + /** + * Services provide this interface method to indicate if the specified firewall can be changed using the specified + * delta + * + * @param delta + * updates to the firewall object using patch semantics + * @param original + * instance of the Firewall object to be updated + * @return integer + * the return value is understood to be a HTTP status code. A return value outside of 200 through 299 + * results in the update operation being interrupted and the returned status value reflected in the + * HTTP response. + */ + public int canUpdateNeutronFirewall(NeutronFirewall delta, NeutronFirewall original); + + /** + * Services provide this interface method for taking action after a firewall has been updated + * + * @param firewall + * instance of modified Firewall object + * @return void + */ + public void neutronFirewallUpdated(NeutronFirewall firewall); + + /** + * Services provide this interface method to indicate if the specified firewall can be deleted + * + * @param firewall + * instance of the Firewall object to be deleted + * @return integer + * the return value is understood to be a HTTP status code. A return value outside of 200 through 299 + * results in the delete operation being interrupted and the returned status value reflected in the + * HTTP response. + */ + public int canDeleteNeutronFirewall(NeutronFirewall firewall); + + /** + * Services provide this interface method for taking action after a firewall has been deleted + * + * @param firewall + * instance of deleted Firewall object + * @return void + */ + public void neutronFirewallDeleted(NeutronFirewall firewall); +} diff --git a/opendaylight/networkconfiguration/neutron/src/main/java/org/opendaylight/controller/networkconfig/neutron/INeutronFirewallCRUD.java b/opendaylight/networkconfiguration/neutron/src/main/java/org/opendaylight/controller/networkconfig/neutron/INeutronFirewallCRUD.java new file mode 100644 index 0000000000..c986bffd6b --- /dev/null +++ b/opendaylight/networkconfiguration/neutron/src/main/java/org/opendaylight/controller/networkconfig/neutron/INeutronFirewallCRUD.java @@ -0,0 +1,95 @@ +/* + * Copyright (C) 2014 Red Hat, Inc. + * + * 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.networkconfig.neutron; + +import java.util.List; + +/** + * This interface defines the methods for CRUD of NB OpenStack Firewall objects + * + */ + +public interface INeutronFirewallCRUD { + /** + * Applications call this interface method to determine if a particular + *Firewall object exists + * + * @param uuid + * UUID of the Firewall object + * @return boolean + */ + + public boolean neutronFirewallExists(String uuid); + + /** + * Applications call this interface method to return if a particular + * Firewall object exists + * + * @param uuid + * UUID of the Firewall object + * @return {@link org.opendaylight.controller.networkconfig.neutron.NeutronFirewall} + * OpenStackFirewall class + */ + + public NeutronFirewall getNeutronFirewall(String uuid); + + /** + * Applications call this interface method to return all Firewall objects + * + * @return List of OpenStackNetworks objects + */ + + public List getAllNeutronFirewalls(); + + /** + * Applications call this interface method to add a Firewall object to the + * concurrent map + * + * @param input + * OpenStackNetwork object + * @return boolean on whether the object was added or not + */ + + public boolean addNeutronFirewall(NeutronFirewall input); + + /** + * Applications call this interface method to remove a Neutron Firewall object to the + * concurrent map + * + * @param uuid + * identifier for the Firewall object + * @return boolean on whether the object was removed or not + */ + + public boolean removeNeutronFirewall(String uuid); + + /** + * Applications call this interface method to edit a Firewall object + * + * @param uuid + * identifier of the Firewall object + * @param delta + * OpenStackFirewall object containing changes to apply + * @return boolean on whether the object was updated or not + */ + + public boolean updateNeutronFirewall(String uuid, NeutronFirewall delta); + + /** + * Applications call this interface method to see if a MAC address is in use + * + * @param uuid + * identifier of the Firewall object + * @return boolean on whether the macAddress is already associated with a + * port or not + */ + + public boolean neutronFirewallInUse(String uuid); + +} diff --git a/opendaylight/networkconfiguration/neutron/src/main/java/org/opendaylight/controller/networkconfig/neutron/INeutronFirewallPolicyAware.java b/opendaylight/networkconfiguration/neutron/src/main/java/org/opendaylight/controller/networkconfig/neutron/INeutronFirewallPolicyAware.java new file mode 100644 index 0000000000..203d513923 --- /dev/null +++ b/opendaylight/networkconfiguration/neutron/src/main/java/org/opendaylight/controller/networkconfig/neutron/INeutronFirewallPolicyAware.java @@ -0,0 +1,83 @@ +/* + * Copyright (C) 2014 Red Hat, Inc. + * + * 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.networkconfig.neutron; + +/** + * This interface defines the methods a service that wishes to be aware of Firewall Policys needs to implement + * + */ + +public interface INeutronFirewallPolicyAware { + + /** + * Services provide this interface method to indicate if the specified firewallPolicy can be created + * + * @param firewallPolicy + * instance of proposed new Firewall Policy object + * @return integer + * the return value is understood to be a HTTP status code. A return value outside of 200 through 299 + * results in the create operation being interrupted and the returned status value reflected in the + * HTTP response. + */ + public int canCreateNeutronFirewallPolicy(NeutronFirewallPolicy firewallPolicy); + + /** + * Services provide this interface method for taking action after a firewallPolicy has been created + * + * @param firewallPolicy + * instance of new Firewall Policy object + * @return void + */ + public void neutronFirewallPolicyCreated(NeutronFirewallPolicy firewallPolicy); + + /** + * Services provide this interface method to indicate if the specified firewallPolicy can be changed using the specified + * delta + * + * @param delta + * updates to the firewallPolicy object using patch semantics + * @param original + * instance of the Firewall Policy object to be updated + * @return integer + * the return value is understood to be a HTTP status code. A return value outside of 200 through 299 + * results in the update operation being interrupted and the returned status value reflected in the + * HTTP response. + */ + public int canUpdateNeutronFirewallPolicy(NeutronFirewallPolicy delta, NeutronFirewallPolicy original); + + /** + * Services provide this interface method for taking action after a firewallPolicy has been updated + * + * @param firewallPolicy + * instance of modified Firewall Policy object + * @return void + */ + public void neutronFirewallPolicyUpdated(NeutronFirewallPolicy firewallPolicy); + + /** + * Services provide this interface method to indicate if the specified firewallPolicy can be deleted + * + * @param firewallPolicy + * instance of the Firewall Policy object to be deleted + * @return integer + * the return value is understood to be a HTTP status code. A return value outside of 200 through 299 + * results in the delete operation being interrupted and the returned status value reflected in the + * HTTP response. + */ + public int canDeleteNeutronFirewallPolicy(NeutronFirewallPolicy firewallPolicy); + + /** + * Services provide this interface method for taking action after a firewallPolicy has been deleted + * + * @param firewallPolicy + * instance of deleted Firewall Policy object + * @return void + */ + public void neutronFirewallPolicyDeleted(NeutronFirewallPolicy firewallPolicy); +} diff --git a/opendaylight/networkconfiguration/neutron/src/main/java/org/opendaylight/controller/networkconfig/neutron/INeutronFirewallPolicyCRUD.java b/opendaylight/networkconfiguration/neutron/src/main/java/org/opendaylight/controller/networkconfig/neutron/INeutronFirewallPolicyCRUD.java new file mode 100644 index 0000000000..6049656a6e --- /dev/null +++ b/opendaylight/networkconfiguration/neutron/src/main/java/org/opendaylight/controller/networkconfig/neutron/INeutronFirewallPolicyCRUD.java @@ -0,0 +1,95 @@ +/* + * Copyright (C) 2014 Red Hat, Inc. + * + * 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.networkconfig.neutron; + +import java.util.List; + +/** + * This interface defines the methods for CRUD of NB OpenStack Firewall Policy objects + * + */ + +public interface INeutronFirewallPolicyCRUD { + /** + * Applications call this interface method to determine if a particular + *FirewallPolicy object exists + * + * @param uuid + * UUID of the Firewall Policy object + * @return boolean + */ + + public boolean neutronFirewallPolicyExists(String uuid); + + /** + * Applications call this interface method to return if a particular + * FirewallPolicy object exists + * + * @param uuid + * UUID of the Firewall Policy object + * @return {@link NeutronFirewallPolicy} + * OpenStackFirewallPolicy class + */ + + public NeutronFirewallPolicy getNeutronFirewallPolicy(String uuid); + + /** + * Applications call this interface method to return all Firewall Policy objects + * + * @return List of OpenStack Firewall Policy objects + */ + + public List getAllNeutronFirewallPolicies(); + + /** + * Applications call this interface method to add a Firewall Policy object to the + * concurrent map + * + * @param input + * OpenStackNetwork object + * @return boolean on whether the object was added or not + */ + + public boolean addNeutronFirewallPolicy(NeutronFirewallPolicy input); + + /** + * Applications call this interface method to remove a Neutron FirewallPolicy object to the + * concurrent map + * + * @param uuid + * identifier for the Firewall Policy object + * @return boolean on whether the object was removed or not + */ + + public boolean removeNeutronFirewallPolicy(String uuid); + + /** + * Applications call this interface method to edit a FirewallPolicy object + * + * @param uuid + * identifier of the Firewall Policy object + * @param delta + * OpenStackFirewallPolicy object containing changes to apply + * @return boolean on whether the object was updated or not + */ + + public boolean updateNeutronFirewallPolicy(String uuid, NeutronFirewallPolicy delta); + + /** + * Applications call this interface method to see if a MAC address is in use + * + * @param uuid + * identifier of the Firewall Policy object + * @return boolean on whether the macAddress is already associated with a + * port or not + */ + + public boolean neutronFirewallPolicyInUse(String uuid); + +} diff --git a/opendaylight/networkconfiguration/neutron/src/main/java/org/opendaylight/controller/networkconfig/neutron/INeutronFirewallRuleAware.java b/opendaylight/networkconfiguration/neutron/src/main/java/org/opendaylight/controller/networkconfig/neutron/INeutronFirewallRuleAware.java new file mode 100644 index 0000000000..a663058328 --- /dev/null +++ b/opendaylight/networkconfiguration/neutron/src/main/java/org/opendaylight/controller/networkconfig/neutron/INeutronFirewallRuleAware.java @@ -0,0 +1,83 @@ +/* + * Copyright (C) 2014 Red Hat, Inc. + * + * 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.networkconfig.neutron; + +/** + * This interface defines the methods a service that wishes to be aware of Firewall Rules needs to implement + * + */ + +public interface INeutronFirewallRuleAware { + + /** + * Services provide this interface method to indicate if the specified firewallRule can be created + * + * @param firewallRule + * instance of proposed new Firewall Rule object + * @return integer + * the return value is understood to be a HTTP status code. A return value outside of 200 through 299 + * results in the create operation being interrupted and the returned status value reflected in the + * HTTP response. + */ + public int canCreateNeutronFirewallRule(NeutronFirewallRule firewallRule); + + /** + * Services provide this interface method for taking action after a firewallRule has been created + * + * @param firewallRule + * instance of new Firewall Rule object + * @return void + */ + public void neutronFirewallRuleCreated(NeutronFirewallRule firewallRule); + + /** + * Services provide this interface method to indicate if the specified firewallRule can be changed using the specified + * delta + * + * @param delta + * updates to the firewallRule object using patch semantics + * @param original + * instance of the Firewall Rule object to be updated + * @return integer + * the return value is understood to be a HTTP status code. A return value outside of 200 through 299 + * results in the update operation being interrupted and the returned status value reflected in the + * HTTP response. + */ + public int canUpdateNeutronFirewallRule(NeutronFirewallRule delta, NeutronFirewallRule original); + + /** + * Services provide this interface method for taking action after a firewallRule has been updated + * + * @param firewallRule + * instance of modified Firewall Rule object + * @return void + */ + public void neutronFirewallRuleUpdated(NeutronFirewallRule firewallRule); + + /** + * Services provide this interface method to indicate if the specified firewallRule can be deleted + * + * @param firewallRule + * instance of the Firewall Rule object to be deleted + * @return integer + * the return value is understood to be a HTTP status code. A return value outside of 200 through 299 + * results in the delete operation being interrupted and the returned status value reflected in the + * HTTP response. + */ + public int canDeleteNeutronFirewallRule(NeutronFirewallRule firewallRule); + + /** + * Services provide this interface method for taking action after a firewallRule has been deleted + * + * @param firewallRule + * instance of deleted Firewall Rule object + * @return void + */ + public void neutronFirewallRuleDeleted(NeutronFirewallRule firewallRule); +} diff --git a/opendaylight/networkconfiguration/neutron/src/main/java/org/opendaylight/controller/networkconfig/neutron/INeutronFirewallRuleCRUD.java b/opendaylight/networkconfiguration/neutron/src/main/java/org/opendaylight/controller/networkconfig/neutron/INeutronFirewallRuleCRUD.java new file mode 100644 index 0000000000..990896bdb7 --- /dev/null +++ b/opendaylight/networkconfiguration/neutron/src/main/java/org/opendaylight/controller/networkconfig/neutron/INeutronFirewallRuleCRUD.java @@ -0,0 +1,95 @@ +/* + * Copyright (C) 2014 Red Hat, Inc. + * + * 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.networkconfig.neutron; + +import java.util.List; + +/** + * This interface defines the methods for CRUD of NB OpenStack Firewall Rule objects + * + */ + +public interface INeutronFirewallRuleCRUD { + /** + * Applications call this interface method to determine if a particular + *FirewallRule object exists + * + * @param uuid + * UUID of the Firewall Rule object + * @return boolean + */ + + public boolean neutronFirewallRuleExists(String uuid); + + /** + * Applications call this interface method to return if a particular + * FirewallRule object exists + * + * @param uuid + * UUID of the Firewall Rule object + * @return {@link NeutronFirewallRule} + * OpenStackFirewall Rule class + */ + + public NeutronFirewallRule getNeutronFirewallRule(String uuid); + + /** + * Applications call this interface method to return all Firewall Rule objects + * + * @return List of OpenStackNetworks objects + */ + + public List getAllNeutronFirewallRules(); + + /** + * Applications call this interface method to add a Firewall Rule object to the + * concurrent map + * + * @param input + * OpenStackNetwork object + * @return boolean on whether the object was added or not + */ + + public boolean addNeutronFirewallRule(NeutronFirewallRule input); + + /** + * Applications call this interface method to remove a Neutron FirewallRule object to the + * concurrent map + * + * @param uuid + * identifier for the Firewall Rule object + * @return boolean on whether the object was removed or not + */ + + public boolean removeNeutronFirewallRule(String uuid); + + /** + * Applications call this interface method to edit a FirewallRule object + * + * @param uuid + * identifier of the Firewall Rule object + * @param delta + * OpenStackFirewallRule object containing changes to apply + * @return boolean on whether the object was updated or not + */ + + public boolean updateNeutronFirewallRule(String uuid, NeutronFirewallRule delta); + + /** + * Applications call this interface method to see if a MAC address is in use + * + * @param uuid + * identifier of the Firewall Rule object + * @return boolean on whether the macAddress is already associated with a + * port or not + */ + + public boolean neutronFirewallRuleInUse(String uuid); + +} diff --git a/opendaylight/networkconfiguration/neutron/src/main/java/org/opendaylight/controller/networkconfig/neutron/NeutronCRUDInterfaces.java b/opendaylight/networkconfiguration/neutron/src/main/java/org/opendaylight/controller/networkconfig/neutron/NeutronCRUDInterfaces.java index 21cfdb1305..6ce5499cdf 100644 --- a/opendaylight/networkconfiguration/neutron/src/main/java/org/opendaylight/controller/networkconfig/neutron/NeutronCRUDInterfaces.java +++ b/opendaylight/networkconfiguration/neutron/src/main/java/org/opendaylight/controller/networkconfig/neutron/NeutronCRUDInterfaces.java @@ -46,4 +46,19 @@ public class NeutronCRUDInterfaces { INeutronSecurityRuleCRUD answer = (INeutronSecurityRuleCRUD) ServiceHelper.getGlobalInstance(INeutronSecurityRuleCRUD.class, o); return answer; } + + public static INeutronFirewallCRUD getINeutronFirewallCRUD(Object o) { + INeutronFirewallCRUD answer = (INeutronFirewallCRUD) ServiceHelper.getGlobalInstance(INeutronFirewallCRUD.class, o); + return answer; + } + + public static INeutronFirewallPolicyCRUD getINeutronFirewallPolicyCRUD(Object o) { + INeutronFirewallPolicyCRUD answer = (INeutronFirewallPolicyCRUD) ServiceHelper.getGlobalInstance(INeutronFirewallPolicyCRUD.class, o); + return answer; + } + + public static INeutronFirewallRuleCRUD getINeutronFirewallRuleCRUD(Object o) { + INeutronFirewallRuleCRUD answer = (INeutronFirewallRuleCRUD) ServiceHelper.getGlobalInstance(INeutronFirewallRuleCRUD.class, o); + return answer; + } } \ No newline at end of file diff --git a/opendaylight/networkconfiguration/neutron/src/main/java/org/opendaylight/controller/networkconfig/neutron/NeutronFirewall.java b/opendaylight/networkconfiguration/neutron/src/main/java/org/opendaylight/controller/networkconfig/neutron/NeutronFirewall.java new file mode 100644 index 0000000000..39f04c9b2b --- /dev/null +++ b/opendaylight/networkconfiguration/neutron/src/main/java/org/opendaylight/controller/networkconfig/neutron/NeutronFirewall.java @@ -0,0 +1,178 @@ +/* + * Copyright (C) 2014 Red Hat, Inc. + * + * 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.networkconfig.neutron; + +import org.opendaylight.controller.configuration.ConfigurationObject; + +import javax.xml.bind.annotation.XmlAccessType; +import javax.xml.bind.annotation.XmlAccessorType; +import javax.xml.bind.annotation.XmlElement; +import javax.xml.bind.annotation.XmlRootElement; +import java.io.Serializable; +import java.util.Iterator; +import java.util.List; + +/** + * OpenStack Neutron v2.0 Firewall as a service + * (FWaaS) bindings. See OpenStack Network API + * v2.0 Reference for description of the fields: + * Implemented fields are as follows: + * + * id uuid-str + * tenant_id uuid-str + * name String + * description String + * admin_state_up Bool + * status String + * shared Bool + * firewall_policy_id uuid-str + * http://docs.openstack.org/api/openstack-network/2.0/openstack-network.pdf + */ + +@XmlRootElement +@XmlAccessorType(XmlAccessType.NONE) + +public class NeutronFirewall extends ConfigurationObject implements Serializable { + private static final long serialVersionUID = 1L; + + @XmlElement(name="id") + String firewallUUID; + + @XmlElement (name="tenant_id") + String firewallTenantID; + + @XmlElement (name="name") + String firewallName; + + @XmlElement (name="description") + String firewallDescription; + + @XmlElement (defaultValue="true", name="admin_state_up") + Boolean firewallAdminStateIsUp; + + @XmlElement (name="status") + String firewallStatus; + + @XmlElement (defaultValue="false", name="shared") + Boolean firewallIsShared; + + @XmlElement (name="firewall_policy_id") + String neutronFirewallPolicyID; + + public String getFirewallUUID() { + return firewallUUID; + } + + public void setFirewallUUID(String firewallUUID) { + this.firewallUUID = firewallUUID; + } + + public String getFirewallTenantID() { + return firewallTenantID; + } + + public void setFirewallTenantID(String firewallTenantID) { + this.firewallTenantID = firewallTenantID; + } + + public String getFirewallName() { + return firewallName; + } + + public void setFirewallName(String firewallName) { + this.firewallName = firewallName; + } + + public String getFirewallDescription() { + return firewallDescription; + } + + public void setFirewallDescription(String firewallDescription) { + this.firewallDescription = firewallDescription; + } + + public Boolean getFirewallAdminStateIsUp() { + return firewallAdminStateIsUp; + } + + public void setFirewallAdminStateIsUp(Boolean firewallAdminStateIsUp) { + this.firewallAdminStateIsUp = firewallAdminStateIsUp; + } + + public String getFirewallStatus() { + return firewallStatus; + } + + public void setFirewallStatus(String firewallStatus) { + this.firewallStatus = firewallStatus; + } + + public Boolean getFirewallIsShared() { + return firewallIsShared; + } + + public void setFirewallIsShared(Boolean firewallIsShared) { + this.firewallIsShared = firewallIsShared; + } + + public String getFirewallPolicyID() { + return neutronFirewallPolicyID; + } + + public void setNeutronFirewallPolicyID(String firewallPolicy) { + this.neutronFirewallPolicyID = firewallPolicy; + } + + public NeutronFirewall extractFields(List fields) { + NeutronFirewall ans = new NeutronFirewall(); + Iterator i = fields.iterator(); + while (i.hasNext()) { + String s = i.next(); + if (s.equals("id")) { + ans.setFirewallUUID(this.getFirewallUUID()); + } + if (s.equals("tenant_id")) { + ans.setFirewallTenantID(this.getFirewallTenantID()); + } + if (s.equals("name")) { + ans.setFirewallName(this.getFirewallName()); + } + if(s.equals("description")) { + ans.setFirewallDescription(this.getFirewallDescription()); + } + if (s.equals("admin_state_up")) { + ans.setFirewallAdminStateIsUp(firewallAdminStateIsUp); + } + if (s.equals("status")) { + ans.setFirewallStatus(this.getFirewallStatus()); + } + if (s.equals("shared")) { + ans.setFirewallIsShared(firewallIsShared); + } + if (s.equals("firewall_policy_id")) { + ans.setNeutronFirewallPolicyID(this.getFirewallPolicyID()); + } + } + return ans; + } + + @Override + public String toString() { + return "NeutronFirewall{" + + "firewallUUID='" + firewallUUID + '\'' + + ", firewallTenantID='" + firewallTenantID + '\'' + + ", firewallName='" + firewallName + '\'' + + ", firewallDescription='" + firewallDescription + '\'' + + ", firewallAdminStateIsUp=" + firewallAdminStateIsUp + + ", firewallStatus='" + firewallStatus + '\'' + + ", firewallIsShared=" + firewallIsShared + + ", firewallRulePolicyID=" + neutronFirewallPolicyID + + '}'; + } +} diff --git a/opendaylight/networkconfiguration/neutron/src/main/java/org/opendaylight/controller/networkconfig/neutron/NeutronFirewallPolicy.java b/opendaylight/networkconfiguration/neutron/src/main/java/org/opendaylight/controller/networkconfig/neutron/NeutronFirewallPolicy.java new file mode 100644 index 0000000000..46436b52f4 --- /dev/null +++ b/opendaylight/networkconfiguration/neutron/src/main/java/org/opendaylight/controller/networkconfig/neutron/NeutronFirewallPolicy.java @@ -0,0 +1,165 @@ +/* + * Copyright (C) 2014 Red Hat, Inc. + * + * 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.networkconfig.neutron; + +import org.opendaylight.controller.configuration.ConfigurationObject; + +import javax.xml.bind.annotation.XmlAccessType; +import javax.xml.bind.annotation.XmlAccessorType; +import javax.xml.bind.annotation.XmlElement; +import javax.xml.bind.annotation.XmlRootElement; +import java.io.Serializable; +import java.util.ArrayList; +import java.util.Iterator; +import java.util.List; + +/** + * OpenStack Neutron v2.0 Firewall as a service + * (FWaaS) bindings. See OpenStack Network API + * v2.0 Reference for description of the fields. + * The implemented fields are as follows: + * + * id uuid-str + * tenant_id uuid-str + * name String + * description String + * shared Boolean + * firewall_rules List + * audited Boolean + * http://docs.openstack.org/api/openstack-network/2.0/openstack-network.pdf + */ + +@XmlRootElement +@XmlAccessorType(XmlAccessType.NONE) + +public class NeutronFirewallPolicy extends ConfigurationObject implements Serializable { + private static final long serialVersionUID = 1L; + + @XmlElement(name="id") + String firewallPolicyUUID; + + @XmlElement (name="tenant_id") + String firewallPolicyTenantID; + + @XmlElement (name="name") + String firewallPolicyName; + + @XmlElement (name="description") + String firewallPolicyDescription; + + @XmlElement (defaultValue="false", name="shared") + Boolean firewallPolicyIsShared; + + @XmlElement (name="firewall_rules") + List firewallPolicyRules; + + @XmlElement (defaultValue="false", name="audited") + String firewallPolicyIsAudited; + + public String getFirewallPolicyIsAudited() { + return firewallPolicyIsAudited; + } + + public void setFirewallPolicyIsAudited(String firewallPolicyIsAudited) { + this.firewallPolicyIsAudited = firewallPolicyIsAudited; + } + + public void setFirewallPolicyRules(List firewallPolicyRules) { + this.firewallPolicyRules = firewallPolicyRules; + } + + public List getFirewallPolicyRules() { + return firewallPolicyRules; + } + + public Boolean getFirewallPolicyIsShared() { + return firewallPolicyIsShared; + } + + public void setFirewallPolicyIsShared(Boolean firewallPolicyIsShared) { + this.firewallPolicyIsShared = firewallPolicyIsShared; + } + + public String getFirewallPolicyDescription() { + return firewallPolicyDescription; + } + + public void setFirewallPolicyDescription(String firewallPolicyDescription) { + this.firewallPolicyDescription = firewallPolicyDescription; + } + + public String getFirewallPolicyName() { + return firewallPolicyName; + } + + public void setFirewallPolicyName(String firewallPolicyName) { + this.firewallPolicyName = firewallPolicyName; + } + + public String getFirewallPolicyTenantID() { + return firewallPolicyTenantID; + } + + public void setFirewallPolicyTenantID(String firewallPolicyTenantID) { + this.firewallPolicyTenantID = firewallPolicyTenantID; + } + + public String getFirewallPolicyUUID() { + return firewallPolicyUUID; + } + + public void setFirewallPolicyUUID(String firewallPolicyUUID) { + this.firewallPolicyUUID = firewallPolicyUUID; + } + + public NeutronFirewallPolicy extractFields(List fields) { + NeutronFirewallPolicy ans = new NeutronFirewallPolicy(); + Iterator i = fields.iterator(); + while (i.hasNext()) { + String s = i.next(); + if (s.equals("id")) { + ans.setFirewallPolicyUUID(this.getFirewallPolicyUUID()); + } + if (s.equals("tenant_id")) { + ans.setFirewallPolicyTenantID(this.getFirewallPolicyTenantID()); + } + if (s.equals("name")) { + ans.setFirewallPolicyName(this.getFirewallPolicyName()); + } + if(s.equals("description")) { + ans.setFirewallPolicyDescription(this.getFirewallPolicyDescription()); + } + if (s.equals("shared")) { + ans.setFirewallPolicyIsShared(firewallPolicyIsShared); + } + if (s.equals("firewall_rules")) { + List firewallRuleList = new ArrayList(); + firewallRuleList.addAll(this.getFirewallPolicyRules()); + ans.setFirewallPolicyRules(firewallRuleList); + } + if (s.equals("audited")) { + ans.setFirewallPolicyIsAudited(firewallPolicyIsAudited); + } + } + return ans; + } + + @Override + public String toString() { + return "NeutronFirewallPolicy{" + + "firewallPolicyUUID='" + firewallPolicyUUID + '\'' + + ", firewallPolicyTenantID='" + firewallPolicyTenantID + '\'' + + ", firewallPolicyName='" + firewallPolicyName + '\'' + + ", firewallPolicyDescription='" + firewallPolicyDescription + '\'' + + ", firewallPolicyIsShared=" + firewallPolicyIsShared + + ", firewallPolicyRules=" + firewallPolicyRules + + ", firewallPolicyIsAudited='" + firewallPolicyIsAudited + '\'' + + '}'; + } +} \ No newline at end of file diff --git a/opendaylight/networkconfiguration/neutron/src/main/java/org/opendaylight/controller/networkconfig/neutron/NeutronFirewallRule.java b/opendaylight/networkconfiguration/neutron/src/main/java/org/opendaylight/controller/networkconfig/neutron/NeutronFirewallRule.java new file mode 100644 index 0000000000..63a65a27f9 --- /dev/null +++ b/opendaylight/networkconfiguration/neutron/src/main/java/org/opendaylight/controller/networkconfig/neutron/NeutronFirewallRule.java @@ -0,0 +1,323 @@ +/* + * Copyright (C) 2014 Red Hat, Inc. + * + * 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.networkconfig.neutron; + +import org.opendaylight.controller.configuration.ConfigurationObject; + +import javax.xml.bind.annotation.XmlAccessType; +import javax.xml.bind.annotation.XmlAccessorType; +import javax.xml.bind.annotation.XmlElement; +import javax.xml.bind.annotation.XmlRootElement; +import java.io.Serializable; +import java.util.Iterator; +import java.util.List; + +/** + * OpenStack Neutron v2.0 Firewall as a service + * (FWaaS) bindings. See OpenStack Network API + * v2.0 Reference for description of the fields. + * The implemented fields are as follows: + * + * tenant_id uuid-str + * name String + * description String + * admin_state_up Bool + * status String + * shared Bool + * firewall_policy_id uuid-str + * protocol String + * ip_version Integer + * source_ip_address String (IP addr or CIDR) + * destination_ip_address String (IP addr or CIDR) + * source_port Integer + * destination_port Integer + * position Integer + * action String + * enabled Bool + * id uuid-str + * http://docs.openstack.org/api/openstack-network/2.0/openstack-network.pdf + */ + +@XmlRootElement +@XmlAccessorType(XmlAccessType.NONE) + +public class NeutronFirewallRule extends ConfigurationObject implements Serializable { + private static final long serialVersionUID = 1L; + + @XmlElement(name = "id") + String firewallRuleUUID; + + @XmlElement(name = "tenant_id") + String firewallRuleTenantID; + + @XmlElement(name = "name") + String firewallRuleName; + + @XmlElement(name = "description") + String firewallRuleDescription; + + @XmlElement(defaultValue = "true", name = "admin_state_up") + Boolean firewallRuleAdminStateIsUp; + + @XmlElement(name = "status") + String firewallRuleStatus; + + @XmlElement(defaultValue = "false", name = "shared") + Boolean firewallRuleIsShared; + + @XmlElement(name = "firewall_policy_id") + String firewallRulePolicyID; + + @XmlElement(name = "protocol") + String firewallRuleProtocol; + + @XmlElement(name = "ip_version") + Integer firewallRuleIpVer; + + @XmlElement(name = "source_ip_address") + String firewallRuleSrcIpAddr; + + @XmlElement(name = "destination_ip_address") + String firewallRuleDstIpAddr; + + @XmlElement(name = "source_port") + Integer firewallRuleSrcPort; + + @XmlElement(name = "destination_port") + Integer firewallRuleDstPort; + + @XmlElement(name = "position") + Integer firewallRulePosition; + + @XmlElement(name = "action") + String firewallRuleAction; + + @XmlElement(name = "enabled") + Boolean firewallRuleIsEnabled; + + public Boolean getFirewallRuleIsEnabled() { + return firewallRuleIsEnabled; + } + + public void setFirewallRuleIsEnabled(Boolean firewallRuleIsEnabled) { + this.firewallRuleIsEnabled = firewallRuleIsEnabled; + } + + public String getFirewallRuleAction() { + return firewallRuleAction; + } + + public void setFirewallRuleAction(String firewallRuleAction) { + this.firewallRuleAction = firewallRuleAction; + } + + public Integer getFirewallRulePosition() { + return firewallRulePosition; + } + + public void setFirewallRulePosition(Integer firewallRulePosition) { + this.firewallRulePosition = firewallRulePosition; + } + + public Integer getFirewallRuleDstPort() { + return firewallRuleDstPort; + } + + public void setFirewallRuleDstPort(Integer firewallRuleDstPort) { + this.firewallRuleDstPort = firewallRuleDstPort; + } + + public Integer getFirewallRuleSrcPort() { + return firewallRuleSrcPort; + } + + public void setFirewallRuleSrcPort(Integer firewallRuleSrcPort) { + this.firewallRuleSrcPort = firewallRuleSrcPort; + } + + public String getFirewallRuleDstIpAddr() { + return firewallRuleDstIpAddr; + } + + public void setFirewallRuleDstIpAddr(String firewallRuleDstIpAddr) { + this.firewallRuleDstIpAddr = firewallRuleDstIpAddr; + } + + public String getFirewallRuleSrcIpAddr() { + return firewallRuleSrcIpAddr; + } + + public void setFirewallRuleSrcIpAddr(String firewallRuleSrcIpAddr) { + this.firewallRuleSrcIpAddr = firewallRuleSrcIpAddr; + } + + public Integer getFirewallRuleIpVer() { + return firewallRuleIpVer; + } + + public void setFirewallRuleIpVer(Integer firewallRuleIpVer) { + this.firewallRuleIpVer = firewallRuleIpVer; + } + + public String getFirewallRuleProtocol() { + return firewallRuleProtocol; + } + + public void setFirewallRuleProtocol(String firewallRuleProtocol) { + this.firewallRuleProtocol = firewallRuleProtocol; + } + + public String getFirewallRulePolicyID() { + return firewallRulePolicyID; + } + + public void setFirewallRulesPolicyID(String firewallRulePolicyID) { + this.firewallRulePolicyID = firewallRulePolicyID; + } + + public Boolean getFirewallRuleIsShared() { + return firewallRuleIsShared; + } + + public void setFirewallRuleIsShared(Boolean firewallRuleIsShared) { + this.firewallRuleIsShared = firewallRuleIsShared; + } + + public String getFirewallRuleStatus() { + return firewallRuleStatus; + } + + public void setFirewallRuleStatus(String firewallRuleStatus) { + this.firewallRuleStatus = firewallRuleStatus; + } + + public Boolean getFirewallRuleAdminStateIsUp() { + return firewallRuleAdminStateIsUp; + } + + public void setFirewallRuleAdminStateIsUp(Boolean firewallRuleAdminStateIsUp) { + this.firewallRuleAdminStateIsUp = firewallRuleAdminStateIsUp; + } + + public String getFirewallRuleDescription() { + return firewallRuleDescription; + } + + public void setFirewallRuleDescription(String firewallRuleDescription) { + this.firewallRuleDescription = firewallRuleDescription; + } + + public String getFirewallRuleName() { + return firewallRuleName; + } + + public void setFirewallRuleName(String firewallRuleName) { + this.firewallRuleName = firewallRuleName; + } + + public String getFirewallRuleTenantID() { + return firewallRuleTenantID; + } + + public void setFirewallRuleTenantID(String firewallRuleTenantID) { + this.firewallRuleTenantID = firewallRuleTenantID; + } + + public String getFirewallRuleUUID() { + return firewallRuleUUID; + } + + public void setFirewallRuleUUID(String firewallRuleUUID) { + this.firewallRuleUUID = firewallRuleUUID; + } + + public NeutronFirewallRule extractFields(List fields) { + NeutronFirewallRule ans = new NeutronFirewallRule(); + Iterator i = fields.iterator(); + while (i.hasNext()) { + String s = i.next(); + if (s.equals("id")) { + ans.setFirewallRuleUUID(this.getFirewallRuleUUID()); + } + if (s.equals("tenant_id")) { + ans.setFirewallRuleTenantID(this.getFirewallRuleTenantID()); + } + if (s.equals("name")) { + ans.setFirewallRuleName(this.getFirewallRuleName()); + } + if (s.equals("description")) { + ans.setFirewallRuleDescription(this.getFirewallRuleDescription()); + } + if (s.equals("admin_state_up")) { + ans.setFirewallRuleAdminStateIsUp(firewallRuleAdminStateIsUp); + } + if (s.equals("status")) { + ans.setFirewallRuleStatus(this.getFirewallRuleStatus()); + } + if (s.equals("shared")) { + ans.setFirewallRuleIsShared(firewallRuleIsShared); + } + if (s.equals("firewall_policy_id")) { + ans.setFirewallRulesPolicyID(this.getFirewallRulePolicyID()); + } + if (s.equals("protocol")) { + ans.setFirewallRuleProtocol(this.getFirewallRuleProtocol()); + } + if (s.equals("source_ip_address")) { + ans.setFirewallRuleSrcIpAddr(this.getFirewallRuleSrcIpAddr()); + } + if (s.equals("destination_ip_address")) { + ans.setFirewallRuleDstIpAddr(this.getFirewallRuleDstIpAddr()); + } + if (s.equals("source_port")) { + ans.setFirewallRuleSrcPort(this.getFirewallRuleSrcPort()); + } + if (s.equals("destination_port")) { + ans.setFirewallRuleDstPort(this.getFirewallRuleDstPort()); + } + if (s.equals("position")) { + ans.setFirewallRulePosition(this.getFirewallRulePosition()); + } + if (s.equals("action")) { + ans.setFirewallRuleAction(this.getFirewallRuleAction()); + } + if (s.equals("enabled")) { + ans.setFirewallRuleIsEnabled(firewallRuleIsEnabled); + } + + } + return ans; + } + + @Override + public String toString() { + return "firewallPolicyRules{" + + "firewallRuleUUID='" + firewallRuleUUID + '\'' + + ", firewallRuleTenantID='" + firewallRuleTenantID + '\'' + + ", firewallRuleName='" + firewallRuleName + '\'' + + ", firewallRuleDescription='" + firewallRuleDescription + '\'' + + ", firewallRuleAdminStateIsUp=" + firewallRuleAdminStateIsUp + + ", firewallRuleStatus='" + firewallRuleStatus + '\'' + + ", firewallRuleIsShared=" + firewallRuleIsShared + + ", firewallRulePolicyID=" + firewallRulePolicyID + + ", firewallRuleProtocol='" + firewallRuleProtocol + '\'' + + ", firewallRuleIpVer=" + firewallRuleIpVer + + ", firewallRuleSrcIpAddr='" + firewallRuleSrcIpAddr + '\'' + + ", firewallRuleDstIpAddr='" + firewallRuleDstIpAddr + '\'' + + ", firewallRuleSrcPort=" + firewallRuleSrcPort + + ", firewallRuleDstPort=" + firewallRuleDstPort + + ", firewallRulePosition=" + firewallRulePosition + + ", firewallRuleAction='" + firewallRuleAction + '\'' + + ", firewallRuleIsEnabled=" + firewallRuleIsEnabled + + '}'; + } + + public void initDefaults() { + } +} \ No newline at end of file diff --git a/opendaylight/northbound/networkconfiguration/neutron/src/main/java/org/opendaylight/controller/networkconfig/neutron/northbound/NeutronFirewallNorthbound.java b/opendaylight/northbound/networkconfiguration/neutron/src/main/java/org/opendaylight/controller/networkconfig/neutron/northbound/NeutronFirewallNorthbound.java new file mode 100644 index 0000000000..204c9f5176 --- /dev/null +++ b/opendaylight/northbound/networkconfiguration/neutron/src/main/java/org/opendaylight/controller/networkconfig/neutron/northbound/NeutronFirewallNorthbound.java @@ -0,0 +1,381 @@ +/* + * Copyright (C) 2014 Red Hat, Inc. + * + * 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.networkconfig.neutron.northbound; + + +import org.codehaus.enunciate.jaxrs.ResponseCode; +import org.codehaus.enunciate.jaxrs.StatusCodes; +import org.opendaylight.controller.networkconfig.neutron.INeutronFirewallAware; +import org.opendaylight.controller.networkconfig.neutron.INeutronFirewallCRUD; +import org.opendaylight.controller.networkconfig.neutron.INeutronFirewallRuleCRUD; +import org.opendaylight.controller.networkconfig.neutron.NeutronCRUDInterfaces; +import org.opendaylight.controller.networkconfig.neutron.NeutronFirewall; +import org.opendaylight.controller.northbound.commons.RestMessages; +import org.opendaylight.controller.northbound.commons.exception.BadRequestException; +import org.opendaylight.controller.northbound.commons.exception.ResourceNotFoundException; +import org.opendaylight.controller.northbound.commons.exception.ServiceUnavailableException; +import org.opendaylight.controller.sal.utils.ServiceHelper; + +import javax.ws.rs.Consumes; +import javax.ws.rs.DELETE; +import javax.ws.rs.GET; +import javax.ws.rs.POST; +import javax.ws.rs.PUT; +import javax.ws.rs.Path; +import javax.ws.rs.PathParam; +import javax.ws.rs.Produces; +import javax.ws.rs.QueryParam; +import javax.ws.rs.core.MediaType; +import javax.ws.rs.core.Response; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.Iterator; +import java.util.List; + +/** + * Neutron Northbound REST APIs for Firewall.
      + * This class provides REST APIs for managing neutron Firewall + * + *
      + *
      + * Authentication scheme : HTTP Basic
      + * Authentication realm : opendaylight
      + * Transport : HTTP and HTTPS
      + *
      + * HTTPS Authentication is disabled by default. Administrator can enable it in + * tomcat-server.xml after adding a proper keystore / SSL certificate from a + * trusted authority.
      + * More info : + * http://tomcat.apache.org/tomcat-7.0-doc/ssl-howto.html#Configuration + * + */ +@Path("/fw/firewalls") +public class NeutronFirewallNorthbound { + + private NeutronFirewall extractFields(NeutronFirewall o, List fields) { + return o.extractFields(fields); + } + + /** + * Returns a list of all Firewalls */ + @GET + @Produces({ MediaType.APPLICATION_JSON }) + @StatusCodes({ + @ResponseCode(code = 200, condition = "Operation successful"), + @ResponseCode(code = 401, condition = "Unauthorized"), + @ResponseCode(code = 501, condition = "Not Implemented") }) + + public Response listGroups( + // return fields + @QueryParam("fields") List fields, + // OpenStack firewall attributes + @QueryParam("id") String queryFirewallUUID, + @QueryParam("tenant_id") String queryFirewallTenantID, + @QueryParam("name") String queryFirewallName, + @QueryParam("description") String queryFirewallDescription, + @QueryParam("shared") Boolean queryFirewallAdminStateIsUp, + @QueryParam("status") String queryFirewallStatus, + @QueryParam("shared") Boolean queryFirewallIsShared, + @QueryParam("firewall_policy_id") String queryFirewallPolicyID, + // pagination + @QueryParam("limit") String limit, + @QueryParam("marker") String marker, + @QueryParam("page_reverse") String pageReverse + // sorting not supported + ) { + INeutronFirewallCRUD firewallInterface = NeutronCRUDInterfaces.getINeutronFirewallCRUD(this); + INeutronFirewallRuleCRUD firewallRuleInterface = NeutronCRUDInterfaces.getINeutronFirewallRuleCRUD(this); + + if (firewallInterface == null) { + throw new ServiceUnavailableException("Firewall CRUD Interface " + + RestMessages.SERVICEUNAVAILABLE.toString()); + } + List allFirewalls = firewallInterface.getAllNeutronFirewalls(); + List ans = new ArrayList(); + Iterator i = allFirewalls.iterator(); + while (i.hasNext()) { + NeutronFirewall nsg = i.next(); + if ((queryFirewallUUID == null || + queryFirewallUUID.equals(nsg.getFirewallUUID())) && + (queryFirewallTenantID == null || + queryFirewallTenantID.equals(nsg.getFirewallTenantID())) && + (queryFirewallName == null || + queryFirewallName.equals(nsg.getFirewallName())) && + (queryFirewallDescription == null || + queryFirewallDescription.equals(nsg.getFirewallDescription())) && + (queryFirewallAdminStateIsUp == null || + queryFirewallAdminStateIsUp.equals(nsg.getFirewallAdminStateIsUp())) && + (queryFirewallStatus == null || + queryFirewallStatus.equals(nsg.getFirewallStatus())) && + (queryFirewallIsShared == null || + queryFirewallIsShared.equals(nsg.getFirewallIsShared())) && + (queryFirewallPolicyID == null || + queryFirewallPolicyID.equals(nsg.getFirewallPolicyID()))) { + if (fields.size() > 0) { + ans.add(extractFields(nsg,fields)); + } else { + ans.add(nsg); + } + } + } + //TODO: apply pagination to results + return Response.status(200).entity( + new NeutronFirewallRequest(ans)).build(); + } + + /** + * Returns a specific Firewall */ + + @Path("{firewallUUID}") + @GET + @Produces({ MediaType.APPLICATION_JSON }) + @StatusCodes({ + @ResponseCode(code = 200, condition = "Operation successful"), + @ResponseCode(code = 401, condition = "Unauthorized"), + @ResponseCode(code = 404, condition = "Not Found"), + @ResponseCode(code = 501, condition = "Not Implemented") }) + public Response showFirewall(@PathParam("firewallUUID") String firewallUUID, + // return fields + @QueryParam("fields") List fields) { + INeutronFirewallCRUD firewallInterface = NeutronCRUDInterfaces.getINeutronFirewallCRUD(this); + if (firewallInterface == null) { + throw new ServiceUnavailableException("Firewall CRUD Interface " + + RestMessages.SERVICEUNAVAILABLE.toString()); + } + if (!firewallInterface.neutronFirewallExists(firewallUUID)) { + throw new ResourceNotFoundException("Firewall UUID does not exist."); + } + if (fields.size() > 0) { + NeutronFirewall ans = firewallInterface.getNeutronFirewall(firewallUUID); + return Response.status(200).entity( + new NeutronFirewallRequest(extractFields(ans, fields))).build(); + } else { + return Response.status(200).entity(new NeutronFirewallRequest(firewallInterface.getNeutronFirewall(firewallUUID))).build(); + } + } + + /** + * Creates new Firewall */ + + @POST + @Produces({ MediaType.APPLICATION_JSON }) + @Consumes({ MediaType.APPLICATION_JSON }) + @StatusCodes({ + @ResponseCode(code = 201, condition = "Created"), + @ResponseCode(code = 400, condition = "Bad Request"), + @ResponseCode(code = 401, condition = "Unauthorized"), + @ResponseCode(code = 403, condition = "Forbidden"), + @ResponseCode(code = 404, condition = "Not Found"), + @ResponseCode(code = 409, condition = "Conflict"), + @ResponseCode(code = 501, condition = "Not Implemented") }) + public Response createFirewalls(final NeutronFirewallRequest input) { + INeutronFirewallCRUD firewallInterface = NeutronCRUDInterfaces.getINeutronFirewallCRUD(this); + if (firewallInterface == null) { + throw new ServiceUnavailableException("Firewall CRUD Interface " + + RestMessages.SERVICEUNAVAILABLE.toString()); + } + if (input.isSingleton()) { + NeutronFirewall singleton = input.getSingleton(); + + /* + * Verify that the Firewall doesn't already exist. + */ + if (firewallInterface.neutronFirewallExists(singleton.getFirewallUUID())) { + throw new BadRequestException("Firewall UUID already exists"); + } + firewallInterface.addNeutronFirewall(singleton); + Object[] instances = ServiceHelper.getGlobalInstances(INeutronFirewallAware.class, this, null); + if (instances != null) { + for (Object instance : instances) { + INeutronFirewallAware service = (INeutronFirewallAware) instance; + int status = service.canCreateNeutronFirewall(singleton); + if (status < 200 || status > 299) { + return Response.status(status).build(); + } + } + } + firewallInterface.addNeutronFirewall(singleton); + if (instances != null) { + for (Object instance : instances) { + INeutronFirewallAware service = (INeutronFirewallAware) instance; + service.neutronFirewallCreated(singleton); + } + } + } else { + List bulk = input.getBulk(); + Iterator i = bulk.iterator(); + HashMap testMap = new HashMap(); + Object[] instances = ServiceHelper.getGlobalInstances(INeutronFirewallAware.class, this, null); + while (i.hasNext()) { + NeutronFirewall test = i.next(); + + /* + * Verify that the secruity group doesn't already exist + */ + if (firewallInterface.neutronFirewallExists(test.getFirewallUUID())) { + throw new BadRequestException("Firewall UUID already is already created"); + } + if (testMap.containsKey(test.getFirewallUUID())) { + throw new BadRequestException("Firewall UUID already exists"); + } + if (instances != null) { + for (Object instance : instances) { + INeutronFirewallAware service = (INeutronFirewallAware) instance; + int status = service.canCreateNeutronFirewall(test); + if (status < 200 || status > 299) { + return Response.status(status).build(); + } + } + } + } + + /* + * now, each element of the bulk request can be added to the cache + */ + i = bulk.iterator(); + while (i.hasNext()) { + NeutronFirewall test = i.next(); + firewallInterface.addNeutronFirewall(test); + if (instances != null) { + for (Object instance : instances) { + INeutronFirewallAware service = (INeutronFirewallAware) instance; + service.neutronFirewallCreated(test); + } + } + } + } + return Response.status(201).entity(input).build(); + } + + /** + * Updates a Firewall */ + + @Path("{firewallUUID}") + @PUT + @Produces({ MediaType.APPLICATION_JSON }) + @Consumes({ MediaType.APPLICATION_JSON }) + @StatusCodes({ + @ResponseCode(code = 200, condition = "Operation successful"), + @ResponseCode(code = 400, condition = "Bad Request"), + @ResponseCode(code = 401, condition = "Unauthorized"), + @ResponseCode(code = 403, condition = "Forbidden"), + @ResponseCode(code = 404, condition = "Not Found"), + @ResponseCode(code = 501, condition = "Not Implemented") }) + public Response updateFirewall( + @PathParam("firewallUUID") String firewallUUID, final NeutronFirewallRequest input) { + INeutronFirewallCRUD firewallInterface = NeutronCRUDInterfaces.getINeutronFirewallCRUD(this); + if (firewallInterface == null) { + throw new ServiceUnavailableException("Firewall CRUD Interface " + + RestMessages.SERVICEUNAVAILABLE.toString()); + } + + /* + * verify the Firewall exists and there is only one delta provided + */ + if (!firewallInterface.neutronFirewallExists(firewallUUID)) { + throw new ResourceNotFoundException("Firewall UUID does not exist."); + } + if (!input.isSingleton()) { + throw new BadRequestException("Only singleton edit supported"); + } + NeutronFirewall delta = input.getSingleton(); + NeutronFirewall original = firewallInterface.getNeutronFirewall(firewallUUID); + + /* + * updates restricted by Neutron + */ + if (delta.getFirewallUUID() != null || + delta.getFirewallTenantID() != null || + delta.getFirewallName() != null || + delta.getFirewallDescription() != null || + delta.getFirewallAdminStateIsUp() != null || + delta.getFirewallStatus() != null || + delta.getFirewallIsShared() != null || + delta.getFirewallPolicyID() != null) { + throw new BadRequestException("Attribute edit blocked by Neutron"); + } + + Object[] instances = ServiceHelper.getGlobalInstances(INeutronFirewallAware.class, this, null); + if (instances != null) { + for (Object instance : instances) { + INeutronFirewallAware service = (INeutronFirewallAware) instance; + int status = service.canUpdateNeutronFirewall(delta, original); + if (status < 200 || status > 299) { + return Response.status(status).build(); + } + } + } + + /* + * update the object and return it + */ + firewallInterface.updateNeutronFirewall(firewallUUID, delta); + NeutronFirewall updatedFirewall = firewallInterface.getNeutronFirewall(firewallUUID); + if (instances != null) { + for (Object instance : instances) { + INeutronFirewallAware service = (INeutronFirewallAware) instance; + service.neutronFirewallUpdated(updatedFirewall); + } + } + return Response.status(200).entity(new NeutronFirewallRequest(firewallInterface.getNeutronFirewall(firewallUUID))).build(); + } + + /** + * Deletes a Firewall */ + + @Path("{firewallUUID}") + @DELETE + @StatusCodes({ + @ResponseCode(code = 204, condition = "No Content"), + @ResponseCode(code = 401, condition = "Unauthorized"), + @ResponseCode(code = 404, condition = "Not Found"), + @ResponseCode(code = 409, condition = "Conflict"), + @ResponseCode(code = 501, condition = "Not Implemented") }) + public Response deleteFirewall( + @PathParam("firewallUUID") String firewallUUID) { + INeutronFirewallCRUD firewallInterface = NeutronCRUDInterfaces.getINeutronFirewallCRUD(this); + if (firewallInterface == null) { + throw new ServiceUnavailableException("Firewall CRUD Interface " + + RestMessages.SERVICEUNAVAILABLE.toString()); + } + + /* + * verify the Firewall exists and it isn't currently in use + */ + if (!firewallInterface.neutronFirewallExists(firewallUUID)) { + throw new ResourceNotFoundException("Firewall UUID does not exist."); + } + if (firewallInterface.neutronFirewallInUse(firewallUUID)) { + return Response.status(409).build(); + } + NeutronFirewall singleton = firewallInterface.getNeutronFirewall(firewallUUID); + Object[] instances = ServiceHelper.getGlobalInstances(INeutronFirewallAware.class, this, null); + if (instances != null) { + for (Object instance : instances) { + INeutronFirewallAware service = (INeutronFirewallAware) instance; + int status = service.canDeleteNeutronFirewall(singleton); + if (status < 200 || status > 299) { + return Response.status(status).build(); + } + } + } + + /* + * remove it and return 204 status + */ + firewallInterface.removeNeutronFirewall(firewallUUID); + if (instances != null) { + for (Object instance : instances) { + INeutronFirewallAware service = (INeutronFirewallAware) instance; + service.neutronFirewallDeleted(singleton); + } + } + return Response.status(204).build(); + } +} diff --git a/opendaylight/northbound/networkconfiguration/neutron/src/main/java/org/opendaylight/controller/networkconfig/neutron/northbound/NeutronFirewallPolicyNorthbound.java b/opendaylight/northbound/networkconfiguration/neutron/src/main/java/org/opendaylight/controller/networkconfig/neutron/northbound/NeutronFirewallPolicyNorthbound.java new file mode 100644 index 0000000000..bfe2c922bd --- /dev/null +++ b/opendaylight/northbound/networkconfiguration/neutron/src/main/java/org/opendaylight/controller/networkconfig/neutron/northbound/NeutronFirewallPolicyNorthbound.java @@ -0,0 +1,374 @@ +/* + * Copyright (C) 2014 Red Hat, Inc. + * + * 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.networkconfig.neutron.northbound; + + +import org.codehaus.enunciate.jaxrs.ResponseCode; +import org.codehaus.enunciate.jaxrs.StatusCodes; +import org.opendaylight.controller.networkconfig.neutron.INeutronFirewallPolicyAware; +import org.opendaylight.controller.networkconfig.neutron.INeutronFirewallPolicyCRUD; +import org.opendaylight.controller.networkconfig.neutron.NeutronCRUDInterfaces; +import org.opendaylight.controller.networkconfig.neutron.NeutronFirewallPolicy; +import org.opendaylight.controller.northbound.commons.RestMessages; +import org.opendaylight.controller.northbound.commons.exception.BadRequestException; +import org.opendaylight.controller.northbound.commons.exception.ResourceNotFoundException; +import org.opendaylight.controller.northbound.commons.exception.ServiceUnavailableException; +import org.opendaylight.controller.sal.utils.ServiceHelper; + +import javax.ws.rs.Consumes; +import javax.ws.rs.DELETE; +import javax.ws.rs.GET; +import javax.ws.rs.POST; +import javax.ws.rs.PUT; +import javax.ws.rs.Path; +import javax.ws.rs.PathParam; +import javax.ws.rs.Produces; +import javax.ws.rs.QueryParam; +import javax.ws.rs.core.MediaType; +import javax.ws.rs.core.Response; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.Iterator; +import java.util.List; + +/** + * Neutron Northbound REST APIs for Firewall Policies.
      + * This class provides REST APIs for managing neutron Firewall Policies + * + *
      + *
      + * Authentication scheme : HTTP Basic
      + * Authentication realm : opendaylight
      + * Transport : HTTP and HTTPS
      + *
      + * HTTPS Authentication is disabled by default. Administrator can enable it in + * tomcat-server.xml after adding a proper keystore / SSL certificate from a + * trusted authority.
      + * More info : + * http://tomcat.apache.org/tomcat-7.0-doc/ssl-howto.html#Configuration + * + */ +@Path("/fw/firewalls_policies") +public class NeutronFirewallPolicyNorthbound { + + private NeutronFirewallPolicy extractFields(NeutronFirewallPolicy o, List fields) { + return o.extractFields(fields); + } + + /** + * Returns a list of all Firewall Policies */ + @GET + @Produces({ MediaType.APPLICATION_JSON }) + @StatusCodes({ + @ResponseCode(code = 200, condition = "Operation successful"), + @ResponseCode(code = 401, condition = "Unauthorized"), + @ResponseCode(code = 501, condition = "Not Implemented") }) + + public Response listGroups( + // return fields + @QueryParam("fields") List fields, + // OpenStack Firewall Policy attributes + @QueryParam("id") String queryFirewallPolicyUUID, + @QueryParam("tenant_id") String queryFirewallPolicyTenantID, + @QueryParam("name") String queryFirewallPolicyName, + @QueryParam("description") String querySecurityPolicyDescription, + @QueryParam("shared") String querySecurityPolicyIsShared, + @QueryParam("firewall_rules") List querySecurityPolicyFirewallRules, + @QueryParam("audited") Boolean querySecurityPolicyIsAudited, + // pagination + @QueryParam("limit") String limit, + @QueryParam("marker") String marker, + @QueryParam("page_reverse") String pageReverse + // sorting not supported + ) { + INeutronFirewallPolicyCRUD firewallPolicyInterface = NeutronCRUDInterfaces.getINeutronFirewallPolicyCRUD(this); + + if (firewallPolicyInterface == null) { + throw new ServiceUnavailableException("Firewall Policy CRUD Interface " + + RestMessages.SERVICEUNAVAILABLE.toString()); + } + List allFirewallPolicies = firewallPolicyInterface.getAllNeutronFirewallPolicies(); + List ans = new ArrayList(); + Iterator i = allFirewallPolicies.iterator(); + while (i.hasNext()) { + NeutronFirewallPolicy nsg = i.next(); + if ((queryFirewallPolicyUUID == null || + queryFirewallPolicyUUID.equals(nsg.getFirewallPolicyUUID())) && + (queryFirewallPolicyTenantID == null || + queryFirewallPolicyTenantID.equals(nsg.getFirewallPolicyTenantID())) && + (queryFirewallPolicyName == null || + queryFirewallPolicyName.equals(nsg.getFirewallPolicyName())) && + (querySecurityPolicyDescription == null || + querySecurityPolicyDescription.equals(nsg.getFirewallPolicyDescription())) && + (querySecurityPolicyIsShared == null || + querySecurityPolicyIsShared.equals(nsg.getFirewallPolicyIsShared())) && + (querySecurityPolicyFirewallRules.size() == 0 || + querySecurityPolicyFirewallRules.equals(nsg.getFirewallPolicyRules())) && + (querySecurityPolicyIsAudited == null || + querySecurityPolicyIsAudited.equals(nsg.getFirewallPolicyIsAudited()))) { + if (fields.size() > 0) { + ans.add(extractFields(nsg,fields)); + } else { + ans.add(nsg); + } + } + } // ans.add((NeutronFirewallPolicy) rules); + //TODO: apply pagination to results + return Response.status(200).entity( + new NeutronFirewallPolicyRequest(ans)).build(); + } + + /** + * Returns a specific Firewall Policy */ + + @Path("{firewallPolicyUUID}") + @GET + @Produces({ MediaType.APPLICATION_JSON }) + @StatusCodes({ + @ResponseCode(code = 200, condition = "Operation successful"), + @ResponseCode(code = 401, condition = "Unauthorized"), + @ResponseCode(code = 404, condition = "Not Found"), + @ResponseCode(code = 501, condition = "Not Implemented") }) + public Response showFirewallPolicy(@PathParam("firewallPolicyUUID") String firewallPolicyUUID, + // return fields + @QueryParam("fields") List fields) { + INeutronFirewallPolicyCRUD firewallPolicyInterface = NeutronCRUDInterfaces.getINeutronFirewallPolicyCRUD(this); + if (firewallPolicyInterface == null) { + throw new ServiceUnavailableException("Firewall Policy CRUD Interface " + + RestMessages.SERVICEUNAVAILABLE.toString()); + } + if (!firewallPolicyInterface.neutronFirewallPolicyExists(firewallPolicyUUID)) { + throw new ResourceNotFoundException("Firewall Policy UUID does not exist."); + } + if (fields.size() > 0) { + NeutronFirewallPolicy ans = firewallPolicyInterface.getNeutronFirewallPolicy(firewallPolicyUUID); + return Response.status(200).entity( + new NeutronFirewallPolicyRequest(extractFields(ans, fields))).build(); + } else { + return Response.status(200).entity(new NeutronFirewallPolicyRequest(firewallPolicyInterface.getNeutronFirewallPolicy(firewallPolicyUUID))).build(); + } + } + + /** + * Creates new Firewall Policy + * */ + @POST + @Produces({ MediaType.APPLICATION_JSON }) + @Consumes({ MediaType.APPLICATION_JSON }) + @StatusCodes({ + @ResponseCode(code = 201, condition = "Created"), + @ResponseCode(code = 400, condition = "Bad Request"), + @ResponseCode(code = 401, condition = "Unauthorized"), + @ResponseCode(code = 403, condition = "Forbidden"), + @ResponseCode(code = 404, condition = "Not Found"), + @ResponseCode(code = 409, condition = "Conflict"), + @ResponseCode(code = 501, condition = "Not Implemented") }) + public Response createFirewallPolicies(final NeutronFirewallPolicyRequest input) { + INeutronFirewallPolicyCRUD firewallPolicyInterface = NeutronCRUDInterfaces.getINeutronFirewallPolicyCRUD(this); + if (firewallPolicyInterface == null) { + throw new ServiceUnavailableException("Firewall Policy CRUD Interface " + + RestMessages.SERVICEUNAVAILABLE.toString()); + } + if (input.isSingleton()) { + NeutronFirewallPolicy singleton = input.getSingleton(); + + /* + * Verify that the Firewall Policy doesn't already exist. + */ + if (firewallPolicyInterface.neutronFirewallPolicyExists(singleton.getFirewallPolicyUUID())) { + throw new BadRequestException("Firewall Policy UUID already exists"); + } + firewallPolicyInterface.addNeutronFirewallPolicy(singleton); + + Object[] instances = ServiceHelper.getGlobalInstances(INeutronFirewallPolicyAware.class, this, null); + if (instances != null) { + for (Object instance : instances) { + INeutronFirewallPolicyAware service = (INeutronFirewallPolicyAware) instance; + int status = service.canCreateNeutronFirewallPolicy(singleton); + if (status < 200 || status > 299) { + return Response.status(status).build(); + } + } + } + firewallPolicyInterface.addNeutronFirewallPolicy(singleton); + if (instances != null) { + for (Object instance : instances) { + INeutronFirewallPolicyAware service = (INeutronFirewallPolicyAware) instance; + service.neutronFirewallPolicyCreated(singleton); + } + } + } else { + List bulk = input.getBulk(); + Iterator i = bulk.iterator(); + HashMap testMap = new HashMap(); + Object[] instances = ServiceHelper.getGlobalInstances(INeutronFirewallPolicyAware.class, this, null); + while (i.hasNext()) { + NeutronFirewallPolicy test = i.next(); + + /* + * Verify that the firewall policy doesn't already exist + */ + + if (firewallPolicyInterface.neutronFirewallPolicyExists(test.getFirewallPolicyUUID())) { + throw new BadRequestException("Firewall Policy UUID already is already created"); + } + if (testMap.containsKey(test.getFirewallPolicyUUID())) { + throw new BadRequestException("Firewall Policy UUID already exists"); + } + if (instances != null) { + for (Object instance : instances) { + INeutronFirewallPolicyAware service = (INeutronFirewallPolicyAware) instance; + int status = service.canCreateNeutronFirewallPolicy(test); + if (status < 200 || status > 299) { + return Response.status(status).build(); + } + } + } + } + /* + * now, each element of the bulk request can be added to the cache + */ + i = bulk.iterator(); + while (i.hasNext()) { + NeutronFirewallPolicy test = i.next(); + firewallPolicyInterface.addNeutronFirewallPolicy(test); + if (instances != null) { + for (Object instance : instances) { + INeutronFirewallPolicyAware service = (INeutronFirewallPolicyAware) instance; + service.neutronFirewallPolicyCreated(test); + } + } + } + } + return Response.status(201).entity(input).build(); + } + + /** + * Updates a Firewall Policy + */ + @Path("{firewallPolicyUUID}") + @PUT + @Produces({ MediaType.APPLICATION_JSON }) + @Consumes({ MediaType.APPLICATION_JSON }) + //@TypeHint(OpenStackSubnets.class) + @StatusCodes({ + @ResponseCode(code = 200, condition = "Operation successful"), + @ResponseCode(code = 400, condition = "Bad Request"), + @ResponseCode(code = 401, condition = "Unauthorized"), + @ResponseCode(code = 403, condition = "Forbidden"), + @ResponseCode(code = 404, condition = "Not Found"), + @ResponseCode(code = 501, condition = "Not Implemented") }) + public Response updateFirewallPolicy( + @PathParam("firewallPolicyUUID") String firewallPolicyUUID, final NeutronFirewallPolicyRequest input) { + INeutronFirewallPolicyCRUD firewallPolicyInterface = NeutronCRUDInterfaces.getINeutronFirewallPolicyCRUD(this); + if (firewallPolicyInterface == null) { + throw new ServiceUnavailableException("Firewall Policy CRUD Interface " + + RestMessages.SERVICEUNAVAILABLE.toString()); + } + + /* + * verify the Firewall Policy exists and there is only one delta provided + */ + if (!firewallPolicyInterface.neutronFirewallPolicyExists(firewallPolicyUUID)) { + throw new ResourceNotFoundException("Firewall Policy UUID does not exist."); + } + if (!input.isSingleton()) { + throw new BadRequestException("Only singleton edit supported"); + } + NeutronFirewallPolicy delta = input.getSingleton(); + NeutronFirewallPolicy original = firewallPolicyInterface.getNeutronFirewallPolicy(firewallPolicyUUID); + + /* + * updates restricted by Neutron + */ + if (delta.getFirewallPolicyUUID() != null || + delta.getFirewallPolicyTenantID() != null || + delta.getFirewallPolicyName() != null || + delta.getFirewallPolicyDescription() != null || + delta.getFirewallPolicyIsShared() != null || + delta.getFirewallPolicyRules().size() > 0 || + delta.getFirewallPolicyIsAudited() != null) { + throw new BadRequestException("Attribute edit blocked by Neutron"); + } + + Object[] instances = ServiceHelper.getGlobalInstances(INeutronFirewallPolicyAware.class, this, null); + if (instances != null) { + for (Object instance : instances) { + INeutronFirewallPolicyAware service = (INeutronFirewallPolicyAware) instance; + int status = service.canUpdateNeutronFirewallPolicy(delta, original); + if (status < 200 || status > 299) { + return Response.status(status).build(); + } + } + } + + /* + * update the object and return it + */ + firewallPolicyInterface.updateNeutronFirewallPolicy(firewallPolicyUUID, delta); + NeutronFirewallPolicy updatedFirewallPolicy = firewallPolicyInterface.getNeutronFirewallPolicy(firewallPolicyUUID); + if (instances != null) { + for (Object instance : instances) { + INeutronFirewallPolicyAware service = (INeutronFirewallPolicyAware) instance; + service.neutronFirewallPolicyUpdated(updatedFirewallPolicy); + } + } + return Response.status(200).entity(new NeutronFirewallPolicyRequest(firewallPolicyInterface.getNeutronFirewallPolicy(firewallPolicyUUID))).build(); + } + + /** + * Deletes a Firewall Policy */ + + @Path("{firewallPolicyUUID}") + @DELETE + @StatusCodes({ + @ResponseCode(code = 204, condition = "No Content"), + @ResponseCode(code = 401, condition = "Unauthorized"), + @ResponseCode(code = 404, condition = "Not Found"), + @ResponseCode(code = 409, condition = "Conflict"), + @ResponseCode(code = 501, condition = "Not Implemented") }) + public Response deleteFirewallPolicy( + @PathParam("firewallPolicyUUID") String firewallPolicyUUID) { + INeutronFirewallPolicyCRUD firewallPolicyInterface = NeutronCRUDInterfaces.getINeutronFirewallPolicyCRUD(this); + if (firewallPolicyInterface == null) { + throw new ServiceUnavailableException("Firewall Policy CRUD Interface " + + RestMessages.SERVICEUNAVAILABLE.toString()); + } + + /* + * verify the Firewall Policy exists and it isn't currently in use + */ + if (!firewallPolicyInterface.neutronFirewallPolicyExists(firewallPolicyUUID)) { + throw new ResourceNotFoundException("Firewall Policy UUID does not exist."); + } + if (firewallPolicyInterface.neutronFirewallPolicyInUse(firewallPolicyUUID)) { + return Response.status(409).build(); + } + NeutronFirewallPolicy singleton = firewallPolicyInterface.getNeutronFirewallPolicy(firewallPolicyUUID); + Object[] instances = ServiceHelper.getGlobalInstances(INeutronFirewallPolicyAware.class, this, null); + if (instances != null) { + for (Object instance : instances) { + INeutronFirewallPolicyAware service = (INeutronFirewallPolicyAware) instance; + int status = service.canDeleteNeutronFirewallPolicy(singleton); + if (status < 200 || status > 299) { + return Response.status(status).build(); + } + } + } + + firewallPolicyInterface.removeNeutronFirewallPolicy(firewallPolicyUUID); + if (instances != null) { + for (Object instance : instances) { + INeutronFirewallPolicyAware service = (INeutronFirewallPolicyAware) instance; + service.neutronFirewallPolicyDeleted(singleton); + } + } + return Response.status(204).build(); + } +} diff --git a/opendaylight/northbound/networkconfiguration/neutron/src/main/java/org/opendaylight/controller/networkconfig/neutron/northbound/NeutronFirewallPolicyRequest.java b/opendaylight/northbound/networkconfiguration/neutron/src/main/java/org/opendaylight/controller/networkconfig/neutron/northbound/NeutronFirewallPolicyRequest.java new file mode 100644 index 0000000000..473846a6d9 --- /dev/null +++ b/opendaylight/northbound/networkconfiguration/neutron/src/main/java/org/opendaylight/controller/networkconfig/neutron/northbound/NeutronFirewallPolicyRequest.java @@ -0,0 +1,58 @@ +/* + * Copyright (C) 2014 Red Hat, Inc. + * + * 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.networkconfig.neutron.northbound; + +import org.opendaylight.controller.networkconfig.neutron.NeutronFirewallPolicy; + +import javax.xml.bind.annotation.XmlAccessType; +import javax.xml.bind.annotation.XmlAccessorType; +import javax.xml.bind.annotation.XmlElement; +import javax.xml.bind.annotation.XmlRootElement; +import java.util.List; + + +@XmlRootElement +@XmlAccessorType(XmlAccessType.NONE) + +public class NeutronFirewallPolicyRequest { + /** + * See OpenStack Network API v2.0 Reference for description of + * http://docs.openstack.org/api/openstack-network/2.0/content/ + */ + + @XmlElement(name="firewall_policy") + NeutronFirewallPolicy singletonFirewallPolicy; + + @XmlElement(name="firewall_policies") + List bulkRequest; + + NeutronFirewallPolicyRequest() { + } + + NeutronFirewallPolicyRequest(List bulk) { + bulkRequest = bulk; + singletonFirewallPolicy = null; + } + + NeutronFirewallPolicyRequest(NeutronFirewallPolicy group) { + singletonFirewallPolicy = group; + } + + public List getBulk() { + return bulkRequest; + } + + public NeutronFirewallPolicy getSingleton() { + return singletonFirewallPolicy; + } + + public boolean isSingleton() { + return (singletonFirewallPolicy != null); + } +} \ No newline at end of file diff --git a/opendaylight/northbound/networkconfiguration/neutron/src/main/java/org/opendaylight/controller/networkconfig/neutron/northbound/NeutronFirewallRequest.java b/opendaylight/northbound/networkconfiguration/neutron/src/main/java/org/opendaylight/controller/networkconfig/neutron/northbound/NeutronFirewallRequest.java new file mode 100644 index 0000000000..11a7836b22 --- /dev/null +++ b/opendaylight/northbound/networkconfiguration/neutron/src/main/java/org/opendaylight/controller/networkconfig/neutron/northbound/NeutronFirewallRequest.java @@ -0,0 +1,58 @@ +/* + * Copyright (C) 2014 Red Hat, Inc. + * + * 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.networkconfig.neutron.northbound; + +import org.opendaylight.controller.networkconfig.neutron.NeutronFirewall; + +import javax.xml.bind.annotation.XmlAccessType; +import javax.xml.bind.annotation.XmlAccessorType; +import javax.xml.bind.annotation.XmlElement; +import javax.xml.bind.annotation.XmlRootElement; +import java.util.List; + + +@XmlRootElement +@XmlAccessorType(XmlAccessType.NONE) + +public class NeutronFirewallRequest { + /** + * See OpenStack Network API v2.0 Reference for description of + * http://docs.openstack.org/api/openstack-network/2.0/content/ + */ + + @XmlElement(name="firewall") + NeutronFirewall singletonFirewall; + + @XmlElement(name="firewalls") + List bulkRequest; + + NeutronFirewallRequest() { + } + + NeutronFirewallRequest(List bulk) { + bulkRequest = bulk; + singletonFirewall = null; + } + + NeutronFirewallRequest(NeutronFirewall group) { + singletonFirewall = group; + } + + public List getBulk() { + return bulkRequest; + } + + public NeutronFirewall getSingleton() { + return singletonFirewall; + } + + public boolean isSingleton() { + return (singletonFirewall != null); + } +} \ No newline at end of file diff --git a/opendaylight/northbound/networkconfiguration/neutron/src/main/java/org/opendaylight/controller/networkconfig/neutron/northbound/NeutronFirewallRuleRequest.java b/opendaylight/northbound/networkconfiguration/neutron/src/main/java/org/opendaylight/controller/networkconfig/neutron/northbound/NeutronFirewallRuleRequest.java new file mode 100644 index 0000000000..19e67dd234 --- /dev/null +++ b/opendaylight/northbound/networkconfiguration/neutron/src/main/java/org/opendaylight/controller/networkconfig/neutron/northbound/NeutronFirewallRuleRequest.java @@ -0,0 +1,58 @@ +/* + * Copyright (C) 2014 Red Hat, Inc. + * + * 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.networkconfig.neutron.northbound; + +import org.opendaylight.controller.networkconfig.neutron.NeutronFirewallRule; + +import javax.xml.bind.annotation.XmlAccessType; +import javax.xml.bind.annotation.XmlAccessorType; +import javax.xml.bind.annotation.XmlElement; +import javax.xml.bind.annotation.XmlRootElement; +import java.util.List; + + +@XmlRootElement +@XmlAccessorType(XmlAccessType.NONE) + +public class NeutronFirewallRuleRequest { + /** + * See OpenStack Network API v2.0 Reference for description of + * http://docs.openstack.org/api/openstack-network/2.0/content/ + */ + + @XmlElement(name="firewall_rule") + NeutronFirewallRule singletonFirewallRule; + + @XmlElement(name="firewall_rules") + List bulkRequest; + + NeutronFirewallRuleRequest() { + } + + NeutronFirewallRuleRequest(List bulk) { + bulkRequest = bulk; + singletonFirewallRule = null; + } + + NeutronFirewallRuleRequest(NeutronFirewallRule group) { + singletonFirewallRule = group; + } + + public List getBulk() { + return bulkRequest; + } + + public NeutronFirewallRule getSingleton() { + return singletonFirewallRule; + } + + public boolean isSingleton() { + return (singletonFirewallRule != null); + } +} \ No newline at end of file diff --git a/opendaylight/northbound/networkconfiguration/neutron/src/main/java/org/opendaylight/controller/networkconfig/neutron/northbound/NeutronFirewallRulesNorthbound.java b/opendaylight/northbound/networkconfiguration/neutron/src/main/java/org/opendaylight/controller/networkconfig/neutron/northbound/NeutronFirewallRulesNorthbound.java new file mode 100644 index 0000000000..9911b4dfd4 --- /dev/null +++ b/opendaylight/northbound/networkconfiguration/neutron/src/main/java/org/opendaylight/controller/networkconfig/neutron/northbound/NeutronFirewallRulesNorthbound.java @@ -0,0 +1,427 @@ +/* + * Copyright (C) 2014 Red Hat, Inc. + * + * 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.networkconfig.neutron.northbound; + + +import org.codehaus.enunciate.jaxrs.ResponseCode; +import org.codehaus.enunciate.jaxrs.StatusCodes; +import org.opendaylight.controller.networkconfig.neutron.INeutronFirewallPolicyCRUD; +import org.opendaylight.controller.networkconfig.neutron.INeutronFirewallRuleAware; +import org.opendaylight.controller.networkconfig.neutron.INeutronFirewallRuleCRUD; +import org.opendaylight.controller.networkconfig.neutron.NeutronCRUDInterfaces; +import org.opendaylight.controller.networkconfig.neutron.NeutronFirewallRule; +import org.opendaylight.controller.northbound.commons.RestMessages; +import org.opendaylight.controller.northbound.commons.exception.BadRequestException; +import org.opendaylight.controller.northbound.commons.exception.ResourceNotFoundException; +import org.opendaylight.controller.northbound.commons.exception.ServiceUnavailableException; +import org.opendaylight.controller.sal.utils.ServiceHelper; + +import javax.ws.rs.Consumes; +import javax.ws.rs.DELETE; +import javax.ws.rs.GET; +import javax.ws.rs.POST; +import javax.ws.rs.PUT; +import javax.ws.rs.Path; +import javax.ws.rs.PathParam; +import javax.ws.rs.Produces; +import javax.ws.rs.QueryParam; +import javax.ws.rs.core.MediaType; +import javax.ws.rs.core.Response; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.Iterator; +import java.util.List; + +/** + * Neutron Northbound REST APIs for Firewall Rule.
      + * This class provides REST APIs for managing neutron Firewall Rule + * + *
      + *
      + * Authentication scheme : HTTP Basic
      + * Authentication realm : opendaylight
      + * Transport : HTTP and HTTPS
      + *
      + * HTTPS Authentication is disabled by default. Administrator can enable it in + * tomcat-server.xml after adding a proper keystore / SSL certificate from a + * trusted authority.
      + * More info : + * http://tomcat.apache.org/tomcat-7.0-doc/ssl-howto.html#Configuration + */ + +@Path("fw/firewalls_rules") +public class NeutronFirewallRulesNorthbound { + + private NeutronFirewallRule extractFields(NeutronFirewallRule o, List fields) { + return o.extractFields(fields); + } + + /** + * Returns a list of all Firewall Rules + */ + @GET + @Produces({MediaType.APPLICATION_JSON}) + @StatusCodes({ + @ResponseCode(code = 200, condition = "Operation successful"), + @ResponseCode(code = 401, condition = "Unauthorized"), + @ResponseCode(code = 501, condition = "Not Implemented")}) + public Response listRules( + // return fields + @QueryParam("fields") List fields, + // OpenStack firewall rule attributes + @QueryParam("id") String queryFirewallRuleUUID, + @QueryParam("tenant_id") String queryFirewallRuleTenantID, + @QueryParam("name") String queryFirewallRuleName, + @QueryParam("description") String queryFirewallRuleDescription, + @QueryParam("admin_state_up") Boolean queryFirewallRuleAdminStateIsUp, + @QueryParam("status") String queryFirewallRuleStatus, + @QueryParam("shared") Boolean queryFirewallRuleIsShared, + @QueryParam("firewall_policy_id") String queryFirewallRulePolicyID, + @QueryParam("protocol") String queryFirewallRuleProtocol, + @QueryParam("ip_version") Integer queryFirewallRuleIpVer, + @QueryParam("source_ip_address") String queryFirewallRuleSrcIpAddr, + @QueryParam("destination_ip_address") String queryFirewallRuleDstIpAddr, + @QueryParam("source_port") Integer queryFirewallRuleSrcPort, + @QueryParam("destination_port") Integer queryFirewallRuleDstPort, + @QueryParam("position") Integer queryFirewallRulePosition, + @QueryParam("action") String queryFirewallRuleAction, + @QueryParam("enabled") Boolean queryFirewallRuleIsEnabled, + // pagination + @QueryParam("limit") String limit, + @QueryParam("marker") String marker, + @QueryParam("page_reverse") String pageReverse + // sorting not supported + ) { + INeutronFirewallRuleCRUD firewallRuleInterface = NeutronCRUDInterfaces.getINeutronFirewallRuleCRUD(this); + if (firewallRuleInterface == null) { + throw new ServiceUnavailableException("Firewall Rule CRUD Interface " + + RestMessages.SERVICEUNAVAILABLE.toString()); + } + List allFirewallRules = firewallRuleInterface.getAllNeutronFirewallRules(); + List ans = new ArrayList(); + Iterator i = allFirewallRules.iterator(); + while (i.hasNext()) { + NeutronFirewallRule nsr = i.next(); + if ((queryFirewallRuleUUID == null || + queryFirewallRuleUUID.equals(nsr.getFirewallRuleUUID())) && + (queryFirewallRuleTenantID == null || + queryFirewallRuleTenantID.equals(nsr.getFirewallRuleTenantID())) && + (queryFirewallRuleName == null || + queryFirewallRuleName.equals(nsr.getFirewallRuleName())) && + (queryFirewallRuleDescription == null || + queryFirewallRuleDescription.equals(nsr.getFirewallRuleDescription())) && + (queryFirewallRuleAdminStateIsUp == null || + queryFirewallRuleAdminStateIsUp.equals(nsr.getFirewallRuleAdminStateIsUp())) && + (queryFirewallRuleStatus == null || + queryFirewallRuleStatus.equals(nsr.getFirewallRuleStatus())) && + (queryFirewallRuleIsShared == null || + queryFirewallRuleIsShared.equals(nsr.getFirewallRuleIsShared())) && + (queryFirewallRulePolicyID == null || + queryFirewallRulePolicyID.equals(nsr.getFirewallRulePolicyID())) && + (queryFirewallRuleProtocol == null || + queryFirewallRuleProtocol.equals(nsr.getFirewallRuleProtocol())) && + (queryFirewallRuleIpVer == null || + queryFirewallRuleIpVer.equals(nsr.getFirewallRuleIpVer())) && + (queryFirewallRuleSrcIpAddr == null || + queryFirewallRuleSrcIpAddr.equals(nsr.getFirewallRuleSrcIpAddr())) && + (queryFirewallRuleDstIpAddr == null || + queryFirewallRuleDstIpAddr.equals(nsr.getFirewallRuleDstIpAddr())) && + (queryFirewallRuleSrcPort == null || + queryFirewallRuleSrcPort.equals(nsr.getFirewallRuleSrcPort())) && + (queryFirewallRuleDstPort == null || + queryFirewallRuleDstPort.equals(nsr.getFirewallRuleDstPort())) && + (queryFirewallRulePosition == null || + queryFirewallRulePosition.equals(nsr.getFirewallRulePosition())) && + (queryFirewallRuleAction == null || + queryFirewallRuleAction.equals(nsr.getFirewallRuleAction())) && + (queryFirewallRuleIsEnabled == null || + queryFirewallRuleIsEnabled.equals(nsr.getFirewallRuleIsEnabled()))) { + if (fields.size() > 0) { + ans.add(extractFields(nsr, fields)); + } else { + ans.add(nsr); + } + } + } + //TODO: apply pagination to results + return Response.status(200).entity( + new NeutronFirewallRuleRequest(ans)).build(); + } + + /** + * Returns a specific Firewall Rule + */ + + @Path("{firewallRuleUUID}") + @GET + @Produces({MediaType.APPLICATION_JSON}) + @StatusCodes({ + @ResponseCode(code = 200, condition = "Operation successful"), + @ResponseCode(code = 401, condition = "Unauthorized"), + @ResponseCode(code = 404, condition = "Not Found"), + @ResponseCode(code = 501, condition = "Not Implemented")}) + public Response showFirewallRule(@PathParam("firewallRuleUUID") String firewallRuleUUID, + // return fields + @QueryParam("fields") List fields) { + INeutronFirewallRuleCRUD firewallRuleInterface = NeutronCRUDInterfaces.getINeutronFirewallRuleCRUD(this); + if (firewallRuleInterface == null) { + throw new ServiceUnavailableException("Firewall Rule CRUD Interface " + + RestMessages.SERVICEUNAVAILABLE.toString()); + } + if (!firewallRuleInterface.neutronFirewallRuleExists(firewallRuleUUID)) { + throw new ResourceNotFoundException("Firewall Rule UUID does not exist."); + } + if (fields.size() > 0) { + NeutronFirewallRule ans = firewallRuleInterface.getNeutronFirewallRule(firewallRuleUUID); + return Response.status(200).entity( + new NeutronFirewallRuleRequest(extractFields(ans, fields))).build(); + } else { + return Response.status(200) + .entity(new NeutronFirewallRuleRequest( + firewallRuleInterface.getNeutronFirewallRule(firewallRuleUUID))) + .build(); + } + } + + /** + * Creates new Firewall Rule + */ + + @POST + @Produces({MediaType.APPLICATION_JSON}) + @Consumes({MediaType.APPLICATION_JSON}) + @StatusCodes({ + @ResponseCode(code = 201, condition = "Created"), + @ResponseCode(code = 400, condition = "Bad Request"), + @ResponseCode(code = 401, condition = "Unauthorized"), + @ResponseCode(code = 403, condition = "Forbidden"), + @ResponseCode(code = 404, condition = "Not Found"), + @ResponseCode(code = 409, condition = "Conflict"), + @ResponseCode(code = 501, condition = "Not Implemented")}) + public Response createFirewallRules(final NeutronFirewallRuleRequest input) { + INeutronFirewallRuleCRUD firewallRuleInterface = NeutronCRUDInterfaces.getINeutronFirewallRuleCRUD(this); + if (firewallRuleInterface == null) { + throw new ServiceUnavailableException("Firewall Rule CRUD Interface " + + RestMessages.SERVICEUNAVAILABLE.toString()); + } + INeutronFirewallPolicyCRUD firewallPolicyInterface = NeutronCRUDInterfaces.getINeutronFirewallPolicyCRUD(this); + if (firewallPolicyInterface == null) { + throw new ServiceUnavailableException("Firewall Policy CRUD Interface " + + RestMessages.SERVICEUNAVAILABLE.toString()); + } + + if (input.isSingleton()) { + NeutronFirewallRule singleton = input.getSingleton(); + if (firewallRuleInterface.neutronFirewallRuleExists(singleton.getFirewallRuleUUID())) { + throw new BadRequestException("Firewall Rule UUID already exists"); + } + firewallRuleInterface.addNeutronFirewallRule(singleton); + Object[] instances = ServiceHelper.getGlobalInstances(INeutronFirewallRuleAware.class, this, null); + if (instances != null) { + for (Object instance : instances) { + INeutronFirewallRuleAware service = (INeutronFirewallRuleAware) instance; + int status = service.canCreateNeutronFirewallRule(singleton); + if (status < 200 || status > 299) { + return Response.status(status).build(); + } + } + } + // add rule to cache + singleton.initDefaults(); + firewallRuleInterface.addNeutronFirewallRule(singleton); + if (instances != null) { + for (Object instance : instances) { + INeutronFirewallRuleAware service = (INeutronFirewallRuleAware) instance; + service.neutronFirewallRuleCreated(singleton); + } + } + } else { + List bulk = input.getBulk(); + Iterator i = bulk.iterator(); + HashMap testMap = new HashMap(); + Object[] instances = ServiceHelper.getGlobalInstances(INeutronFirewallRuleAware.class, this, null); + while (i.hasNext()) { + NeutronFirewallRule test = i.next(); + + /* + * Verify that the Firewall rule doesn't already exist + */ + + if (firewallRuleInterface.neutronFirewallRuleExists(test.getFirewallRuleUUID())) { + throw new BadRequestException("Firewall Rule UUID already exists"); + } + if (testMap.containsKey(test.getFirewallRuleUUID())) { + throw new BadRequestException("Firewall Rule UUID already exists"); + } + if (instances != null) { + for (Object instance : instances) { + INeutronFirewallRuleAware service = (INeutronFirewallRuleAware) instance; + int status = service.canCreateNeutronFirewallRule(test); + if (status < 200 || status > 299) { + return Response.status(status).build(); + } + } + } + } + /* + * now, each element of the bulk request can be added to the cache + */ + i = bulk.iterator(); + while (i.hasNext()) { + NeutronFirewallRule test = i.next(); + firewallRuleInterface.addNeutronFirewallRule(test); + if (instances != null) { + for (Object instance : instances) { + INeutronFirewallRuleAware service = (INeutronFirewallRuleAware) instance; + service.neutronFirewallRuleCreated(test); + } + } + } + } + return Response.status(201).entity(input).build(); + } + + /** + * Updates a Firewall Rule + */ + @Path("{firewallRuleUUID}") + @PUT + @Produces({MediaType.APPLICATION_JSON}) + @Consumes({MediaType.APPLICATION_JSON}) + @StatusCodes({ + @ResponseCode(code = 200, condition = "Operation successful"), + @ResponseCode(code = 400, condition = "Bad Request"), + @ResponseCode(code = 401, condition = "Unauthorized"), + @ResponseCode(code = 403, condition = "Forbidden"), + @ResponseCode(code = 404, condition = "Not Found"), + @ResponseCode(code = 501, condition = "Not Implemented")}) + public Response updateFirewallRule( + @PathParam("firewallRuleUUID") String firewallRuleUUID, final NeutronFirewallRuleRequest input) { + INeutronFirewallRuleCRUD firewallRuleInterface = NeutronCRUDInterfaces.getINeutronFirewallRuleCRUD(this); + if (firewallRuleInterface == null) { + throw new ServiceUnavailableException("Firewall Rule CRUD Interface " + + RestMessages.SERVICEUNAVAILABLE.toString()); + } + /* + * verify the Firewall Rule exists + */ + if (!firewallRuleInterface.neutronFirewallRuleExists(firewallRuleUUID)) { + throw new ResourceNotFoundException("Firewall Rule UUID does not exist."); + } + if (!input.isSingleton()) { + throw new BadRequestException("Only singleton edit supported"); + } + NeutronFirewallRule delta = input.getSingleton(); + NeutronFirewallRule original = firewallRuleInterface.getNeutronFirewallRule(firewallRuleUUID); + + /* + * updates restricted by Neutron + * + */ + if (delta.getFirewallRuleUUID() != null || + delta.getFirewallRuleTenantID() != null || + delta.getFirewallRuleName() != null || + delta.getFirewallRuleDescription() != null || + delta.getFirewallRuleAdminStateIsUp() != null || + delta.getFirewallRuleStatus() != null || + delta.getFirewallRuleIsShared() != null || + delta.getFirewallRulePolicyID() != null || + delta.getFirewallRuleProtocol() != null || + delta.getFirewallRuleIpVer() != null || + delta.getFirewallRuleSrcIpAddr() != null || + delta.getFirewallRuleDstIpAddr() != null || + delta.getFirewallRuleSrcPort() != null || + delta.getFirewallRuleDstPort() != null || + delta.getFirewallRulePosition() != null || + delta.getFirewallRuleAction() != null || + delta.getFirewallRuleIsEnabled() != null) { + throw new BadRequestException("Attribute edit blocked by Neutron"); + } + + Object[] instances = ServiceHelper.getGlobalInstances(INeutronFirewallRuleAware.class, this, null); + if (instances != null) { + for (Object instance : instances) { + INeutronFirewallRuleAware service = (INeutronFirewallRuleAware) instance; + int status = service.canUpdateNeutronFirewallRule(delta, original); + if (status < 200 || status > 299) { + return Response.status(status).build(); + } + } + } + + /* + * update the object and return it + */ + firewallRuleInterface.updateNeutronFirewallRule(firewallRuleUUID, delta); + NeutronFirewallRule updatedFirewallRule = firewallRuleInterface.getNeutronFirewallRule(firewallRuleUUID); + if (instances != null) { + for (Object instance : instances) { + INeutronFirewallRuleAware service = (INeutronFirewallRuleAware) instance; + service.neutronFirewallRuleUpdated(updatedFirewallRule); + } + } + return Response.status(200) + .entity(new NeutronFirewallRuleRequest(firewallRuleInterface.getNeutronFirewallRule(firewallRuleUUID))) + .build(); + } + + /** + * Deletes a Firewall Rule + */ + + @Path("{firewallRuleUUID}") + @DELETE + @StatusCodes({ + @ResponseCode(code = 204, condition = "No Content"), + @ResponseCode(code = 401, condition = "Unauthorized"), + @ResponseCode(code = 404, condition = "Not Found"), + @ResponseCode(code = 409, condition = "Conflict"), + @ResponseCode(code = 501, condition = "Not Implemented")}) + public Response deleteFirewallRule( + @PathParam("firewallRuleUUID") String firewallRuleUUID) { + INeutronFirewallRuleCRUD firewallRuleInterface = NeutronCRUDInterfaces.getINeutronFirewallRuleCRUD(this); + if (firewallRuleInterface == null) { + throw new ServiceUnavailableException("Firewall Rule CRUD Interface " + + RestMessages.SERVICEUNAVAILABLE.toString()); + } + + /* + * verify the Firewall Rule exists and it isn't currently in use + */ + if (!firewallRuleInterface.neutronFirewallRuleExists(firewallRuleUUID)) { + throw new ResourceNotFoundException("Firewall Rule UUID does not exist."); + } + if (firewallRuleInterface.neutronFirewallRuleInUse(firewallRuleUUID)) { + return Response.status(409).build(); + } + NeutronFirewallRule singleton = firewallRuleInterface.getNeutronFirewallRule(firewallRuleUUID); + Object[] instances = ServiceHelper.getGlobalInstances(INeutronFirewallRuleAware.class, this, null); + if (instances != null) { + for (Object instance : instances) { + INeutronFirewallRuleAware service = (INeutronFirewallRuleAware) instance; + int status = service.canDeleteNeutronFirewallRule(singleton); + if (status < 200 || status > 299) { + return Response.status(status).build(); + } + } + } + + /* + * remove it and return 204 status + */ + firewallRuleInterface.removeNeutronFirewallRule(firewallRuleUUID); + if (instances != null) { + for (Object instance : instances) { + INeutronFirewallRuleAware service = (INeutronFirewallRuleAware) instance; + service.neutronFirewallRuleDeleted(singleton); + } + } + return Response.status(204).build(); + } +} diff --git a/opendaylight/northbound/networkconfiguration/neutron/src/main/java/org/opendaylight/controller/networkconfig/neutron/northbound/NeutronNorthboundRSApplication.java b/opendaylight/northbound/networkconfiguration/neutron/src/main/java/org/opendaylight/controller/networkconfig/neutron/northbound/NeutronNorthboundRSApplication.java index 3fe03a2dac..9abcca7c53 100644 --- a/opendaylight/northbound/networkconfiguration/neutron/src/main/java/org/opendaylight/controller/networkconfig/neutron/northbound/NeutronNorthboundRSApplication.java +++ b/opendaylight/northbound/networkconfiguration/neutron/src/main/java/org/opendaylight/controller/networkconfig/neutron/northbound/NeutronNorthboundRSApplication.java @@ -8,12 +8,13 @@ package org.opendaylight.controller.networkconfig.neutron.northbound; +import org.eclipse.persistence.jaxb.rs.MOXyJsonProvider; + +import javax.ws.rs.core.Application; import java.util.HashMap; import java.util.HashSet; import java.util.Map; import java.util.Set; -import javax.ws.rs.core.Application; -import org.eclipse.persistence.jaxb.rs.MOXyJsonProvider; /** @@ -34,6 +35,9 @@ public class NeutronNorthboundRSApplication extends Application { classes.add(NeutronFloatingIPsNorthbound.class); classes.add(NeutronSecurityGroupsNorthbound.class); classes.add(NeutronSecurityRulesNorthbound.class); + classes.add(NeutronFirewallNorthbound.class); + classes.add(NeutronFirewallPolicyNorthbound.class); + classes.add(NeutronFirewallRulesNorthbound.class); return classes; } diff --git a/opendaylight/topologymanager/implementation/pom.xml b/opendaylight/topologymanager/implementation/pom.xml index 196982b361..746135891e 100644 --- a/opendaylight/topologymanager/implementation/pom.xml +++ b/opendaylight/topologymanager/implementation/pom.xml @@ -44,6 +44,7 @@ org.apache.felix maven-bundle-plugin + ${bundle.plugin.version} true diff --git a/opendaylight/topologymanager/implementation/src/main/java/org/opendaylight/controller/topologymanager/ITopologyManagerShell.java b/opendaylight/topologymanager/implementation/src/main/java/org/opendaylight/controller/topologymanager/ITopologyManagerShell.java new file mode 100644 index 0000000000..22bd9c0512 --- /dev/null +++ b/opendaylight/topologymanager/implementation/src/main/java/org/opendaylight/controller/topologymanager/ITopologyManagerShell.java @@ -0,0 +1,17 @@ +/** +* Copyright (c) 2014 Inocybe Technologies, 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.topologymanager; + +import java.util.List; + +public interface ITopologyManagerShell { + public List printUserLink(); + public List addUserLink(String name, String ncStr1, String ncStr2); + public List deleteUserLinkShell(String name); + public List printNodeEdges(); +} diff --git a/opendaylight/topologymanager/implementation/src/main/java/org/opendaylight/controller/topologymanager/internal/Activator.java b/opendaylight/topologymanager/implementation/src/main/java/org/opendaylight/controller/topologymanager/internal/Activator.java index 4ccbb0197d..80d7083ec0 100644 --- a/opendaylight/topologymanager/implementation/src/main/java/org/opendaylight/controller/topologymanager/internal/Activator.java +++ b/opendaylight/topologymanager/implementation/src/main/java/org/opendaylight/controller/topologymanager/internal/Activator.java @@ -26,6 +26,7 @@ import org.opendaylight.controller.switchmanager.ISwitchManager; import org.opendaylight.controller.topologymanager.ITopologyManager; import org.opendaylight.controller.topologymanager.ITopologyManagerAware; import org.opendaylight.controller.topologymanager.ITopologyManagerClusterWideAware; +import org.opendaylight.controller.topologymanager.ITopologyManagerShell; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -73,6 +74,7 @@ public class Activator extends ComponentActivatorAbstractBase { c.setInterface(new String[] { IListenTopoUpdates.class.getName(), ITopologyManager.class.getName(), + ITopologyManagerShell.class.getName(), IConfigurationContainerAware.class.getName(), ICacheUpdateAware.class.getName() }, props); diff --git a/opendaylight/topologymanager/implementation/src/main/java/org/opendaylight/controller/topologymanager/internal/TopologyManagerImpl.java b/opendaylight/topologymanager/implementation/src/main/java/org/opendaylight/controller/topologymanager/internal/TopologyManagerImpl.java index ff1c026a34..b0e87c48f3 100644 --- a/opendaylight/topologymanager/implementation/src/main/java/org/opendaylight/controller/topologymanager/internal/TopologyManagerImpl.java +++ b/opendaylight/topologymanager/implementation/src/main/java/org/opendaylight/controller/topologymanager/internal/TopologyManagerImpl.java @@ -57,6 +57,7 @@ import org.opendaylight.controller.switchmanager.ISwitchManager; import org.opendaylight.controller.topologymanager.ITopologyManager; import org.opendaylight.controller.topologymanager.ITopologyManagerAware; import org.opendaylight.controller.topologymanager.ITopologyManagerClusterWideAware; +import org.opendaylight.controller.topologymanager.ITopologyManagerShell; import org.opendaylight.controller.topologymanager.TopologyUserLinkConfig; import org.osgi.framework.BundleContext; import org.osgi.framework.FrameworkUtil; @@ -71,6 +72,7 @@ import org.slf4j.LoggerFactory; public class TopologyManagerImpl implements ICacheUpdateAware, ITopologyManager, + ITopologyManagerShell, IConfigurationContainerAware, IListenTopoUpdates, IObjectReader, @@ -1010,4 +1012,82 @@ public class TopologyManagerImpl implements } } } + + public List printUserLink() { + List result = new ArrayList(); + for (String name : this.userLinksDB.keySet()) { + TopologyUserLinkConfig linkConfig = userLinksDB.get(name); + result.add("Name : " + name); + result.add(linkConfig.toString()); + result.add("Edge " + getLinkTuple(linkConfig)); + result.add("Reverse Edge " + getReverseLinkTuple(linkConfig)); + } + return result; + } + + public List addUserLink(String name, String ncStr1, String ncStr2) { + List result = new ArrayList(); + if ((name == null)) { + result.add("Please enter a valid Name"); + return result; + } + + if (ncStr1 == null) { + result.add("Please enter two node connector strings"); + return result; + } + if (ncStr2 == null) { + result.add("Please enter second node connector string"); + return result; + } + + NodeConnector nc1 = NodeConnector.fromString(ncStr1); + if (nc1 == null) { + result.add("Invalid input node connector 1 string: " + ncStr1); + return result; + } + NodeConnector nc2 = NodeConnector.fromString(ncStr2); + if (nc2 == null) { + result.add("Invalid input node connector 2 string: " + ncStr2); + return result; + } + + TopologyUserLinkConfig config = new TopologyUserLinkConfig(name, ncStr1, ncStr2); + result.add(this.addUserLink(config).toString()); + return result; + } + + public List deleteUserLinkShell(String name) { + List result = new ArrayList(); + if ((name == null)) { + result.add("Please enter a valid Name"); + return result; + } + this.deleteUserLink(name); + return result; + } + + public List printNodeEdges() { + List result = new ArrayList(); + Map> nodeEdges = getNodeEdges(); + if (nodeEdges == null) { + return result; + } + Set nodeSet = nodeEdges.keySet(); + if (nodeSet == null) { + return result; + } + result.add(" Node Edge"); + for (Node node : nodeSet) { + Set edgeSet = nodeEdges.get(node); + if (edgeSet == null) { + continue; + } + for (Edge edge : edgeSet) { + result.add(node + " " + edge); + } + } + return result; + } + } diff --git a/opendaylight/topologymanager/shell/pom.xml b/opendaylight/topologymanager/shell/pom.xml new file mode 100644 index 0000000000..078b55c596 --- /dev/null +++ b/opendaylight/topologymanager/shell/pom.xml @@ -0,0 +1,52 @@ + + + 4.0.0 + + org.opendaylight.controller + commons.opendaylight + 1.4.2-SNAPSHOT + ../../commons/opendaylight + + topologymanager.shell + ${topologymanager.shell.version} + bundle + + + junit + junit + + + org.apache.karaf.shell + org.apache.karaf.shell.console + ${karaf.shell.version} + + + org.mockito + mockito-all + + + org.opendaylight.controller + topologymanager + ${topologymanager.version} + + + + + + + org.apache.felix + maven-bundle-plugin + ${bundle.plugin.version} + + + org.apache.felix.service.command, + org.apache.karaf.shell.commands, + org.apache.karaf.shell.console, + * + + + + + + + diff --git a/opendaylight/topologymanager/shell/src/main/java/org/opendaylight/controller/topologymanager/shell/AddUserLink.java b/opendaylight/topologymanager/shell/src/main/java/org/opendaylight/controller/topologymanager/shell/AddUserLink.java new file mode 100644 index 0000000000..1565a8733b --- /dev/null +++ b/opendaylight/topologymanager/shell/src/main/java/org/opendaylight/controller/topologymanager/shell/AddUserLink.java @@ -0,0 +1,39 @@ +/** +* Copyright (c) 2014 Inocybe Technologies, 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.topologymanager.shell; + +import org.apache.felix.gogo.commands.Command; +import org.apache.felix.gogo.commands.Argument; +import org.apache.karaf.shell.console.OsgiCommandSupport; +import org.opendaylight.controller.topologymanager.ITopologyManagerShell; + +@Command(scope = "topologymanager", name = "addUserLink", description="Adds user link") +public class AddUserLink extends OsgiCommandSupport{ + private ITopologyManagerShell topologyManager; + + @Argument(index=0, name="name", description="name", required=true, multiValued=false) + String name = null; + + @Argument(index=1, name="ncStr1", description="ncStr1", required=true, multiValued=false) + String ncStr1 = null; + + @Argument(index=2, name="ncStr2", description="ncStr2", required=true, multiValued=false) + String ncStr2 = null; + + @Override + protected Object doExecute() throws Exception { + for(String p : topologyManager.addUserLink(name, ncStr1, ncStr2)) { + System.out.println(p); + } + return null; + } + + public void setTopologyManager(ITopologyManagerShell topologyManager){ + this.topologyManager = topologyManager; + } +} diff --git a/opendaylight/topologymanager/shell/src/main/java/org/opendaylight/controller/topologymanager/shell/DeleteUserLink.java b/opendaylight/topologymanager/shell/src/main/java/org/opendaylight/controller/topologymanager/shell/DeleteUserLink.java new file mode 100644 index 0000000000..b226c3c2e2 --- /dev/null +++ b/opendaylight/topologymanager/shell/src/main/java/org/opendaylight/controller/topologymanager/shell/DeleteUserLink.java @@ -0,0 +1,33 @@ +/** +* Copyright (c) 2014 Inocybe Technologies, 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.topologymanager.shell; + +import org.apache.felix.gogo.commands.Command; +import org.apache.felix.gogo.commands.Argument; +import org.apache.karaf.shell.console.OsgiCommandSupport; +import org.opendaylight.controller.topologymanager.ITopologyManagerShell; + +@Command(scope = "topologymanager", name = "deleteUserLink", description="deletes user link") +public class DeleteUserLink extends OsgiCommandSupport{ + private ITopologyManagerShell topologyManager; + + @Argument(index=0, name="name", description="name", required=true, multiValued=false) + String name = null; + + @Override + protected Object doExecute() throws Exception { + for(String p : topologyManager.deleteUserLinkShell(name)) { + System.out.println(p); + } + return null; + } + + public void setTopologyManager(ITopologyManagerShell topologyManager){ + this.topologyManager = topologyManager; + } +} diff --git a/opendaylight/topologymanager/shell/src/main/java/org/opendaylight/controller/topologymanager/shell/PrintNodeEdges.java b/opendaylight/topologymanager/shell/src/main/java/org/opendaylight/controller/topologymanager/shell/PrintNodeEdges.java new file mode 100644 index 0000000000..9c5e806b6d --- /dev/null +++ b/opendaylight/topologymanager/shell/src/main/java/org/opendaylight/controller/topologymanager/shell/PrintNodeEdges.java @@ -0,0 +1,29 @@ +/** +* Copyright (c) 2014 Inocybe Technologies, 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.topologymanager.shell; + +import org.apache.felix.gogo.commands.Command; +import org.apache.karaf.shell.console.OsgiCommandSupport; +import org.opendaylight.controller.topologymanager.ITopologyManagerShell; + +@Command(scope = "topologymanager", name = "printNodeEdges", description="Prints node edges") +public class PrintNodeEdges extends OsgiCommandSupport{ + private ITopologyManagerShell topologyManager; + + @Override + protected Object doExecute() throws Exception { + for(String p : topologyManager.printNodeEdges()) { + System.out.println(p); + } + return null; + } + + public void setTopologyManager(ITopologyManagerShell topologyManager){ + this.topologyManager = topologyManager; + } +} diff --git a/opendaylight/topologymanager/shell/src/main/java/org/opendaylight/controller/topologymanager/shell/PrintUserLink.java b/opendaylight/topologymanager/shell/src/main/java/org/opendaylight/controller/topologymanager/shell/PrintUserLink.java new file mode 100644 index 0000000000..df7ab35073 --- /dev/null +++ b/opendaylight/topologymanager/shell/src/main/java/org/opendaylight/controller/topologymanager/shell/PrintUserLink.java @@ -0,0 +1,29 @@ +/** +* Copyright (c) 2014 Inocybe Technologies, 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.topologymanager.shell; + +import org.apache.felix.gogo.commands.Command; +import org.apache.karaf.shell.console.OsgiCommandSupport; +import org.opendaylight.controller.topologymanager.ITopologyManagerShell; + +@Command(scope = "topologymanager", name = "printUserLink", description="Prints user link") +public class PrintUserLink extends OsgiCommandSupport{ + private ITopologyManagerShell topologyManager; + + @Override + protected Object doExecute() throws Exception { + for(String p : topologyManager.printUserLink()) { + System.out.println(p); + } + return null; + } + + public void setTopologyManager(ITopologyManagerShell topologyManager){ + this.topologyManager = topologyManager; + } +} diff --git a/opendaylight/topologymanager/shell/src/main/resources/OSGI-INF/blueprint/blueprint.xml b/opendaylight/topologymanager/shell/src/main/resources/OSGI-INF/blueprint/blueprint.xml new file mode 100644 index 0000000000..96b0b10f10 --- /dev/null +++ b/opendaylight/topologymanager/shell/src/main/resources/OSGI-INF/blueprint/blueprint.xml @@ -0,0 +1,33 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +