--- /dev/null
+<?xml version="1.0" encoding="UTF-8"?>
+<project>
+ <modelVersion>4.0.0</modelVersion>
+ <parent>
+ <groupId>org.opendaylight.controller</groupId>
+ <artifactId>commons.opendaylight</artifactId>
+ <version>1.4.2-SNAPSHOT</version>
+ <relativePath>../../opendaylight/commons/opendaylight</relativePath>
+ </parent>
+ <artifactId>base-features</artifactId>
+ <packaging>kar</packaging>
+ <name>${project.artifactId}</name>
+ <description>Base Features POM</description>
+ <properties>
+ <features.file>features.xml</features.file>
+ </properties>
+ <build>
+ <resources>
+ <resource>
+ <filtering>true</filtering>
+ <directory>src/main/resources</directory>
+ </resource>
+ </resources>
+ <plugins>
+ <plugin>
+ <groupId>org.apache.karaf.tooling</groupId>
+ <artifactId>karaf-maven-plugin</artifactId>
+ <version>${karaf.version}</version>
+ <extensions>true</extensions>
+ <executions>
+ <execution>
+ <id>features-create-kar</id>
+ <goals>
+ <goal>features-create-kar</goal>
+ </goals>
+ <configuration>
+ <featuresFile>${project.build.directory}/classes/${features.file}</featuresFile>
+ </configuration>
+ </execution>
+ </executions>
+ <!-- There is no useful configuration for the kar mojo. The features-generate-descriptor mojo configuration may be useful -->
+ </plugin>
+ <plugin>
+ <groupId>org.apache.maven.plugins</groupId>
+ <artifactId>maven-resources-plugin</artifactId>
+ <executions>
+ <execution>
+ <id>filter</id>
+ <goals>
+ <goal>resources</goal>
+ </goals>
+ <phase>generate-resources</phase>
+ </execution>
+ </executions>
+ </plugin>
+ <plugin>
+ <groupId>org.codehaus.mojo</groupId>
+ <artifactId>build-helper-maven-plugin</artifactId>
+ <executions>
+ <execution>
+ <id>attach-artifacts</id>
+ <goals>
+ <goal>attach-artifact</goal>
+ </goals>
+ <phase>package</phase>
+ <configuration>
+ <artifacts>
+ <artifact>
+ <file>${project.build.directory}/classes/${features.file}</file>
+ <type>xml</type>
+ <classifier>features</classifier>
+ </artifact>
+ </artifacts>
+ </configuration>
+ </execution>
+ </executions>
+ </plugin>
+ </plugins>
+ </build>
+</project>
--- /dev/null
+<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
+<features name="base-${project.version}" xmlns="http://karaf.apache.org/xmlns/features/v1.2.0"
+ xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+ xsi:schemaLocation="http://karaf.apache.org/xmlns/features/v1.2.0 http://karaf.apache.org/xmlns/features/v1.2.0">
+
+ <feature name="base-all" description="OpenDaylight Controller"
+ version="${project.version}">
+ <feature>http</feature>
+ <feature>transaction</feature>
+ <feature>base-felix-dm</feature>
+ <feature>base-aries-spi-fly</feature>
+ <feature>base-dummy-console</feature>
+ <feature>base-apache-commons</feature>
+ <feature>base-eclipselink-persistence</feature>
+ <feature>base-gemini-web</feature>
+ <feature>base-tomcat</feature>
+ <feature>base-netty</feature>
+ <feature>base-jersey</feature>
+ <feature>base-spring-security</feature>
+ </feature>
+ <feature name="base-dummy-console" description="Temporary Dummy Console" version="1.1.0-SNAPSHOT">
+ <bundle>mvn:org.opendaylight.controller/dummy-console/1.1.0-SNAPSHOT</bundle>
+ </feature>
+ <feature name="base-felix-dm" description="Felix Dependency Manager"
+ version="${felix.dependencymanager.version}">
+ <bundle start-level="35">mvn:org.osgi/org.osgi.compendium/${osgi.compendium.version}</bundle>
+ <bundle start-level="35">mvn:org.apache.felix/org.apache.felix.dependencymanager/${felix.dependencymanager.version}</bundle>
+ <bundle start-level="35">mvn:org.apache.felix/org.apache.felix.dependencymanager.shell/${felix.dependencymanager.shell.version}</bundle>
+ </feature>
+ <feature name="base-aries-spi-fly" description="Aries SPI Fly"
+ version="${spifly.version}">
+ <bundle start-level="35">mvn:org.apache.aries/org.apache.aries.util/1.1.0</bundle>
+ <bundle start-level="35">mvn:org.apache.aries.spifly/org.apache.aries.spifly.dynamic.bundle/${spifly.version}</bundle>
+ <bundle start-level="35">mvn:org.ow2.asm/asm-all/4.0</bundle>
+ </feature>
+ <feature name='base-netty' version='${netty.version}'>
+ <bundle>wrap:mvn:io.netty/netty-buffer/${netty.version}</bundle>
+ <bundle>wrap:mvn:io.netty/netty-codec/${netty.version}</bundle>
+ <bundle>wrap:mvn:io.netty/netty-transport/${netty.version}</bundle>
+ <bundle>wrap:mvn:io.netty/netty-common/${netty.version}</bundle>
+ <bundle>wrap:mvn:io.netty/netty-handler/${netty.version}</bundle>
+ <bundle>wrap:mvn:io.netty/netty-codec-http/${netty.version}</bundle>
+ <bundle>mvn:org.opendaylight.controller.thirdparty/ganymed/1.1-SNAPSHOT</bundle>
+ </feature>
+ <feature name="base-jersey" description="Jersey" version="${jersey.version}">
+ <feature>base-gemini-web</feature>
+ <bundle>mvn:org.opendaylight.controller.thirdparty/com.sun.jersey.jersey-servlet/${jersey.version}</bundle>
+ <bundle>mvn:com.sun.jersey/jersey-server/${jersey.version}</bundle>
+ <bundle>mvn:com.sun.jersey/jersey-core/${jersey.version}</bundle>
+ <bundle>mvn:com.sun.jersey/jersey-client/${jersey.version}</bundle>
+ <bundle>mvn:com.sun.jersey/jersey-servlet/${jersey.version}</bundle>
+ </feature>
+ <feature name="base-jackson" description="Jackson JAX-RS" version="${jackson.version}">
+ <bundle start="true" start-level="35">mvn:com.fasterxml.jackson.core/jackson-annotations/${jackson.version}</bundle>
+ <bundle start="true" start-level="35">mvn:com.fasterxml.jackson.core/jackson-core/${jackson.version}</bundle>
+ <bundle start="true" start-level="35">mvn:com.fasterxml.jackson.core/jackson-databind/${jackson.version}</bundle>
+ <bundle start="true" start-level="35">mvn:org.codehaus.jettison/jettison/${jettison.version}</bundle>
+ <bundle start="true" start-level="35">mvn:javax.ws.rs/jsr311-api/${jsr311.api.version}</bundle>
+ <bundle start="true" start-level="35">mvn:com.fasterxml.jackson.module/jackson-module-jaxb-annotations/${jackson.version}</bundle>
+ <bundle start="true" start-level="35">mvn:com.fasterxml.jackson.jaxrs/jackson-jaxrs-base/${jackson.version}</bundle>
+ <bundle start="true" start-level="35">mvn:com.fasterxml.jackson.jaxrs/jackson-jaxrs-json-provider/${jackson.version}</bundle>
+ </feature>
+ <feature name="base-slf4j" description="SLF4J Logging" version="${slf4j.version}">
+ <bundle start-level="35">mvn:org.slf4j/slf4j-jdk14/1.7.2</bundle>
+ <bundle start-level="35">mvn:org.slf4j/slf4j-nop/1.7.2</bundle>
+ <bundle start-level="35">mvn:org.slf4j/slf4j-simple/1.7.2</bundle>
+ <bundle start="true" start-level="35">mvn:org.slf4j/slf4j-api/1.7.2</bundle>
+ </feature>
+ <feature name="base-apache-commons" description="Apache Commons Libraries"
+ version="${project.version}">
+ <bundle start="true" start-level="35">mvn:com.google.guava/guava/${guava.version}</bundle>
+ <bundle start="true" start-level="35">mvn:org.javassist/javassist/${javassist.version}</bundle>
+ <bundle start="true" start-level="35">mvn:commons-io/commons-io/${commons.io.version}</bundle>
+ <bundle start="true" start-level="35">mvn:commons-codec/commons-codec/${commons.codec.version}</bundle>
+ <bundle start="true" start-level="35">mvn:org.apache.commons/commons-lang3/${commons.lang.version}</bundle>
+ <bundle start="true" start-level="35">mvn:commons-net/commons-net/${commons.net.version}</bundle>
+ </feature>
+ <feature name="base-eclipselink-persistence" description="EclipseLink Persistence API" version="2.0.4.v201112161009">
+ <bundle start="true" start-level="35">mvn:eclipselink/javax.persistence/2.0.4.v201112161009</bundle>
+ <bundle start="true" start-level="35">mvn:eclipselink/javax.resource/1.5.0.v200906010428</bundle>
+ </feature>
+ <feature name="base-gemini-web" description="Gemini Web" version="${geminiweb.version}">
+ <feature>http</feature>
+ <feature>transaction</feature>
+ <feature>base-slf4j</feature>
+ <feature>base-felix-dm</feature>
+ <feature>base-jackson</feature>
+ <feature>base-apache-commons</feature>
+ <bundle start="true" start-level="35">mvn:com.google.code.gson/gson/${gson.version}</bundle>
+ <bundle start="true" start-level="35">mvn:commons-fileupload/commons-fileupload/${commons.fileupload.version}</bundle>
+ <bundle start="true" start-level="35">mvn:geminiweb/org.eclipse.gemini.web.core/${geminiweb.version}</bundle>
+ <bundle start="true" start-level="35">mvn:geminiweb/org.eclipse.gemini.web.extender/${geminiweb.version}</bundle>
+ <bundle start="true" start-level="35">mvn:geminiweb/org.eclipse.virgo.util.common/${virgo.version}</bundle>
+ <bundle start="true" start-level="35">mvn:geminiweb/org.eclipse.virgo.util.io/${virgo.version}</bundle>
+ <bundle start="true" start-level="35">mvn:geminiweb/org.eclipse.virgo.util.math/${virgo.version}</bundle>
+ <bundle start="true" start-level="35">mvn:geminiweb/org.eclipse.virgo.util.osgi/${virgo.version}</bundle>
+ <bundle start="true" start-level="35">mvn:geminiweb/org.eclipse.virgo.util.osgi.manifest/${virgo.version}</bundle>
+ <bundle start="true" start-level="35">mvn:geminiweb/org.eclipse.virgo.util.parser.manifest/${virgo.version}</bundle>
+ <bundle start="true" start-level="35">mvn:org.apache.felix/org.apache.felix.fileinstall/3.1.6</bundle>
+ <bundle start="true" start-level="35">mvn:orbit/javax.activation/1.1.0.v201211130549</bundle>
+ <bundle start="true" start-level="35">mvn:orbit/javax.annotation/1.1.0.v201209060031</bundle>
+ <bundle start="true" start-level="35">mvn:orbit/javax.ejb/3.1.1.v201204261316</bundle>
+ <bundle start="true" start-level="35">mvn:orbit/javax.el/2.2.0.v201108011116</bundle>
+ <bundle start="true" start-level="35">mvn:orbit/javax.mail.glassfish/1.4.1.v201108011116</bundle>
+ <bundle start="true" start-level="35">mvn:orbit/javax.xml.rpc/1.1.0.v201005080400</bundle>
+ <bundle start="true" start-level="35">mvn:org.eclipse.jetty.orbit/javax.servlet.jsp/2.2.0.v201112011158</bundle>
+ <bundle start="true" start-level="35">mvn:orbit/javax.servlet.jsp.jstl/1.2.0.v201105211821</bundle>
+ <bundle start="true" start-level="35">mvn:orbit/javax.servlet.jsp.jstl.impl/1.2.0.v201210211230</bundle>
+ </feature>
+ <feature name="base-tomcat" description="OpenDaylight Tomcat" version="7.0.32">
+ <feature>base-gemini-web</feature>
+ <feature>base-eclipselink-persistence</feature>
+ <bundle start="true" start-level="35">mvn:orbit/org.apache.catalina/7.0.32.v201211201336</bundle>
+ <bundle start="true" start-level="35">mvn:geminiweb/org.eclipse.gemini.web.tomcat/${geminiweb.version}</bundle>
+ <bundle start="true" start-level="35">mvn:orbit/org.apache.catalina.ha/7.0.32.v201211201952</bundle>
+ <bundle start="true" start-level="35">mvn:orbit/org.apache.catalina.tribes/7.0.32.v201211201952</bundle>
+ <bundle start="true" start-level="35">mvn:orbit/org.apache.coyote/7.0.32.v201211201952</bundle>
+ <bundle start="true" start-level="35">mvn:orbit/org.apache.el/7.0.32.v201211081135</bundle>
+ <bundle start="true" start-level="35">mvn:orbit/org.apache.jasper/7.0.32.v201211201952</bundle>
+ <bundle start="true" start-level="35">mvn:orbit/org.apache.juli.extras/7.0.32.v201211081135</bundle>
+ <bundle start="true" start-level="35">mvn:orbit/org.apache.tomcat.api/7.0.32.v201211081135</bundle>
+ <bundle start="true" start-level="35">mvn:orbit/org.apache.tomcat.util/7.0.32.v201211201952</bundle>
+ <bundle start="true" start-level="35">wrap:mvn:virgomirror/org.eclipse.jdt.core.compiler.batch/3.8.0.I20120518-2145</bundle>
+ </feature>
+ <feature name="base-spring" description="Opendaylight Spring Support" version="${spring.version}">
+ <bundle>mvn:org.ow2.asm/asm-all/${asm.version}</bundle>
+ <bundle>mvn:org.aopalliance/com.springsource.org.aopalliance/${aopalliance.version}</bundle>
+ <bundle>mvn:org.springframework/org.springframework.aop/${spring.version}</bundle>
+ <bundle>mvn:org.springframework/org.springframework.asm/${spring.version}</bundle>
+ <bundle>mvn:org.springframework/org.springframework.beans/${spring.version}</bundle>
+ <bundle>mvn:org.springframework/org.springframework.context/${spring.version}</bundle>
+ <bundle>mvn:org.springframework/org.springframework.context.support/${spring.version}</bundle>
+ <bundle>mvn:org.springframework/org.springframework.core/${spring.version}</bundle>
+ <bundle>mvn:org.springframework/org.springframework.expression/${spring.version}</bundle>
+ <bundle>mvn:org.springframework/org.springframework.transaction/${spring.version}</bundle>
+ </feature>
+ <feature name="base-spring-web" description="OpenDaylight Spring Web" version="${spring.version}">
+ <feature>base-spring</feature>
+ <feature>base-gemini-web</feature>
+ <bundle>mvn:org.springframework/org.springframework.web/${spring.version}</bundle>
+ <bundle>mvn:org.springframework/org.springframework.web.servlet/${spring.version}</bundle>
+ </feature>
+ <feature name="base-spring-security" description="OpenDaylight Spring Security" version="${spring-security.version}">
+ <feature>base-spring-web</feature>
+ <bundle>mvn:org.springframework.security/spring-security-config/${spring-security.version}</bundle>
+ <bundle>mvn:org.springframework.security/spring-security-core/${spring-security.version}</bundle>
+ <bundle>mvn:org.springframework.security/spring-security-taglibs/${spring-security.version}</bundle>
+ <bundle>mvn:org.springframework.security/spring-security-web/${spring-security.version}</bundle>
+ </feature>
+</features>
<appauth.version>0.4.2-SNAPSHOT</appauth.version>
<!-- Controller Modules Versions -->
<arphandler.version>0.5.2-SNAPSHOT</arphandler.version>
+ <aries.util.version>1.1.0</aries.util.version>
<asm.version>4.1</asm.version>
<!-- Plugin Versions -->
<bouncycastle.version>1.50</bouncycastle.version>
*/
package org.opendaylight.controller.config.api;
+import javax.management.AttributeNotFoundException;
+import javax.management.InstanceNotFoundException;
+import javax.management.MBeanException;
+import javax.management.ObjectName;
+import javax.management.ReflectionException;
import org.opendaylight.controller.config.api.annotations.AbstractServiceInterface;
import org.opendaylight.yangtools.concepts.Identifiable;
import org.opendaylight.yangtools.yang.binding.BaseIdentity;
-import javax.management.ObjectName;
-
/**
* Each new {@link org.opendaylight.controller.config.spi.Module} can receive
* resolver from {@link org.opendaylight.controller.config.spi.ModuleFactory}
* To be used during validation phase to validate serice interface of
* dependent module.
*
- * @param expectedServiceInterface
- * MBean/MXBean interface which will back the proxy object.
- * @param objectName
- * ObjectName of dependent module without transaction name
- * (platformON).
- * @param jmxAttribute
- * @throws {@link IllegalArgumentException} when module is not found
- * @throws {@link IllegalStateException} if module does not export this
- * service interface.
+ * @param expectedServiceInterface MBean/MXBean interface which will back the proxy object.
+ * @param objectName ObjectName of dependent module without transaction name
+ * (platformON).
+ * @param jmxAttribute for reporting
+ * @throws IllegalArgumentException when module is not found
+ * @throws IllegalStateException if module does not export this
+ * service interface.
*/
void validateDependency(
Class<? extends AbstractServiceInterface> expectedServiceInterface,
* To be used during commit phase to wire actual dependencies.
*
* @return dependency instance using
- * {@link org.opendaylight.controller.config.spi.Module#getInstance()}
- * @throws {@link IllegalArgumentException} when module is not found
+ * {@link org.opendaylight.controller.config.spi.Module#getInstance()}
+ * @throws IllegalArgumentException when module is not found
*/
<T> T resolveInstance(Class<T> expectedType, ObjectName objectName,
- JmxAttribute jmxAttribute);
-
- // TODO finish javadoc
+ JmxAttribute jmxAttribute);
/**
* To be used during commit phase to resolve identity-ref config attributes.
*/
<T extends BaseIdentity> Class<? extends T> resolveIdentity(IdentityAttributeRef identityRef, Class<T> expectedBaseClass);
+
+ /**
+ * Validate identity-ref config attribute.
+ */
<T extends BaseIdentity> void validateIdentity(IdentityAttributeRef identityRef, Class<T> expectedBaseClass, JmxAttribute jmxAttribute);
+ /**
+ * Can be used during validation or commit phase to get attribute value of dependent module.
+ *
+ * @param name either direct ObjectName of a Module (type=Module) or service reference (type=ServiceReference) of dependent Module
+ * @param attribute String identifying attribute name in JMX. Note that attributes start with upper case. See {@link org.opendaylight.controller.config.api.JmxAttribute#getAttributeName()}
+ */
+ Object getAttribute(ObjectName name, String attribute)
+ throws MBeanException, AttributeNotFoundException,
+ InstanceNotFoundException, ReflectionException;
+
+
+ /**
+ * Helper method around {@link javax.management.JMX#newMXBeanProxy(javax.management.MBeanServerConnection, javax.management.ObjectName, Class)} }.
+ * Returns MXBean proxy for dependent module. Can be used during validation or commit phase to inspect dependent module's attributes.
+ *
+ * @param objectName either direct ObjectName of a Module (type=Module) or service reference (type=ServiceReference) of dependent Module
+ * @param interfaceClass MXBean interface to be used as a proxy
+ * @param <T> type of proxy for type safe return value
+ * @return instance of MXBean proxy
+ */
+ <T> T newMXBeanProxy(ObjectName objectName, Class<T> interfaceClass);
+
}
this.attributeName = attributeName;
}
+ /**
+ * Name of attribute in JMX.
+ */
public String getAttributeName() {
return attributeName;
}
*/
package org.opendaylight.controller.config.manager.impl;
+import static com.google.common.base.Preconditions.checkNotNull;
import static java.lang.String.format;
import java.util.ArrayList;
import org.osgi.framework.BundleContext;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
-
-import static com.google.common.base.Preconditions.checkNotNull;
/**
* This is a JMX bean representing current transaction. It contains
* transaction identifier, unique version and parent version for
this.factoriesHolder = new HierarchicalConfigMBeanFactoriesHolder(currentlyRegisteredFactories);
this.transactionStatus = new TransactionStatus();
this.dependencyResolverManager = new DependencyResolverManager(txLookupRegistry.getTransactionIdentifier(),
- transactionStatus, writableSRRegistry, codecRegistry);
+ transactionStatus, writableSRRegistry, codecRegistry, transactionsMBeanServer);
this.transactionsMBeanServer = transactionsMBeanServer;
this.configMBeanServer = configMBeanServer;
this.blankTransaction = blankTransaction;
*/
package org.opendaylight.controller.config.manager.impl.dependencyresolver;
+import static java.lang.String.format;
+
+import java.util.HashSet;
+import java.util.LinkedHashSet;
+import java.util.Set;
+import javax.annotation.concurrent.GuardedBy;
+import javax.management.AttributeNotFoundException;
+import javax.management.InstanceNotFoundException;
+import javax.management.JMX;
+import javax.management.MBeanException;
+import javax.management.MBeanServer;
+import javax.management.ObjectName;
+import javax.management.ReflectionException;
import org.opendaylight.controller.config.api.DependencyResolver;
import org.opendaylight.controller.config.api.IdentityAttributeRef;
import org.opendaylight.controller.config.api.JmxAttribute;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
-import javax.annotation.concurrent.GuardedBy;
-import javax.management.ObjectName;
-import java.util.HashSet;
-import java.util.LinkedHashSet;
-import java.util.Set;
-
-import static java.lang.String.format;
-
/**
* Protect {@link org.opendaylight.controller.config.spi.Module#getInstance()}
* by creating proxy that would throw exception if those methods are called
private final Set<ModuleIdentifier> dependencies = new HashSet<>();
private final ServiceReferenceReadableRegistry readableRegistry;
private final CodecRegistry codecRegistry;
+ private final String transactionName;
+ private final MBeanServer mBeanServer;
DependencyResolverImpl(ModuleIdentifier currentModule,
TransactionStatus transactionStatus, ModulesHolder modulesHolder,
- ServiceReferenceReadableRegistry readableRegistry, CodecRegistry codecRegistry) {
+ ServiceReferenceReadableRegistry readableRegistry, CodecRegistry codecRegistry,
+ String transactionName, MBeanServer mBeanServer) {
this.codecRegistry = codecRegistry;
this.name = currentModule;
this.transactionStatus = transactionStatus;
this.modulesHolder = modulesHolder;
this.readableRegistry = readableRegistry;
+ this.transactionName = transactionName;
+ this.mBeanServer = mBeanServer;
}
/**
JmxAttributeValidationException.checkNotNull(dependentReadOnlyON,
"is null, expected dependency implementing "
- + expectedServiceInterface, jmxAttribute);
+ + expectedServiceInterface, jmxAttribute
+ );
// check that objectName belongs to this transaction - this should be
JmxAttributeValidationException.checkCondition(
hasTransaction == false,
format("ObjectName should not contain "
- + "transaction name. %s set to %s. ", jmxAttribute,
- dependentReadOnlyON), jmxAttribute);
+ + "transaction name. %s set to %s. ", jmxAttribute,
+ dependentReadOnlyON
+ ), jmxAttribute
+ );
dependentReadOnlyON = translateServiceRefIfPossible(dependentReadOnlyON);
+ "attribute %s",
foundFactory.getImplementationName(), foundFactory,
expectedServiceInterface, dependentReadOnlyON,
- jmxAttribute);
+ jmxAttribute
+ );
throw new JmxAttributeValidationException(message, jmxAttribute);
}
synchronized (this) {
String message = format(
"Error while %s resolving instance %s. getInstance() returned null. "
+ "Expected type %s , attribute %s", name,
- dependentModuleIdentifier, expectedType, jmxAttribute);
+ dependentModuleIdentifier, expectedType, jmxAttribute
+ );
throw new JmxAttributeValidationException(message, jmxAttribute);
}
try {
String message = format(
"Instance cannot be cast to expected type. Instance class is %s , "
+ "expected type %s , attribute %s",
- instance.getClass(), expectedType, jmxAttribute);
+ instance.getClass(), expectedType, jmxAttribute
+ );
throw new JmxAttributeValidationException(message, e, jmxAttribute);
}
}
return name;
}
+ @Override
+ public Object getAttribute(ObjectName name, String attribute)
+ throws MBeanException, AttributeNotFoundException, InstanceNotFoundException, ReflectionException {
+ name = translateServiceRefIfPossible(name);
+ // add transaction name
+ name = ObjectNameUtil.withTransactionName(name, transactionName);
+ return mBeanServer.getAttribute(name, attribute);
+ }
+
+ @Override
+ public <T> T newMXBeanProxy(ObjectName name, Class<T> interfaceClass) {
+ name = translateServiceRefIfPossible(name);
+ // add transaction name
+ name = ObjectNameUtil.withTransactionName(name, transactionName);
+ return JMX.newMXBeanProxy(mBeanServer, name, interfaceClass);
+ }
}
import java.util.Map;
import javax.annotation.concurrent.GuardedBy;
import javax.management.InstanceAlreadyExistsException;
+import javax.management.MBeanServer;
import org.opendaylight.controller.config.api.DependencyResolver;
import org.opendaylight.controller.config.api.DependencyResolverFactory;
import org.opendaylight.controller.config.api.JmxAttribute;
public class DependencyResolverManager implements DependencyResolverFactory, AutoCloseable {
@GuardedBy("this")
private final Map<ModuleIdentifier, DependencyResolverImpl> moduleIdentifiersToDependencyResolverMap = new HashMap<>();
+ private final TransactionIdentifier transactionIdentifier;
private final ModulesHolder modulesHolder;
private final TransactionStatus transactionStatus;
private final ServiceReferenceReadableRegistry readableRegistry;
private final CodecRegistry codecRegistry;
private final DeadlockMonitor deadlockMonitor;
+ private final MBeanServer mBeanServer;
public DependencyResolverManager(TransactionIdentifier transactionIdentifier,
- TransactionStatus transactionStatus, ServiceReferenceReadableRegistry readableRegistry, CodecRegistry codecRegistry) {
+ TransactionStatus transactionStatus,
+ ServiceReferenceReadableRegistry readableRegistry, CodecRegistry codecRegistry,
+ MBeanServer mBeanServer) {
+ this.transactionIdentifier = transactionIdentifier;
this.modulesHolder = new ModulesHolder(transactionIdentifier);
this.transactionStatus = transactionStatus;
this.readableRegistry = readableRegistry;
this.codecRegistry = codecRegistry;
this.deadlockMonitor = new DeadlockMonitor(transactionIdentifier);
+ this.mBeanServer = mBeanServer;
}
@Override
DependencyResolverImpl dependencyResolver = moduleIdentifiersToDependencyResolverMap.get(name);
if (dependencyResolver == null) {
transactionStatus.checkNotCommitted();
- dependencyResolver = new DependencyResolverImpl(name, transactionStatus, modulesHolder, readableRegistry, codecRegistry);
+ dependencyResolver = new DependencyResolverImpl(name, transactionStatus, modulesHolder, readableRegistry,
+ codecRegistry, transactionIdentifier.getName(), mBeanServer);
moduleIdentifiersToDependencyResolverMap.put(name, dependencyResolver);
}
return dependencyResolver;
import org.opendaylight.controller.config.api.ModuleIdentifier;
import org.opendaylight.controller.config.api.ServiceReferenceReadableRegistry;
import org.opendaylight.controller.config.api.jmx.ObjectNameUtil;
+import org.opendaylight.controller.config.manager.impl.AbstractLockedPlatformMBeanServerTest;
import org.opendaylight.controller.config.manager.impl.ModuleInternalInfo;
import org.opendaylight.controller.config.manager.impl.TransactionIdentifier;
import org.opendaylight.controller.config.manager.impl.TransactionStatus;
import org.opendaylight.controller.config.spi.ModuleFactory;
import org.osgi.framework.BundleContext;
-public class DependencyResolverManagerTest {
+public class DependencyResolverManagerTest extends AbstractLockedPlatformMBeanServerTest {
final ModuleIdentifier apspName = new ModuleIdentifier("apsp", "apsp"); // depends
// on:
public void setUp() {
transactionStatus = mock(TransactionStatus.class);
ServiceReferenceReadableRegistry mockedRegistry = mock(ServiceReferenceReadableRegistry.class);
- tested = new DependencyResolverManager(new TransactionIdentifier("txName"), transactionStatus, mockedRegistry, null);
+ tested = new DependencyResolverManager(new TransactionIdentifier("txName"), transactionStatus, mockedRegistry,
+ null, platformMBeanServer);
doNothing().when(transactionStatus).checkCommitStarted();
doNothing().when(transactionStatus).checkNotCommitted();
}
*/
package org.opendaylight.controller.config.manager.testingservices.parallelapsp;
+import static com.google.common.base.Preconditions.checkNotNull;
+import static com.google.common.base.Preconditions.checkState;
+
import com.google.common.base.Strings;
+import java.io.Closeable;
+import javax.annotation.Nullable;
+import javax.annotation.concurrent.NotThreadSafe;
+import javax.management.ObjectName;
import org.opendaylight.controller.config.api.DependencyResolver;
import org.opendaylight.controller.config.api.JmxAttribute;
import org.opendaylight.controller.config.api.ModuleIdentifier;
import org.opendaylight.controller.config.api.annotations.RequireInterface;
import org.opendaylight.controller.config.manager.testingservices.seviceinterface.TestingThreadPoolServiceInterface;
+import org.opendaylight.controller.config.manager.testingservices.threadpool.TestingThreadPoolConfigMXBean;
import org.opendaylight.controller.config.manager.testingservices.threadpool.TestingThreadPoolIfc;
import org.opendaylight.controller.config.spi.Module;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
-import javax.annotation.Nullable;
-import javax.annotation.concurrent.NotThreadSafe;
-import javax.management.ObjectName;
-import java.io.Closeable;
-
-import static com.google.common.base.Preconditions.checkNotNull;
-import static com.google.common.base.Preconditions.checkState;
-
/**
* Represents service that has dependency to thread pool.
*/
checkState("Commit was not triggered".equals(e.getMessage()),
e.getMessage());
}
+
+ // test retrieving dependent module's attribute
+ int threadCount;
+ try {
+ threadCount = (Integer)dependencyResolver.getAttribute(threadPoolON, "ThreadCount");
+ } catch (Exception e) {
+ throw new IllegalStateException(e);
+ }
+ checkState(threadCount > 0);
+ TestingThreadPoolConfigMXBean proxy = dependencyResolver.newMXBeanProxy(threadPoolON, TestingThreadPoolConfigMXBean.class);
+ checkState(threadCount == proxy.getThreadCount());
}
@Override
*/
package org.opendaylight.controller.config.manager.testingservices.parallelapsp.test;
+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;
import org.opendaylight.controller.config.manager.testingservices.parallelapsp.TestingParallelAPSPConfigMXBean;
import org.opendaylight.controller.config.manager.testingservices.parallelapsp.TestingParallelAPSPImpl;
import org.opendaylight.controller.config.manager.testingservices.parallelapsp.TestingParallelAPSPModuleFactory;
+import org.opendaylight.controller.config.manager.testingservices.seviceinterface.TestingThreadPoolServiceInterface;
import org.opendaylight.controller.config.manager.testingservices.threadpool.TestingFixedThreadPool;
import org.opendaylight.controller.config.manager.testingservices.threadpool.TestingFixedThreadPoolConfigMXBean;
import org.opendaylight.controller.config.manager.testingservices.threadpool.TestingFixedThreadPoolModuleFactory;
import org.opendaylight.controller.config.util.ConfigTransactionJMXClient;
-import javax.management.ObjectName;
-import java.util.Map;
-
-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;
-
public class DependentWiringTest extends AbstractParallelAPSPTest {
private final String fixed1 = "fixed1";
private final String apsp1 = "apsp-parallel";
parallelAPSPRuntimeProxy.getMaxNumberOfThreads());
}
+
+ @Test
+ public void testUsingServiceReferences() throws Exception {
+ ConfigTransactionJMXClient transaction = configRegistryClient.createTransaction();
+ ObjectName threadPoolON = createFixed1(transaction, 10);
+ transaction.lookupConfigBean(getThreadPoolImplementationName(), fixed1);
+ String refName = "ref";
+ ObjectName serviceReferenceON = transaction.saveServiceReference(TestingThreadPoolServiceInterface.QNAME, refName,
+ threadPoolON);
+ createParallelAPSP(transaction, serviceReferenceON);
+ transaction.commit();
+
+ }
}
<!-- scope is runtime so the feature repo is listed in the features
service config file, and features may be installed using the
karaf-maven-plugin configuration -->
- <!-- dependencies commented out till we can get them in
<dependency>
<groupId>org.apache.karaf.features</groupId>
<artifactId>standard</artifactId>
<scope>runtime</scope>
</dependency>
<dependency>
+ <!-- scope is compile so all features (there is only one) are installed
+ into startup.properties and the feature repo itself is not installed -->
+ <groupId>org.opendaylight.controller</groupId>
+ <artifactId>base-features</artifactId>
+ <version>${project.version}</version>
+ <type>kar</type>
+ <scope>runtime</scope>
+ </dependency>
+ <!--<dependency>
+ <groupId>org.opendaylight.controller</groupId>
+ <artifactId>base-features</artifactId>
+ <version>${project.version}</version>
+ <classifier>features</classifier>
+ <type>xml</type>
+ <scope>runtime</scope>
+ </dependency>-->
+ <!-- <dependency>
<groupId>org.opendaylight.controller</groupId>
<artifactId>controller-features</artifactId>
<version>${project.version}</version>
#Hosttracker hostsdb key scheme setting
hosttracker.keyscheme=IP
+
+# LISP Flow Mapping configuration
+# Map-Register messages overwrite existing RLOC sets in EID-to-RLOC mappings
+lisp.mappingOverwrite = true
+# Enable the Solicit-Map-Request (SMR) mechanism
+lisp.smr = false
<data xmlns="urn:ietf:params:xml:ns:netconf:base:1.0">
<modules xmlns="urn:opendaylight:params:xml:ns:yang:controller:config">
<module>
- <type xmlns:prefix="urn:opendaylight:params:xml:ns:yang:controller:config:toaster-provider:impl">
- prefix:toaster-provider-impl
+ <type xmlns:toaster="urn:opendaylight:params:xml:ns:yang:controller:config:toaster-provider:impl">
+ toaster:toaster-provider-impl
</type>
<name>toaster-provider-impl</name>
<name>binding-rpc-broker</name>
</rpc-registry>
+ <data-broker>
+ <type xmlns:binding="urn:opendaylight:params:xml:ns:yang:controller:md:sal:binding">binding:binding-data-broker</type>
+ <name>binding-data-broker</name>
+ </data-broker>
+
<notification-service>
<type xmlns:binding="urn:opendaylight:params:xml:ns:yang:controller:md:sal:binding">
binding:binding-notification-service
</module>
<module>
- <type xmlns:prefix="urn:opendaylight:params:xml:ns:yang:controller:config:toaster-consumer:impl">
- prefix:toaster-consumer-impl
+ <type xmlns:kitchen="urn:opendaylight:params:xml:ns:yang:controller:config:kitchen-service:impl">
+ kitchen:kitchen-service-impl
</type>
- <name>toaster-consumer-impl</name>
+ <name>kitchen-service-impl</name>
<rpc-registry>
<type xmlns:binding="urn:opendaylight:params:xml:ns:yang:controller:md:sal:binding">binding:binding-rpc-registry</type>
</notification-service>
</module>
</modules>
-
+
<services xmlns="urn:opendaylight:params:xml:ns:yang:controller:config">
<service>
- <type xmlns:toaster="urn:opendaylight:params:xml:ns:yang:controller:config:toaster-provider">toaster:toaster-provider</type>
- <instance>
- <name>toaster-provider</name>
- <provider>/modules/module[type='toaster-provider-impl'][name='toaster-provider-impl']</provider>
- </instance>
- </service>
- <service>
- <type xmlns:toaster="urn:opendaylight:params:xml:ns:yang:controller:config:toaster-consumer">toaster:toaster-consumer</type>
+ <type xmlns:kitchen="urn:opendaylight:params:xml:ns:yang:controller:config:kitchen-service:impl">
+ kitchen:kitchen-service
+ </type>
<instance>
- <name>toaster-consumer</name>
- <provider>/modules/module[type='toaster-consumer-impl'][name='toaster-consumer-impl']</provider>
+ <name>kitchen-service</name>
+ <provider>/modules/module[type='kitchen-service-impl'][name='kitchen-service-impl']</provider>
</instance>
</service>
</services>
</configuration>
<required-capabilities>
- <capability>urn:opendaylight:params:xml:ns:yang:controller:md:sal:binding?module=opendaylight-md-sal-binding&revision=2013-10-28</capability>
- <capability>urn:opendaylight:params:xml:ns:yang:controller:config:toaster-consumer?module=toaster-consumer&revision=2014-01-31</capability>
- <capability>urn:opendaylight:params:xml:ns:yang:controller:config:toaster-consumer:impl?module=toaster-consumer-impl&revision=2014-01-31</capability>
- <capability>urn:opendaylight:params:xml:ns:yang:controller:config:toaster-provider?module=toaster-provider&revision=2014-01-31</capability>
+ <capability>urn:opendaylight:params:xml:ns:yang:controller:config:kitchen-service:impl?module=kitchen-service-impl&revision=2014-01-31</capability>
<capability>urn:opendaylight:params:xml:ns:yang:controller:config:toaster-provider:impl?module=toaster-provider-impl&revision=2014-01-31</capability>
</required-capabilities>
+++ /dev/null
-<?xml version="1.0" encoding="UTF-8"?>
-<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
- xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
- <modelVersion>4.0.0</modelVersion>
- <parent>
- <groupId>org.opendaylight.controller</groupId>
- <artifactId>sal-parent</artifactId>
- <version>1.1-SNAPSHOT</version>
- <relativePath>../..</relativePath>
- </parent>
- <scm>
- <connection>scm:git:ssh://git.opendaylight.org:29418/controller.git</connection>
- <developerConnection>scm:git:ssh://git.opendaylight.org:29418/controller.git</developerConnection>
- <url>https://wiki.opendaylight.org/view/OpenDaylight_Controller:Main</url>
- <tag>HEAD</tag>
- </scm>
-
- <artifactId>clustered-datastore-implementation</artifactId>
- <version>0.4.1-SNAPSHOT</version>
- <packaging>bundle</packaging>
-
- <build>
- <plugins>
- <plugin>
- <groupId>org.apache.felix</groupId>
- <artifactId>maven-bundle-plugin</artifactId>
- <extensions>true</extensions>
- <configuration>
- <instructions>
- </instructions>
- <manifestLocation>${project.basedir}/META-INF</manifestLocation>
- </configuration>
- </plugin>
- <plugin>
- <groupId>org.opendaylight.yangtools</groupId>
- <artifactId>yang-maven-plugin</artifactId>
- <executions>
- <execution>
- <goals>
- <goal>generate-sources</goal>
- </goals>
- <configuration>
- <codeGenerators>
- <generator>
- <codeGeneratorClass>
- org.opendaylight.controller.config.yangjmxgenerator.plugin.JMXGenerator
- </codeGeneratorClass>
- <outputBaseDir>${project.build.directory}/generated-sources/config</outputBaseDir>
- <additionalConfiguration>
- <namespaceToPackage1>
- urn:opendaylight:params:xml:ns:yang:controller==org.opendaylight.controller.config.yang
- </namespaceToPackage1>
- </additionalConfiguration>
- </generator>
- <generator>
- <codeGeneratorClass>org.opendaylight.yangtools.yang.unified.doc.generator.maven.DocumentationGeneratorImpl</codeGeneratorClass>
- <outputBaseDir>target/site/models</outputBaseDir>
- </generator>
- </codeGenerators>
- <inspectDependencies>true</inspectDependencies>
- </configuration>
- </execution>
- </executions>
- <dependencies>
- <dependency>
- <groupId>org.opendaylight.controller</groupId>
- <artifactId>yang-jmx-generator-plugin</artifactId>
- <version>0.2.3-SNAPSHOT</version>
- </dependency>
- <dependency>
- <groupId>org.opendaylight.yangtools</groupId>
- <artifactId>maven-sal-api-gen-plugin</artifactId>
- <version>${yangtools.version}</version>
- <type>jar</type>
- </dependency>
- </dependencies>
- </plugin>
- </plugins>
- </build>
- <dependencies>
-
- <dependency>
- <groupId>com.google.guava</groupId>
- <artifactId>guava</artifactId>
- </dependency>
- <dependency>
- <groupId>org.opendaylight.controller</groupId>
- <artifactId>sal-core-api</artifactId>
- </dependency>
- <dependency>
- <groupId>org.opendaylight.controller</groupId>
- <artifactId>sal-common-util</artifactId>
- </dependency>
- <dependency>
- <groupId>org.opendaylight.controller</groupId>
- <artifactId>config-api</artifactId>
- </dependency>
-
- <dependency>
- <groupId>org.opendaylight.controller</groupId>
- <artifactId>sal</artifactId>
- </dependency>
- <dependency>
- <groupId>org.opendaylight.controller</groupId>
- <artifactId>clustering.services</artifactId>
- </dependency>
- <dependency>
- <groupId>junit</groupId>
- <artifactId>junit</artifactId>
- <scope>test</scope>
- </dependency>
- <dependency>
- <groupId>org.mockito</groupId>
- <artifactId>mockito-all</artifactId>
- <scope>test</scope>
- </dependency>
- <dependency>
- <groupId>org.opendaylight.yangtools</groupId>
- <artifactId>yang-binding</artifactId>
- </dependency>
- <dependency>
- <groupId>org.opendaylight.yangtools</groupId>
- <artifactId>yang-data-api</artifactId>
- </dependency>
-
- </dependencies>
-</project>
+++ /dev/null
-/*
- * Copyright (c) 2014 Cisco Systems, Inc. and others. All rights reserved.
- *
- * This program and the accompanying materials are made available under the
- * terms of the Eclipse Public License v1.0 which accompanies this distribution,
- * and is available at http://www.eclipse.org/legal/epl-v10.html
- */
-/**
-* Generated file
-
-* Generated from: yang module name: odl-sal-dom-clustered-store-cfg yang module local name: dom-clustered-store-impl
-* Generated by: org.opendaylight.controller.config.yangjmxgenerator.plugin.JMXGenerator
-* Generated at: Wed Nov 27 17:09:17 CET 2013
-*
-* Do not modify this file unless it is present under src/main directory
-*/
-package org.opendaylight.controller.config.yang.md.sal.dom.cluster.store;
-
-import org.opendaylight.controller.datastore.internal.ClusteredDataStoreManager;
-import org.osgi.framework.BundleContext;
-
-/**
-*
-*/
-public final class ClusteredDataStoreImplModule extends org.opendaylight.controller.config.yang.md.sal.dom.cluster.store.AbstractClusteredDataStoreImplModule
-{
-
- private BundleContext bundleContext;
-
- public ClusteredDataStoreImplModule(org.opendaylight.controller.config.api.ModuleIdentifier identifier, org.opendaylight.controller.config.api.DependencyResolver dependencyResolver) {
- super(identifier, dependencyResolver);
- }
-
- public ClusteredDataStoreImplModule(org.opendaylight.controller.config.api.ModuleIdentifier identifier, org.opendaylight.controller.config.api.DependencyResolver dependencyResolver, ClusteredDataStoreImplModule oldModule, java.lang.AutoCloseable oldInstance) {
- super(identifier, dependencyResolver, oldModule, oldInstance);
- }
-
- @Override
- public void validate(){
- super.validate();
- // Add custom validation for module attributes here.
- }
-
- @Override
- public java.lang.AutoCloseable createInstance() {
- ClusteredDataStoreManager manager = new ClusteredDataStoreManager();
- manager.setContext(bundleContext);
- manager.start();
- return manager;
- }
-
- public void setBundleContext(BundleContext bundleContext) {
- this.bundleContext = bundleContext;
- }
-}
+++ /dev/null
-/*
- * Copyright (c) 2014 Cisco Systems, Inc. and others. All rights reserved.
- *
- * This program and the accompanying materials are made available under the
- * terms of the Eclipse Public License v1.0 which accompanies this distribution,
- * and is available at http://www.eclipse.org/legal/epl-v10.html
- */
-/**
-* Generated file
-
-* Generated from: yang module name: odl-sal-dom-clustered-store-cfg yang module local name: dom-clustered-store-impl
-* Generated by: org.opendaylight.controller.config.yangjmxgenerator.plugin.JMXGenerator
-* Generated at: Wed Nov 27 17:09:17 CET 2013
-*
-* Do not modify this file unless it is present under src/main directory
-*/
-package org.opendaylight.controller.config.yang.md.sal.dom.cluster.store;
-
-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 ClusteredDataStoreImplModuleFactory extends org.opendaylight.controller.config.yang.md.sal.dom.cluster.store.AbstractClusteredDataStoreImplModuleFactory
-{
-
- @Override
- public Module createModule(String instanceName, DependencyResolver dependencyResolver, BundleContext bundleContext) {
- ClusteredDataStoreImplModule module =
- (ClusteredDataStoreImplModule) super.createModule(instanceName, dependencyResolver, bundleContext);
- module.setBundleContext(bundleContext);
- return module;
- }
-
- @Override
- public Module createModule(String instanceName, DependencyResolver dependencyResolver,
- DynamicMBeanWithInstance old, BundleContext bundleContext) throws Exception {
- ClusteredDataStoreImplModule module =
- (ClusteredDataStoreImplModule) super.createModule(instanceName, dependencyResolver, old, bundleContext);
- module.setBundleContext(bundleContext);
- return module;
- }
-
-}
+++ /dev/null
-
-/*
- * 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.datastore;
-
-import org.opendaylight.controller.md.sal.common.api.data.DataCommitHandler;
-import org.opendaylight.controller.md.sal.common.api.data.DataReader;
-import org.opendaylight.controller.sal.core.api.data.DataStore;
-import org.opendaylight.yangtools.yang.data.api.CompositeNode;
-import org.opendaylight.yangtools.yang.data.api.InstanceIdentifier;
-
-public interface ClusteredDataStore extends DataStore {
-
-
-}
+++ /dev/null
-
-/*
- * 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.datastore.internal;
-
-import com.google.common.base.Preconditions;
-
-import org.opendaylight.controller.clustering.services.CacheConfigException;
-import org.opendaylight.controller.clustering.services.CacheExistException;
-import org.opendaylight.controller.clustering.services.IClusterGlobalServices;
-import org.opendaylight.controller.clustering.services.IClusterServices;
-import org.opendaylight.controller.datastore.ClusteredDataStore;
-import org.opendaylight.controller.md.sal.common.api.data.DataModification;
-import org.opendaylight.controller.sal.common.util.Rpcs;
-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.InstanceIdentifier;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-
-import java.util.Collections;
-import java.util.EnumSet;
-import java.util.Set;
-import java.util.concurrent.ConcurrentMap;
-
-/**
- * The ClusteredDataStoreImpl stores global data to be shared across a controller cluster. It uses Clustering Services.
- */
-public class ClusteredDataStoreImpl implements ClusteredDataStore {
-
-
- public static final String OPERATIONAL_DATA_CACHE = "clustered_data_store.operational_data_cache";
- public static final String CONFIGURATION_DATA_CACHE = "clustered_data_store.configuration_data_cache";
-
- private final ConcurrentMap<InstanceIdentifier, CompositeNode> operationalDataCache;
- private final ConcurrentMap<InstanceIdentifier, CompositeNode> configurationDataCache;
-
- private Logger logger = LoggerFactory.getLogger(ClusteredDataStoreImpl.class);
-
- public ClusteredDataStoreImpl(IClusterGlobalServices clusterGlobalServices) throws CacheConfigException {
- logger.trace("Constructing clustered data store");
- Preconditions.checkNotNull(clusterGlobalServices, "clusterGlobalServices cannot be null");
-
- operationalDataCache = getOrCreateCache(clusterGlobalServices, OPERATIONAL_DATA_CACHE);
-
- Preconditions.checkNotNull(operationalDataCache, "operationalDataCache cannot be null");
-
- configurationDataCache = getOrCreateCache(clusterGlobalServices, CONFIGURATION_DATA_CACHE);
-
- Preconditions.checkNotNull(configurationDataCache, "configurationDataCache cannot be null");
- }
-
- @Override
- public DataCommitTransaction<InstanceIdentifier, CompositeNode> requestCommit(DataModification<InstanceIdentifier, CompositeNode> modification) {
- return new ClusteredDataStoreTransaction(modification);
- }
-
- @Override
- public CompositeNode readOperationalData(InstanceIdentifier path) {
- Preconditions.checkNotNull(path, "path cannot be null");
- return operationalDataCache.get(path);
- }
-
- @Override
- public boolean containsConfigurationPath(InstanceIdentifier path) {
- return configurationDataCache.containsKey(path);
- }
-
- @Override
- public boolean containsOperationalPath(InstanceIdentifier path) {
- return operationalDataCache.containsKey(path);
- }
-
- @Override
- public Iterable<InstanceIdentifier> getStoredConfigurationPaths() {
- return configurationDataCache.keySet();
- }
-
- @Override
- public Iterable<InstanceIdentifier> getStoredOperationalPaths() {
- return operationalDataCache.keySet();
- }
-
-
-
- @Override
- public CompositeNode readConfigurationData(InstanceIdentifier path) {
- Preconditions.checkNotNull(path, "path cannot be null");
- return configurationDataCache.get(path);
- }
-
- private RpcResult<Void> finish(final ClusteredDataStoreTransaction transaction) {
- final DataModification<InstanceIdentifier,CompositeNode> modification = transaction.getModification();
-
- this.configurationDataCache.putAll(modification.getUpdatedConfigurationData());
- this.operationalDataCache.putAll(modification.getUpdatedOperationalData());
-
- for (final InstanceIdentifier removal : modification.getRemovedConfigurationData()) {
- this.configurationDataCache.remove(removal);
- }
-
- for (final InstanceIdentifier removal : modification.getRemovedOperationalData()) {
- this.operationalDataCache.remove(removal );
- }
-
- Set<RpcError> _emptySet = Collections.<RpcError>emptySet();
- return Rpcs.<Void>getRpcResult(true, null, _emptySet);
- }
-
- private RpcResult<Void> rollback(final ClusteredDataStoreTransaction transaction) {
- Set<RpcError> _emptySet = Collections.<RpcError>emptySet();
- return Rpcs.<Void>getRpcResult(true, null, _emptySet);
- }
-
-
- private ConcurrentMap getOrCreateCache(IClusterGlobalServices clusterGlobalServices, String name) throws CacheConfigException {
- ConcurrentMap cache = clusterGlobalServices.getCache(name);
-
- if(cache == null) {
- try {
- cache = clusterGlobalServices.createCache(name, EnumSet.of(IClusterServices.cacheMode.TRANSACTIONAL));
- } catch (CacheExistException e) {
- cache = clusterGlobalServices.getCache(name);
- }
- }
- return cache;
- }
-
- private class ClusteredDataStoreTransaction implements DataCommitTransaction<InstanceIdentifier, CompositeNode> {
- private final DataModification<InstanceIdentifier,CompositeNode> modification;
-
- public ClusteredDataStoreTransaction(DataModification<InstanceIdentifier,CompositeNode> modification){
- Preconditions.checkNotNull(modification, "modification cannot be null");
-
- this.modification = modification;
- }
-
- @Override
- public DataModification<InstanceIdentifier, CompositeNode> getModification() {
- return this.modification;
- }
-
- @Override
- public RpcResult<Void> finish() throws IllegalStateException {
- return ClusteredDataStoreImpl.this.finish(this);
- }
-
- @Override
- public RpcResult<Void> rollback() throws IllegalStateException {
- return ClusteredDataStoreImpl.this.rollback(this);
- }
- }
-}
+++ /dev/null
-/*
- * 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.datastore.internal;
-
-import java.util.Hashtable;
-
-import com.google.common.base.Preconditions;
-
-import org.opendaylight.controller.clustering.services.CacheConfigException;
-import org.opendaylight.controller.clustering.services.IClusterGlobalServices;
-import org.opendaylight.controller.datastore.ClusteredDataStore;
-import org.opendaylight.controller.md.sal.common.api.data.DataModification;
-import org.opendaylight.yangtools.yang.data.api.CompositeNode;
-import org.opendaylight.yangtools.yang.data.api.InstanceIdentifier;
-import org.osgi.framework.BundleContext;
-import org.osgi.framework.ServiceReference;
-import org.osgi.util.tracker.ServiceTracker;
-import org.osgi.util.tracker.ServiceTrackerCustomizer;
-
-public class ClusteredDataStoreManager implements //
- ClusteredDataStore, //
- ServiceTrackerCustomizer<IClusterGlobalServices, IClusterGlobalServices>, //
- AutoCloseable {
-
- private ClusteredDataStore clusteredDataStore = null;
- private IClusterGlobalServices clusterGlobalServices = null;
- private BundleContext context;
-
- private ServiceReference<IClusterGlobalServices> firstClusterGlobalReference;
- private ServiceTracker<IClusterGlobalServices, IClusterGlobalServices> clusterTracker;
-
- @Override
- public DataCommitTransaction<InstanceIdentifier, CompositeNode> requestCommit(
- DataModification<InstanceIdentifier, CompositeNode> modification) {
- Preconditions.checkState(clusteredDataStore != null, "clusteredDataStore cannot be null");
- return clusteredDataStore.requestCommit(modification);
- }
-
- @Override
- public CompositeNode readOperationalData(InstanceIdentifier path) {
- Preconditions.checkState(clusteredDataStore != null, "clusteredDataStore cannot be null");
- return clusteredDataStore.readOperationalData(path);
- }
-
- @Override
- public CompositeNode readConfigurationData(InstanceIdentifier path) {
- Preconditions.checkState(clusteredDataStore != null, "clusteredDataStore cannot be null");
- return clusteredDataStore.readConfigurationData(path);
- }
-
- public Iterable<InstanceIdentifier> getStoredConfigurationPaths() {
- Preconditions.checkState(clusteredDataStore != null, "clusteredDataStore cannot be null");
- return clusteredDataStore.getStoredConfigurationPaths();
- }
-
- public Iterable<InstanceIdentifier> getStoredOperationalPaths() {
- Preconditions.checkState(clusteredDataStore != null, "clusteredDataStore cannot be null");
- return clusteredDataStore.getStoredOperationalPaths();
- }
-
- public boolean containsConfigurationPath(InstanceIdentifier path) {
- Preconditions.checkState(clusteredDataStore != null, "clusteredDataStore cannot be null");
- return clusteredDataStore.containsConfigurationPath(path);
- }
-
- public boolean containsOperationalPath(InstanceIdentifier path) {
- Preconditions.checkState(clusteredDataStore != null, "clusteredDataStore cannot be null");
- return clusteredDataStore.containsOperationalPath(path);
- }
-
- public void setClusterGlobalServices(IClusterGlobalServices clusterGlobalServices) {
- this.clusterGlobalServices = clusterGlobalServices;
- try {
- // Adding creation of the clustered data store in its own method
- // to make the method unit testable
- clusteredDataStore = createClusteredDataStore();
- } catch (CacheConfigException e) {
- throw new IllegalStateException("could not construct clusteredDataStore");
- }
- }
-
- @Override
- public IClusterGlobalServices addingService(ServiceReference<IClusterGlobalServices> reference) {
- if (clusterGlobalServices == null) {
- setClusterGlobalServices(context.getService(reference));
- return clusterGlobalServices;
- }
- return null;
- }
-
- @Override
- public void modifiedService(ServiceReference<IClusterGlobalServices> reference, IClusterGlobalServices service) {
-
- }
-
- @Override
- public void removedService(ServiceReference<IClusterGlobalServices> reference, IClusterGlobalServices service) {
- if (clusterGlobalServices == service) {
- clusterGlobalServices = null;
- clusteredDataStore = null;
- }
- }
-
- public BundleContext getContext() {
- return context;
- }
-
- public void setContext(BundleContext context) {
- this.context = context;
- }
-
-
- /**
- * Function called by the dependency manager when all the required
- * dependencies are satisfied
- *
- */
- public void start() {
- if (context != null) {
- clusterTracker = new ServiceTracker<>(context, IClusterGlobalServices.class, this);
- clusterTracker.open();
-
- context.registerService(ClusteredDataStore.class, this, new Hashtable<String,Object>());
- }
- }
-
- protected ClusteredDataStore createClusteredDataStore() throws CacheConfigException {
- return new ClusteredDataStoreImpl(clusterGlobalServices);
- }
-
- @Override
- public void close() throws Exception {
- clusterTracker.close();
- }
-}
+++ /dev/null
-module odl-sal-dom-clustered-store-cfg {
- yang-version 1;
- namespace "urn:opendaylight:params:xml:ns:yang:controller:md:sal:dom:cluster:store";
- prefix "binding-impl";
-
- import config { prefix config; revision-date 2013-04-05; }
- import opendaylight-md-sal-dom {prefix sal;}
-
- description
- "Service definition for MD-SAL Clustered Store.";
-
- revision "2013-10-28" {
- description
- "Initial revision";
- }
-
- identity dom-clustered-store-impl {
- base config:module-type;
- config:provided-service sal:dom-data-store;
- config:java-name-prefix ClusteredDataStoreImpl;
- }
-
- augment "/config:modules/config:module/config:state" {
- case dom-clustered-store-impl {
- when "/config:modules/config:module/config:type = 'dom-clustered-store-impl'";
- }
- }
-
-}
\ No newline at end of file
+++ /dev/null
-/*
- * Copyright (c) 2014 Cisco Systems, Inc. and others. All rights reserved.
- *
- * This program and the accompanying materials are made available under the
- * terms of the Eclipse Public License v1.0 which accompanies this distribution,
- * and is available at http://www.eclipse.org/legal/epl-v10.html
- */
-package org.opendaylight.controller.datastore.internal;
-
-import org.junit.Before;
-import org.junit.Test;
-import org.mockito.Mockito;
-import org.opendaylight.controller.clustering.services.CacheConfigException;
-import org.opendaylight.controller.clustering.services.CacheExistException;
-import org.opendaylight.controller.clustering.services.IClusterGlobalServices;
-import org.opendaylight.controller.clustering.services.IClusterServices;
-import org.opendaylight.controller.md.sal.common.api.data.DataCommitHandler;
-import org.opendaylight.controller.md.sal.common.api.data.DataModification;
-import org.opendaylight.yangtools.yang.data.api.CompositeNode;
-import org.opendaylight.yangtools.yang.data.api.InstanceIdentifier;
-
-import java.util.EnumSet;
-import java.util.Map;
-import java.util.concurrent.ConcurrentHashMap;
-import java.util.concurrent.ConcurrentMap;
-
-import static junit.framework.Assert.assertEquals;
-import static junit.framework.Assert.assertNotNull;
-import static junit.framework.Assert.assertNull;
-import static org.mockito.Mockito.mock;
-import static org.mockito.Mockito.never;
-import static org.mockito.Mockito.verify;
-import static org.mockito.Mockito.when;
-
-public class ClusteredDataStoreImplTest {
- @Before
- public void setUp(){
-
- }
-
- @Test
- public void constructor_WhenPassedANullClusteringServices_ShouldThrowANullPointerException() throws CacheExistException, CacheConfigException {
- try {
- new ClusteredDataStoreImpl(null);
- } catch(NullPointerException npe){
- assertEquals("clusterGlobalServices cannot be null", npe.getMessage());
- }
- }
-
- @Test
- public void constructor_WhenClusteringServicesReturnsANullOperationalDataCache_ShouldThrowANullPointerException() throws CacheExistException, CacheConfigException {
- try {
- new ClusteredDataStoreImpl(mock(IClusterGlobalServices.class));
- } catch(NullPointerException npe){
- assertEquals("operationalDataCache cannot be null", npe.getMessage());
- }
- }
-
- @Test
- public void constructor_WhenClusteringServicesReturnsANullOConfigurationDataCache_ShouldThrowANullPointerException() throws CacheExistException, CacheConfigException {
- IClusterGlobalServices mockClusterGlobalServices = mock(IClusterGlobalServices.class);
-
- // Confused about the following line?
- // See this http://stackoverflow.com/questions/10952629/a-strange-generics-edge-case-with-mockito-when-and-generic-type-inference
- Mockito.<ConcurrentMap<?,?>>when(mockClusterGlobalServices.createCache(ClusteredDataStoreImpl.OPERATIONAL_DATA_CACHE, EnumSet.of(IClusterServices.cacheMode.TRANSACTIONAL))).thenReturn(new ConcurrentHashMap<Object, Object>());
-
-
- try {
- new ClusteredDataStoreImpl(mockClusterGlobalServices);
- } catch(NullPointerException npe){
- assertEquals("configurationDataCache cannot be null", npe.getMessage());
- }
- }
-
- @Test
- public void constructor_WhenOperationalDataCacheIsAlreadyPresent_ShouldNotAttemptToCreateCache() throws CacheExistException, CacheConfigException {
- IClusterGlobalServices mockClusterGlobalServices = mock(IClusterGlobalServices.class);
-
- Mockito.<ConcurrentMap<?,?>>when(mockClusterGlobalServices.getCache(ClusteredDataStoreImpl.OPERATIONAL_DATA_CACHE)).thenReturn(new ConcurrentHashMap<Object, Object>());
- Mockito.<ConcurrentMap<?,?>>when(mockClusterGlobalServices.getCache(ClusteredDataStoreImpl.CONFIGURATION_DATA_CACHE)).thenReturn(new ConcurrentHashMap<Object, Object>());
-
- new ClusteredDataStoreImpl(mockClusterGlobalServices);
-
- verify(mockClusterGlobalServices, never()).createCache(ClusteredDataStoreImpl.OPERATIONAL_DATA_CACHE, EnumSet.of(IClusterServices.cacheMode.TRANSACTIONAL));
- }
-
- @Test
- public void constructor_WhenConfigurationDataCacheIsAlreadyPresent_ShouldNotAttemptToCreateCache() throws CacheExistException, CacheConfigException {
- IClusterGlobalServices mockClusterGlobalServices = mock(IClusterGlobalServices.class);
-
- Mockito.<ConcurrentMap<?,?>>when(mockClusterGlobalServices.getCache(ClusteredDataStoreImpl.OPERATIONAL_DATA_CACHE)).thenReturn(new ConcurrentHashMap<Object, Object>());
- Mockito.<ConcurrentMap<?,?>>when(mockClusterGlobalServices.getCache(ClusteredDataStoreImpl.CONFIGURATION_DATA_CACHE)).thenReturn(new ConcurrentHashMap<Object, Object>());
-
- new ClusteredDataStoreImpl(mockClusterGlobalServices);
-
- verify(mockClusterGlobalServices, never()).createCache(ClusteredDataStoreImpl.CONFIGURATION_DATA_CACHE, EnumSet.of(IClusterServices.cacheMode.TRANSACTIONAL));
- }
-
-
- @Test
- public void constructor_WhenPassedAValidClusteringServices_ShouldNotThrowAnyExceptions() throws CacheExistException, CacheConfigException {
- IClusterGlobalServices mockClusterGlobalServices = createClusterGlobalServices();
-
- new ClusteredDataStoreImpl(mockClusterGlobalServices);
- }
-
-
- @Test
- public void readOperationalData_WhenPassedANullPath_ShouldThrowANullPointerException() throws CacheExistException, CacheConfigException {
- IClusterGlobalServices mockClusterGlobalServices = createClusterGlobalServices();
-
- ClusteredDataStoreImpl store = new ClusteredDataStoreImpl(mockClusterGlobalServices);
-
- try {
- store.readOperationalData(null);
- } catch(NullPointerException npe){
- assertEquals("path cannot be null", npe.getMessage());
- }
- }
-
- @Test
- public void readOperationalData_WhenPassedAKeyThatDoesNotExistInTheCache_ShouldReturnNull() throws CacheExistException, CacheConfigException {
- InstanceIdentifier path = InstanceIdentifier.builder().toInstance();
-
- IClusterGlobalServices mockClusterGlobalServices = createClusterGlobalServices();
-
- ClusteredDataStoreImpl store = new ClusteredDataStoreImpl(mockClusterGlobalServices);
-
- assertNull(store.readOperationalData(path));
- }
-
- @Test
- public void readOperationalData_WhenPassedAKeyThatDoesExistInTheCache_ShouldReturnTheValueObject() throws CacheExistException, CacheConfigException {
- InstanceIdentifier path = InstanceIdentifier.builder().toInstance();
-
- IClusterGlobalServices mockClusterGlobalServices = createClusterGlobalServices();
-
- ConcurrentMap<InstanceIdentifier, CompositeNode> mockOperationalDataCache = mock(ConcurrentMap.class);
-
- CompositeNode valueObject = mock(CompositeNode.class);
-
- when(mockOperationalDataCache.get(path)).thenReturn(valueObject);
-
- Mockito.<ConcurrentMap<?,?>>when(mockClusterGlobalServices.createCache(ClusteredDataStoreImpl.OPERATIONAL_DATA_CACHE, EnumSet.of(IClusterServices.cacheMode.TRANSACTIONAL))).thenReturn(mockOperationalDataCache);
- Mockito.<ConcurrentMap<?,?>>when(mockClusterGlobalServices.createCache(ClusteredDataStoreImpl.CONFIGURATION_DATA_CACHE, EnumSet.of(IClusterServices.cacheMode.TRANSACTIONAL))).thenReturn(new ConcurrentHashMap<Object, Object>());
-
-
- ClusteredDataStoreImpl store = new ClusteredDataStoreImpl(mockClusterGlobalServices);
-
- assertEquals(valueObject, store.readOperationalData(path));
- }
-
-
-
- @Test
- public void readConfigurationData_WhenPassedANullPath_ShouldThrowANullPointerException() throws CacheExistException, CacheConfigException {
-
- IClusterGlobalServices mockClusterGlobalServices = createClusterGlobalServices();
-
- ClusteredDataStoreImpl store = new ClusteredDataStoreImpl(mockClusterGlobalServices);
-
- try {
- store.readConfigurationData(null);
- } catch(NullPointerException npe){
- assertEquals("path cannot be null", npe.getMessage());
- }
- }
-
-
- @Test
- public void readConfigurationData_WhenPassedAKeyThatDoesNotExistInTheCache_ShouldReturnNull() throws CacheExistException, CacheConfigException {
- InstanceIdentifier path = InstanceIdentifier.builder().toInstance();
-
- IClusterGlobalServices mockClusterGlobalServices = createClusterGlobalServices();
-
- ClusteredDataStoreImpl store = new ClusteredDataStoreImpl(mockClusterGlobalServices);
-
- assertNull(store.readConfigurationData(path));
- }
-
- @Test
- public void readConfigurationData_WhenPassedAKeyThatDoesExistInTheCache_ShouldReturnTheValueObject() throws CacheExistException, CacheConfigException {
- InstanceIdentifier path = InstanceIdentifier.builder().toInstance();
-
- IClusterGlobalServices mockClusterGlobalServices = createClusterGlobalServices();
-
- ConcurrentMap<InstanceIdentifier, CompositeNode> mockConfigurationDataCache = mock(ConcurrentMap.class);
-
- CompositeNode valueObject = mock(CompositeNode.class);
-
- when(mockConfigurationDataCache.get(path)).thenReturn(valueObject);
-
- Mockito.<ConcurrentMap<?,?>>when(mockClusterGlobalServices.createCache(ClusteredDataStoreImpl.OPERATIONAL_DATA_CACHE, EnumSet.of(IClusterServices.cacheMode.TRANSACTIONAL))).thenReturn(mock(ConcurrentMap.class));
- Mockito.<ConcurrentMap<?,?>>when(mockClusterGlobalServices.createCache(ClusteredDataStoreImpl.CONFIGURATION_DATA_CACHE, EnumSet.of(IClusterServices.cacheMode.TRANSACTIONAL))).thenReturn(mockConfigurationDataCache);
-
-
- ClusteredDataStoreImpl store = new ClusteredDataStoreImpl(mockClusterGlobalServices);
-
- assertEquals(valueObject, store.readConfigurationData(path));
- }
-
-
- @Test
- public void requestCommit_ShouldReturnADataTransaction() throws CacheExistException, CacheConfigException {
- IClusterGlobalServices mockClusterGlobalServices = createClusterGlobalServices();
-
- ClusteredDataStoreImpl store = new ClusteredDataStoreImpl(mockClusterGlobalServices);
-
- assertNotNull(store.requestCommit(mock(DataModification.class)));
-
-
- }
-
- @Test
- public void finishingADataTransaction_ShouldUpdateTheUnderlyingCache() throws CacheExistException, CacheConfigException {
- IClusterGlobalServices mockClusterGlobalServices = mock(IClusterGlobalServices.class);
-
- ConcurrentMap mockConfigurationDataCache = mock(ConcurrentMap.class);
- ConcurrentMap mockOperationalDataCache = mock(ConcurrentMap.class);
-
- Mockito.<ConcurrentMap<?,?>>when(mockClusterGlobalServices.createCache(ClusteredDataStoreImpl.OPERATIONAL_DATA_CACHE, EnumSet.of(IClusterServices.cacheMode.TRANSACTIONAL))).thenReturn(mockOperationalDataCache);
- Mockito.<ConcurrentMap<?,?>>when(mockClusterGlobalServices.createCache(ClusteredDataStoreImpl.CONFIGURATION_DATA_CACHE, EnumSet.of(IClusterServices.cacheMode.TRANSACTIONAL))).thenReturn(mockConfigurationDataCache);
-
- ClusteredDataStoreImpl store = new ClusteredDataStoreImpl(mockClusterGlobalServices);
-
- DataModification mockModification = mock(DataModification.class);
-
- Map configurationData = mock(Map.class);
- Map operationalData = mock(Map.class);
-
- when(mockModification.getUpdatedConfigurationData()).thenReturn(configurationData);
- when(mockModification.getUpdatedOperationalData()).thenReturn(operationalData);
-
- DataCommitHandler.DataCommitTransaction<InstanceIdentifier, CompositeNode> transaction = store.requestCommit(mockModification);
-
- transaction.finish();
-
- verify(mockConfigurationDataCache).putAll(mockModification.getUpdatedConfigurationData());
- verify(mockOperationalDataCache).putAll(mockModification.getUpdatedOperationalData());
- }
-
-
- @Test
- public void rollingBackADataTransaction_ShouldDoNothing() throws CacheExistException, CacheConfigException {
- IClusterGlobalServices mockClusterGlobalServices = mock(IClusterGlobalServices.class);
-
- ConcurrentMap mockConfigurationDataCache = mock(ConcurrentMap.class);
- ConcurrentMap mockOperationalDataCache = mock(ConcurrentMap.class);
-
- Mockito.<ConcurrentMap<?,?>>when(mockClusterGlobalServices.createCache(ClusteredDataStoreImpl.OPERATIONAL_DATA_CACHE, EnumSet.of(IClusterServices.cacheMode.TRANSACTIONAL))).thenReturn(mockOperationalDataCache);
- Mockito.<ConcurrentMap<?,?>>when(mockClusterGlobalServices.createCache(ClusteredDataStoreImpl.CONFIGURATION_DATA_CACHE, EnumSet.of(IClusterServices.cacheMode.TRANSACTIONAL))).thenReturn(mockConfigurationDataCache);
-
- ClusteredDataStoreImpl store = new ClusteredDataStoreImpl(mockClusterGlobalServices);
-
- DataModification mockModification = mock(DataModification.class);
-
- Map configurationData = mock(Map.class);
- Map operationalData = mock(Map.class);
-
- when(mockModification.getUpdatedConfigurationData()).thenReturn(configurationData);
- when(mockModification.getUpdatedOperationalData()).thenReturn(operationalData);
-
- DataCommitHandler.DataCommitTransaction<InstanceIdentifier, CompositeNode> transaction = store.requestCommit(mockModification);
-
- transaction.rollback();
-
- verify(mockConfigurationDataCache, never()).putAll(mockModification.getUpdatedConfigurationData());
- verify(mockOperationalDataCache, never()).putAll(mockModification.getUpdatedOperationalData());
-
- }
-
-
- private IClusterGlobalServices createClusterGlobalServices() throws CacheExistException, CacheConfigException {
- IClusterGlobalServices mockClusterGlobalServices = mock(IClusterGlobalServices.class);
-
- Mockito.<ConcurrentMap<?,?>>when(mockClusterGlobalServices.createCache(ClusteredDataStoreImpl.OPERATIONAL_DATA_CACHE, EnumSet.of(IClusterServices.cacheMode.TRANSACTIONAL))).thenReturn(mock(ConcurrentMap.class));
- Mockito.<ConcurrentMap<?,?>>when(mockClusterGlobalServices.createCache(ClusteredDataStoreImpl.CONFIGURATION_DATA_CACHE, EnumSet.of(IClusterServices.cacheMode.TRANSACTIONAL))).thenReturn(mock(ConcurrentMap.class));
-
- return mockClusterGlobalServices;
- }
-}
+++ /dev/null
-/*
- * 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.datastore.internal;
-
-import java.util.concurrent.ConcurrentHashMap;
-
-import org.apache.felix.dm.Component;
-import org.junit.BeforeClass;
-import org.junit.Test;
-import org.opendaylight.controller.clustering.services.CacheConfigException;
-import org.opendaylight.controller.clustering.services.CacheExistException;
-import org.opendaylight.controller.clustering.services.IClusterGlobalServices;
-import org.opendaylight.controller.md.sal.common.api.data.DataCommitHandler.DataCommitTransaction;
-import org.opendaylight.controller.md.sal.common.api.data.DataModification;
-import org.opendaylight.yangtools.yang.data.api.CompositeNode;
-import org.opendaylight.yangtools.yang.data.api.InstanceIdentifier;
-
-import static junit.framework.Assert.assertNotNull;
-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.spy;
-import static org.mockito.Mockito.when;
-
-public class ClusteredDataStoreManagerTest {
-
- private static ClusteredDataStoreManager clusteredDSMgr = null;
- private IClusterGlobalServices icClusterGlbServices = mock(IClusterGlobalServices.class);
-
- @BeforeClass
- public static void construct() {
- clusteredDSMgr = new ClusteredDataStoreManager();
- assertNotNull(clusteredDSMgr);
- }
-
- @Test
- public void construct_OnSetClusterGlobalServices_AssertNoException() {
- doReturn(new ConcurrentHashMap<InstanceIdentifier, CompositeNode>()).when(icClusterGlbServices).getCache(ClusteredDataStoreImpl.CONFIGURATION_DATA_CACHE);
- doReturn(new ConcurrentHashMap<InstanceIdentifier, CompositeNode>()).when(icClusterGlbServices).getCache(ClusteredDataStoreImpl.OPERATIONAL_DATA_CACHE);
- clusteredDSMgr.setClusterGlobalServices(icClusterGlbServices);
- }
-
- @Test
- public void construct_init_AssertNoException() throws CacheExistException, CacheConfigException {
- ClusteredDataStoreImpl clusteredDSImpl = mock(ClusteredDataStoreImpl.class);
-
- ClusteredDataStoreManager clusteredDSManager = spy(new ClusteredDataStoreManager());
- doReturn(clusteredDSImpl).when(clusteredDSManager).createClusteredDataStore();
- clusteredDSManager.start();
- }
-
-
- @Test
- public void construct_readOperationalData_AssertNoException() throws CacheExistException, CacheConfigException {
- ClusteredDataStoreImpl clusteredDSImpl = mock(ClusteredDataStoreImpl.class);
-
- ClusteredDataStoreManager clusteredDSManager = spy(new ClusteredDataStoreManager());
- doReturn(clusteredDSImpl).when(clusteredDSManager).createClusteredDataStore();
- Component c = mock(Component.class);
-
- clusteredDSManager.start();
- clusteredDSManager.setClusterGlobalServices(icClusterGlbServices);
- CompositeNode o = mock(CompositeNode.class);
-
- when(clusteredDSImpl.readOperationalData(any(InstanceIdentifier.class))).thenReturn(o);
- assertEquals(o, clusteredDSManager.readOperationalData(any(InstanceIdentifier.class)));
- }
-
- @Test
- public void construct_readConfigurationData_AssertNoException() throws CacheExistException, CacheConfigException {
- ClusteredDataStoreImpl clusteredDSImpl = mock(ClusteredDataStoreImpl.class);
-
- ClusteredDataStoreManager clusteredDSManager = spy(new ClusteredDataStoreManager());
- doReturn(clusteredDSImpl).when(clusteredDSManager).createClusteredDataStore();
- Component c = mock(Component.class);
-
- clusteredDSManager.start();
- clusteredDSManager.setClusterGlobalServices(icClusterGlbServices);
-
- CompositeNode o = mock(CompositeNode.class);
-
- when(clusteredDSImpl.readConfigurationData(any(InstanceIdentifier.class))).thenReturn(o);
- assertEquals(o, clusteredDSManager.readConfigurationData(any(InstanceIdentifier.class)));
- }
-
- @Test
- public void construct_requestCommit_AssertNoException() throws CacheExistException, CacheConfigException {
- ClusteredDataStoreImpl clusteredDSImpl = mock(ClusteredDataStoreImpl.class);
-
- ClusteredDataStoreManager clusteredDSManager = spy(new ClusteredDataStoreManager());
- doReturn(clusteredDSImpl).when(clusteredDSManager).createClusteredDataStore();
- IClusterGlobalServices globalServices = mock(IClusterGlobalServices.class);
- clusteredDSManager.setClusterGlobalServices(globalServices);
- clusteredDSManager.start();
- DataCommitTransaction dataCommitTransaction = mock(DataCommitTransaction.class);
-
- when(clusteredDSImpl.requestCommit(any(DataModification.class))).thenReturn(dataCommitTransaction);
- assertEquals(dataCommitTransaction, clusteredDSManager.requestCommit(any(DataModification.class)));
- }
-}
+++ /dev/null
-<?xml version="1.0" encoding="UTF-8"?>
-<project
- xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"
- xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
- <modelVersion>4.0.0</modelVersion>
- <parent>
- <groupId>org.opendaylight.controller</groupId>
- <artifactId>commons.integrationtest</artifactId>
- <version>0.5.1-SNAPSHOT</version>
- <relativePath>../../../commons/integrationtest</relativePath>
- </parent>
- <scm>
- <connection>scm:git:ssh://git.opendaylight.org:29418/controller.git</connection>
- <developerConnection>scm:git:ssh://git.opendaylight.org:29418/controller.git</developerConnection>
- <url>https://wiki.opendaylight.org/view/OpenDaylight_Controller:Main</url>
- </scm>
-
- <artifactId>clustered-datastore.integrationtest</artifactId>
- <version>0.4.0-SNAPSHOT</version>
-
- <dependencyManagement>
- <dependencies>
- <dependency>
- <groupId>xml-apis</groupId>
- <artifactId>xml-apis</artifactId>
- <version>1.4.01</version>
- </dependency>
- </dependencies>
- </dependencyManagement>
-
- <dependencies>
- <dependency>
- <groupId>com.google.guava</groupId>
- <artifactId>guava</artifactId>
- </dependency>
- <dependency>
- <groupId>org.opendaylight.controller</groupId>
- <artifactId>sal-binding-it</artifactId>
- <version>1.0-SNAPSHOT</version>
- </dependency>
- <dependency>
- <groupId>org.opendaylight.controller</groupId>
- <artifactId>sal-common-api</artifactId>
- <version>1.0-SNAPSHOT</version>
- </dependency>
- <dependency>
- <groupId>org.opendaylight.controller</groupId>
- <artifactId>sal-common-util</artifactId>
- <version>1.0-SNAPSHOT</version>
- </dependency>
- <dependency>
- <groupId>org.opendaylight.controller</groupId>
- <artifactId>sal-common-impl</artifactId>
- <version>1.0-SNAPSHOT</version>
- </dependency>
- <dependency>
- <groupId>org.opendaylight.controller</groupId>
- <artifactId>sal-binding-broker-impl</artifactId>
- <version>1.0-SNAPSHOT</version>
- <exclusions>
- <exclusion>
- <artifactId>xml-apis</artifactId>
- <groupId>xml-apis</groupId>
- </exclusion>
- <exclusion>
- <artifactId>reflections</artifactId>
- <groupId>org.reflections</groupId>
- </exclusion>
- </exclusions>
- </dependency>
- <dependency>
- <groupId>org.opendaylight.controller</groupId>
- <artifactId>sal</artifactId>
- <version>0.7.0-SNAPSHOT</version>
- </dependency>
- <dependency>
- <groupId>org.opendaylight.controller</groupId>
- <artifactId>clustering.services</artifactId>
- <version>0.5.0-SNAPSHOT</version>
- </dependency>
- <dependency>
- <groupId>org.opendaylight.yangtools</groupId>
- <artifactId>yang-binding</artifactId>
- </dependency>
- <dependency>
- <groupId>org.opendaylight.yangtools.thirdparty</groupId>
- <artifactId>antlr4-runtime-osgi-nohead</artifactId>
- <version>4.0</version>
- </dependency>
- <dependency>
- <groupId>org.opendaylight.controller</groupId>
- <artifactId>protocol_plugins.stub</artifactId>
- <version>0.4.1-SNAPSHOT</version>
- </dependency>
- <dependency>
- <groupId>org.opendaylight.controller</groupId>
- <artifactId>sal.implementation</artifactId>
- <version>0.4.1-SNAPSHOT</version>
- </dependency>
- <dependency>
- <groupId>org.opendaylight.controller</groupId>
- <artifactId>containermanager</artifactId>
- <version>0.5.1-SNAPSHOT</version>
- </dependency>
- <dependency>
- <groupId>org.opendaylight.controller</groupId>
- <artifactId>containermanager.it.implementation</artifactId>
- <version>0.5.1-SNAPSHOT</version>
- </dependency>
- <dependency>
- <groupId>org.opendaylight.controller</groupId>
- <artifactId>clustering.stub</artifactId>
- <version>0.4.1-SNAPSHOT</version>
- </dependency>
- <dependency>
- <groupId>org.opendaylight.controller</groupId>
- <artifactId>clustered-datastore-implementation</artifactId>
- <version>0.4.1-SNAPSHOT</version>
- </dependency>
- <dependency>
- <groupId>org.opendaylight.yangtools.thirdparty</groupId>
- <artifactId>xtend-lib-osgi</artifactId>
- <version>2.4.3</version>
- <scope>test</scope>
- </dependency>
- <dependency>
- <groupId>org.opendaylight.controller</groupId>
- <artifactId>sal-binding-broker-impl</artifactId>
- <version>1.0-SNAPSHOT</version>
- <scope>provided</scope>
- </dependency>
- <dependency>
- <groupId>org.ops4j.pax.exam</groupId>
- <artifactId>pax-exam-container-native</artifactId>
- <version>${exam.version}</version>
- <scope>test</scope>
- </dependency>
- <dependency>
- <groupId>org.ops4j.pax.exam</groupId>
- <artifactId>pax-exam-junit4</artifactId>
- <version>${exam.version}</version>
- <scope>test</scope>
- </dependency>
- <dependency>
- <groupId>org.opendaylight.controller</groupId>
- <artifactId>config-netconf-connector</artifactId>
- <version>${netconf.version}</version>
- <scope>test</scope>
- <exclusions>
- <exclusion>
- <artifactId>xml-apis</artifactId>
- <groupId>xml-apis</groupId>
- </exclusion>
- </exclusions>
- </dependency>
- <dependency>
- <groupId>org.opendaylight.controller</groupId>
- <artifactId>logback-config</artifactId>
- </dependency>
- <dependency>
- <groupId>org.opendaylight.controller</groupId>
- <artifactId>config-persister-impl</artifactId>
- </dependency>
- <dependency>
- <groupId>org.opendaylight.controller</groupId>
- <artifactId>config-persister-file-xml-adapter</artifactId>
- </dependency>
- <dependency>
- <groupId>org.opendaylight.controller</groupId>
- <artifactId>netconf-impl</artifactId>
- <version>${netconf.version}</version>
- </dependency>
- <dependency>
- <groupId>org.opendaylight.controller</groupId>
- <artifactId>netconf-client</artifactId>
- <version>${netconf.version}</version>
- </dependency>
- <dependency>
- <groupId>org.opendaylight.controller</groupId>
- <artifactId>sal-common</artifactId>
- <version>1.0-SNAPSHOT</version>
- </dependency>
- <dependency>
- <groupId>org.opendaylight.yangtools</groupId>
- <artifactId>yang-common</artifactId>
- </dependency>
- <dependency>
- <groupId>org.opendaylight.yangtools</groupId>
- <artifactId>concepts</artifactId>
- </dependency>
- <dependency>
- <groupId>org.opendaylight.yangtools</groupId>
- <artifactId>yang-data-api</artifactId>
- </dependency>
- <dependency>
- <groupId>org.mockito</groupId>
- <artifactId>mockito-all</artifactId>
- <version>1.9.5</version>
- <scope>test</scope>
- </dependency>
- <dependency>
- <groupId>org.opendaylight.controller</groupId>
- <artifactId>config-manager</artifactId>
- <version>0.2.3-SNAPSHOT</version>
- </dependency>
- <dependency>
- <groupId>org.opendaylight.controller.model</groupId>
- <artifactId>model-flow-management</artifactId>
- <version>1.0-SNAPSHOT</version>
- <scope>provided</scope>
- </dependency>
- <dependency>
- <groupId>org.opendaylight.yangtools.thirdparty</groupId>
- <artifactId>antlr4-runtime-osgi-nohead</artifactId>
- <version>4.0</version>
- </dependency>
- <dependency>
- <groupId>org.opendaylight.yangtools.thirdparty</groupId>
- <artifactId>xtend-lib-osgi</artifactId>
- <version>2.4.3</version>
- <scope>test</scope>
- </dependency>
- <dependency>
- <groupId>org.opendaylight.controller</groupId>
- <artifactId>sal-binding-broker-impl</artifactId>
- <version>1.0-SNAPSHOT</version>
- <scope>provided</scope>
- </dependency>
- <dependency>
- <groupId>org.ops4j.pax.exam</groupId>
- <artifactId>pax-exam-container-native</artifactId>
- <version>${exam.version}</version>
- <scope>test</scope>
- </dependency>
- <dependency>
- <groupId>org.ops4j.pax.exam</groupId>
- <artifactId>pax-exam-junit4</artifactId>
- <version>${exam.version}</version>
- <scope>test</scope>
- </dependency>
- <dependency>
- <groupId>org.opendaylight.controller</groupId>
- <artifactId>config-netconf-connector</artifactId>
- <version>${netconf.version}</version>
- <scope>test</scope>
- </dependency>
-
- <dependency>
- <groupId>org.opendaylight.yangtools</groupId>
- <artifactId>yang-parser-impl</artifactId>
- <version>${yangtools.version}</version>
- </dependency>
- <dependency>
- <groupId>org.opendaylight.yangtools</groupId>
- <artifactId>yang-model-util</artifactId>
- <version>${yangtools.version}</version>
- </dependency>
-
- <dependency>
- <groupId>org.opendaylight.controller</groupId>
- <artifactId>logback-config</artifactId>
- </dependency>
- <dependency>
- <groupId>org.opendaylight.controller</groupId>
- <artifactId>config-persister-impl</artifactId>
- </dependency>
- <dependency>
- <groupId>org.opendaylight.controller</groupId>
- <artifactId>netconf-impl</artifactId>
- <version>${netconf.version}</version>
- </dependency>
- <dependency>
- <groupId>org.opendaylight.controller</groupId>
- <artifactId>netconf-client</artifactId>
- <version>${netconf.version}</version>
- </dependency>
- <dependency>
- <groupId>org.ops4j.pax.exam</groupId>
- <artifactId>pax-exam-link-mvn</artifactId>
- <version>${exam.version}</version>
- <scope>test</scope>
- </dependency>
- <dependency>
- <groupId>equinoxSDK381</groupId>
- <artifactId>org.eclipse.osgi</artifactId>
- <version>3.8.1.v20120830-144521</version>
- <scope>test</scope>
- </dependency>
- <dependency>
- <groupId>org.slf4j</groupId>
- <artifactId>log4j-over-slf4j</artifactId>
- <version>1.7.2</version>
- </dependency>
- <dependency>
- <groupId>ch.qos.logback</groupId>
- <artifactId>logback-core</artifactId>
- <version>1.0.9</version>
- </dependency>
- <dependency>
- <groupId>ch.qos.logback</groupId>
- <artifactId>logback-classic</artifactId>
- <version>1.0.9</version>
- </dependency>
- <dependency>
- <groupId>org.opendaylight.controller.model</groupId>
- <artifactId>model-flow-service</artifactId>
- <version>1.0-SNAPSHOT</version>
- <scope>provided</scope>
- </dependency>
- <dependency>
- <groupId>org.opendaylight.controller</groupId>
- <artifactId>config-manager</artifactId>
- <version>0.2.3-SNAPSHOT</version>
- </dependency>
- <dependency>
- <groupId>org.opendaylight.controller.model</groupId>
- <artifactId>model-flow-management</artifactId>
- <version>1.0-SNAPSHOT</version>
- <scope>provided</scope>
- </dependency>
- <dependency>
- <groupId>org.opendaylight.yangtools.thirdparty</groupId>
- <artifactId>antlr4-runtime-osgi-nohead</artifactId>
- <version>4.0</version>
- </dependency>
- </dependencies>
- <properties>
- <!-- Sonar jacoco plugin to get integration test coverage info -->
- <sonar.jacoco.reportPath>../implementation/target/jacoco.exec</sonar.jacoco.reportPath>
- <sonar.jacoco.itReportPath>../implementaiton/target/jacoco-it.exec</sonar.jacoco.itReportPath>
- </properties>
- <build>
- <plugins>
- <plugin>
- <groupId>org.jacoco</groupId>
- <artifactId>jacoco-maven-plugin</artifactId>
- <configuration>
- <destFile>../implementation/target/jacoco-it.exec</destFile>
- <includes><include>org.opendaylight.controller.*</include></includes>
- </configuration>
- <executions>
- <execution>
- <id>pre-test</id>
- <goals>
- <goal>prepare-agent</goal>
- </goals>
- </execution>
- <execution>
- <id>post-test</id>
- <configuration>
- <skip>true</skip>
- </configuration>
- </execution>
- </executions>
- </plugin>
- </plugins>
- </build>
-</project>
+++ /dev/null
-/*
- * 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.datastore;
-
-import static junit.framework.Assert.assertNotNull;
-import static junit.framework.Assert.assertNull;
-import static org.mockito.Mockito.mock;
-import static org.mockito.Mockito.when;
-import static org.ops4j.pax.exam.CoreOptions.junitBundles;
-import static org.ops4j.pax.exam.CoreOptions.mavenBundle;
-import static org.ops4j.pax.exam.CoreOptions.options;
-import static org.ops4j.pax.exam.CoreOptions.systemPackages;
-import static org.ops4j.pax.exam.CoreOptions.systemProperty;
-
-import java.util.ArrayList;
-import java.util.HashMap;
-import java.util.List;
-
-import javax.inject.Inject;
-
-import org.junit.Assert;
-import org.junit.Test;
-import org.junit.runner.RunWith;
-import org.opendaylight.controller.md.sal.common.api.data.DataCommitHandler.DataCommitTransaction;
-import org.opendaylight.controller.md.sal.common.api.data.DataModification;
-import org.opendaylight.controller.test.sal.binding.it.TestHelper;
-import org.opendaylight.yangtools.yang.data.api.CompositeNode;
-import org.opendaylight.yangtools.yang.data.api.InstanceIdentifier;
-import org.ops4j.pax.exam.Configuration;
-import org.ops4j.pax.exam.Option;
-import org.ops4j.pax.exam.junit.PaxExam;
-import org.ops4j.pax.exam.util.Filter;
-import org.ops4j.pax.exam.util.PathUtils;
-import org.osgi.framework.Bundle;
-import org.osgi.framework.BundleContext;
-import org.osgi.framework.ServiceReference;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-
-@RunWith(PaxExam.class)
-//@ExamReactorStrategy(PerClass.class)
-public class ClusteredDataStoreIT {
- private Logger log = LoggerFactory.getLogger(ClusteredDataStoreIT.class);
- // get the OSGI bundle context
- @Inject
- private BundleContext bc;
- @Inject
- @Filter(timeout=60*1000)
- private ClusteredDataStore clusteredDS;
-
- // Configure the OSGi container
- @Configuration
- public Option[] config() {
- return options(
- //
- systemProperty("logback.configurationFile").value(
- "file:" + PathUtils.getBaseDir() + "/src/test/resources/logback.xml"),
- // To start OSGi console for inspection remotely
- systemProperty("osgi.console").value("2401"),
- // Set the systemPackages (used by clustering)
- systemPackages("sun.reflect", "sun.reflect.misc", "sun.misc"),
- systemProperty("org.ops4j.pax.logging.DefaultServiceLog.level").value("DEBUG"),
- // List framework bundles
- mavenBundle("equinoxSDK381", "org.eclipse.equinox.console").versionAsInProject(),
- mavenBundle("equinoxSDK381", "org.eclipse.equinox.util").versionAsInProject(),
- mavenBundle("equinoxSDK381", "org.eclipse.osgi.services").versionAsInProject(),
- mavenBundle("equinoxSDK381", "org.eclipse.equinox.ds").versionAsInProject(),
- mavenBundle("equinoxSDK381", "org.apache.felix.gogo.command").versionAsInProject(),
- mavenBundle("equinoxSDK381", "org.apache.felix.gogo.runtime").versionAsInProject(),
- mavenBundle("equinoxSDK381", "org.apache.felix.gogo.shell").versionAsInProject(),
- // List logger bundles
- mavenBundle("org.slf4j", "slf4j-api").versionAsInProject(),
- mavenBundle("org.slf4j", "log4j-over-slf4j").versionAsInProject(),
- mavenBundle("ch.qos.logback", "logback-core").versionAsInProject(),
- mavenBundle("ch.qos.logback", "logback-classic").versionAsInProject(),
- // needed by statisticsmanager
- mavenBundle("org.opendaylight.controller", "containermanager").versionAsInProject(),
- mavenBundle("org.opendaylight.controller", "containermanager.it.implementation").versionAsInProject(),
- mavenBundle("org.opendaylight.controller", "clustering.services").versionAsInProject(),
- mavenBundle("org.opendaylight.controller", "clustering.stub").versionAsInProject(),
-
- // List all the bundles on which the test case depends
- mavenBundle("org.opendaylight.controller", "sal").versionAsInProject(),
- TestHelper.baseModelBundles(),
- TestHelper.configMinumumBundles(),
- TestHelper.bindingIndependentSalBundles(),
- TestHelper.bindingAwareSalBundles(),
- TestHelper.mdSalCoreBundles(),
- mavenBundle("org.opendaylight.controller", "config-api").versionAsInProject(),
- mavenBundle("org.opendaylight.controller", "sal.implementation").versionAsInProject(),
- mavenBundle("org.opendaylight.controller", "protocol_plugins.stub").versionAsInProject(),
-
- mavenBundle("org.osgi", "org.osgi.core").versionAsInProject(),
- // adding new maven bundles
- mavenBundle("org.mockito", "mockito-all").versionAsInProject(),
-
- // needed by hosttracker
- mavenBundle("org.opendaylight.controller", "clustered-datastore-implementation").versionAsInProject(),
- mavenBundle("org.jboss.spec.javax.transaction", "jboss-transaction-api_1.1_spec").versionAsInProject(),
- mavenBundle("org.apache.commons", "commons-lang3").versionAsInProject(),
- mavenBundle("org.apache.felix", "org.apache.felix.dependencymanager").versionAsInProject(),
- junitBundles());
- }
-
- private String stateToString(int state) {
- switch (state) {
- case Bundle.ACTIVE:
- return "ACTIVE";
- case Bundle.INSTALLED:
- return "INSTALLED";
- case Bundle.RESOLVED:
- return "RESOLVED";
- case Bundle.UNINSTALLED:
- return "UNINSTALLED";
- default:
- return "Not CONVERTED";
- }
- }
-
- @Test
- public void testBundleContextClusteredDS_NotNull() throws Exception {
- ServiceReference serviceReference = bc.getServiceReference(ClusteredDataStore.class);
- ClusteredDataStore store = ClusteredDataStore.class.cast(bc.getService(serviceReference));
- assertNotNull(store);
- }
-
- @Test
- public void testInjected_ClusteredDS_NotNull() {
- assertNotNull(clusteredDS);
- }
-
- @Test
- public void requestCommit_readConfigurationData_ShouldVerifyDataAndNoException() {
- DataModification dataModification = mock(DataModification.class);
- HashMap map = new HashMap();
- List list = new ArrayList();
- list.add("key");
- InstanceIdentifier key = new InstanceIdentifier(list);
- map.put(key, mock(CompositeNode.class));
- when(dataModification.getUpdatedConfigurationData()).thenReturn(map);
- DataCommitTransaction dataCommitTrans = clusteredDS.requestCommit(dataModification);
- dataCommitTrans.finish();
- Object value = clusteredDS.readConfigurationData(key);
- Assert.assertNotNull(value);
- }
-
- @Test(expected = NullPointerException.class)
- public void requestCommit_ShouldThrowException() {
- DataModification dataModification = null;
- DataCommitTransaction dataCommitTrans = clusteredDS.requestCommit(dataModification);
- dataCommitTrans.finish();
- }
-
- @Test
- public void requestCommit_readOperationalData_ShouldVerifyDataAndNoException() {
- DataModification dataModification = mock(DataModification.class);
- HashMap map = new HashMap();
- List list = new ArrayList();
- list.add("key");
- InstanceIdentifier key = new InstanceIdentifier(list);
- map.put(key, mock(CompositeNode.class));
- when(dataModification.getUpdatedOperationalData()).thenReturn(map);
- DataCommitTransaction dataCommitTrans = clusteredDS.requestCommit(dataModification);
- dataCommitTrans.finish();
- Object value = clusteredDS.readOperationalData(key);
- Assert.assertNotNull(value);
- }
-
- @Test
- public void requestCommit_readConfigurationData_NonExistingKey_ShouldVerifyNoMappedValueAndNoException() {
- DataModification dataModification = mock(DataModification.class);
- HashMap map = new HashMap();
- List list = new ArrayList();
- list.add("key");
- InstanceIdentifier key = new InstanceIdentifier(list);
- map.put(key, "value");
- when(dataModification.getUpdatedConfigurationData()).thenReturn(map);
- DataCommitTransaction dataCommitTrans = clusteredDS.requestCommit(dataModification);
- dataCommitTrans.finish();
- list = new ArrayList();
- list.add("key1");
- InstanceIdentifier key1 = new InstanceIdentifier(list);
-
- Object value = clusteredDS.readConfigurationData(key1);
- assertNull(value);
- }
-
- @Test
- public void requestCommit_readOperationalData_NonExistingKey_ShouldVerifyNoMappedValueAndNoException() {
- DataModification dataModification = mock(DataModification.class);
- HashMap map = new HashMap();
- List list = new ArrayList();
- list.add("key");
- InstanceIdentifier key = new InstanceIdentifier(list);
- map.put(key, mock(CompositeNode.class));
- when(dataModification.getUpdatedOperationalData()).thenReturn(map);
- DataCommitTransaction dataCommitTrans = clusteredDS.requestCommit(dataModification);
- dataCommitTrans.finish();
- list = new ArrayList();
- list.add("key1");
- InstanceIdentifier key1 = new InstanceIdentifier(list);
-
- Object value = clusteredDS.readOperationalData(key1);
- assertNull(value);
- }
-
- @Test(expected = NullPointerException.class)
- public void requestCommit_readConfigurationData_WithNullPathShouldThrowException() {
- DataModification dataModification = mock(DataModification.class);
- HashMap map = new HashMap();
- List list = new ArrayList();
- list.add("key");
- InstanceIdentifier key = new InstanceIdentifier(list);
- map.put(key, "value");
- when(dataModification.getUpdatedConfigurationData()).thenReturn(map);
- DataCommitTransaction dataCommitTrans = clusteredDS.requestCommit(dataModification);
- dataCommitTrans.finish();
- Object value = clusteredDS.readConfigurationData(null);
- }
-
- @Test(expected = NullPointerException.class)
- public void requestCommit_readOperationalData_WithNullPathShouldThrowException() {
- DataModification dataModification = mock(DataModification.class);
- HashMap map = new HashMap();
- List list = new ArrayList();
- list.add("key");
- InstanceIdentifier key = new InstanceIdentifier(list);
- map.put(key, "value");
- when(dataModification.getOriginalOperationalData()).thenReturn(map);
- DataCommitTransaction dataCommitTrans = clusteredDS.requestCommit(dataModification);
- dataCommitTrans.finish();
- Object value = clusteredDS.readOperationalData(null);
- }
-
-}
+++ /dev/null
-<?xml version="1.0" encoding="UTF-8"?>
-<persisted-snapshots>
- <snapshots>
- <snapshot>
- <required-capabilities>
- <capability>
- urn:opendaylight:params:xml:ns:yang:controller:md:sal:dom:cluster:store?module=odl-sal-dom-clustered-store-cfg&revision=2013-10-28
- </capability>
- </required-capabilities>
- <configuration>
-
- <data xmlns="urn:ietf:params:xml:ns:netconf:base:1.0">
- <modules xmlns="urn:opendaylight:params:xml:ns:yang:controller:config">
- <module>
- <type xmlns:prefix="urn:opendaylight:params:xml:ns:yang:controller:md:sal:dom:cluster:store">
- prefix:dom-clustered-store-impl
- </type>
- <name>cluster-data-store</name>
- </module>
- </modules>
-
- <services xmlns="urn:opendaylight:params:xml:ns:yang:controller:config">
-
- </services>
- </data>
-
- </configuration>
- </snapshot>
- </snapshots>
-</persisted-snapshots>
+++ /dev/null
-<configuration scan="true">
-
- <appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender">
- <encoder>
- <pattern>%d{HH:mm:ss.SSS} [%thread] %-5level %logger{36} - %msg%n
- </pattern>
- </encoder>
- </appender>
-
- <root level="debug">
- <appender-ref ref="STDOUT" />
- </root>
-</configuration>
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.yang.gen.v1.urn.opendaylight.inventory.rev130819.nodes.NodeKey;
-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 com.google.common.base.Objects;
import com.google.common.base.Preconditions;
return new org.opendaylight.controller.sal.core.Node(NodeMapping.MD_SAL_TYPE, aDNodeId);
}
- public static NodeId toNodeId(final InstanceIdentifier<? extends Object> node) {
- Preconditions.<InstanceIdentifier<? extends Object>>checkNotNull(node);
- List<PathArgument> path = node.getPath();
- Preconditions.<List<PathArgument>>checkNotNull(path);
- int size = path.size();
- Preconditions.checkArgument(size >= 2);
- final PathArgument arg = path.get(1);
- final IdentifiableItem item = Arguments.<IdentifiableItem>checkInstanceOf(arg, IdentifiableItem.class);
- Identifier<?> key = item.getKey();
- final NodeKey nodeKey = Arguments.<NodeKey>checkInstanceOf(key, NodeKey.class);
- return nodeKey.getId();
+ public static NodeId toNodeId(final InstanceIdentifier<?> id) {
+ final NodeKey key = id.firstKeyOf(Node.class, NodeKey.class);
+ Preconditions.checkArgument(key != null, "No node identifier found in %s", id);
+ return key.getId();
}
public static String toADNodeId(final NodeId nodeId) {
- Preconditions.<NodeId>checkNotNull(nodeId);
return nodeId.getValue();
}
public static org.opendaylight.controller.sal.core.NodeConnector toADNodeConnector(final NodeConnectorRef source) throws ConstructionException {
- Preconditions.<NodeConnectorRef>checkNotNull(source);
- final InstanceIdentifier<?> path = Preconditions.<InstanceIdentifier<? extends Object>>checkNotNull(source.getValue());
- Preconditions.checkArgument(path.getPath().size() >= 3);
- final PathArgument arg = path.getPath().get(2);
- final IdentifiableItem item = Arguments.<IdentifiableItem>checkInstanceOf(arg,IdentifiableItem.class);
- final NodeConnectorKey connectorKey = Arguments.<NodeConnectorKey>checkInstanceOf(item.getKey(), NodeConnectorKey.class);
- return NodeMapping.toADNodeConnector(connectorKey.getId(), NodeMapping.toNodeId(path));
+ final InstanceIdentifier<?> id = Preconditions.checkNotNull(source.getValue());
+ final NodeConnectorKey key = id.firstKeyOf(NodeConnector.class, NodeConnectorKey.class);
+ return NodeMapping.toADNodeConnector(key.getId(), NodeMapping.toNodeId(id));
}
public static org.opendaylight.controller.sal.core.NodeConnector toADNodeConnector(final NodeConnectorId ncid, final NodeId nid) throws ConstructionException {
public static NodeConnectorRef toNodeConnectorRef(final org.opendaylight.controller.sal.core.NodeConnector nodeConnector) {
final NodeRef node = NodeMapping.toNodeRef(nodeConnector.getNode());
+ @SuppressWarnings("unchecked")
final InstanceIdentifier<Node> nodePath = ((InstanceIdentifier<Node>) node.getValue());
NodeConnectorId nodeConnectorId = null;
<!-- Clustering -->
<module>remoterpc-routingtable/implementation</module>
<module>sal-remoterpc-connector/implementation</module>
- <!--module>clustered-data-store/implementation</module>
- -->
<!-- Documentation -->
<module>sal-rest-docgen</module>
<modules>
<module>sal-binding-it</module>
<module>sal-binding-dom-it</module>
- <!--module>clustered-data-store/integrationtest</module -->
- <!--module>zeromq-routingtable/integrationtest</module -->
- <!--module>sal-remoterpc-connector/integrationtest</module -->
- <!--module>test/sal-rest-connector-it</modulei -->
</modules>
</profile>
</profiles>
* component of the controller or application supplies a concrete implementation
* of this interface.
*
- * A user-implemented component (application) which faciliates the SAL and SAL
+ * A user-implemented component (application) which facilitates the SAL and SAL
* services to access infrastructure services or providers' functionality.
*
*
for (Map.Entry<org.opendaylight.yangtools.yang.data.api.InstanceIdentifier, ? extends NormalizedNode<?, ?>> entry : normalized
.entrySet()) {
try {
- Entry<InstanceIdentifier<? extends DataObject>, DataObject> binding = getCodec().toBinding(entry);
- newMap.put(binding.getKey(), binding.getValue());
+ Optional<Entry<InstanceIdentifier<? extends DataObject>, DataObject>> potential = getCodec().toBinding(
+ entry);
+ if (potential.isPresent()) {
+ Entry<InstanceIdentifier<? extends DataObject>, DataObject> binding = potential.get();
+ newMap.put(binding.getKey(), binding.getValue());
+ }
} catch (DeserializationException e) {
LOG.warn("Failed to transform {}, omitting it", entry, e);
}
Set<InstanceIdentifier<?>> hashSet = new HashSet<>();
for (org.opendaylight.yangtools.yang.data.api.InstanceIdentifier normalizedPath : normalized) {
try {
- InstanceIdentifier<? extends DataObject> binding = getCodec().toBinding(normalizedPath);
- hashSet.add(binding);
+ Optional<InstanceIdentifier<? extends DataObject>> potential = getCodec().toBinding(normalizedPath);
+ if (potential.isPresent()) {
+ InstanceIdentifier<? extends DataObject> binding = potential.get();
+ hashSet.add(binding);
+ }
} catch (DeserializationException e) {
LOG.warn("Failed to transform {}, omitting it", normalizedPath, e);
}
}
protected Optional<DataObject> toBindingData(final InstanceIdentifier<?> path, final NormalizedNode<?, ?> data) {
- if(path.isWildcarded()) {
+ if (path.isWildcarded()) {
return Optional.absent();
}
@Override
public DataObject getOriginalSubtree() {
if (originalDataCache == null) {
- originalDataCache = toBindingData(path, domEvent.getOriginalSubtree());
+ if(domEvent.getOriginalSubtree() != null) {
+ originalDataCache = toBindingData(path, domEvent.getOriginalSubtree());
+ } else {
+ originalDataCache = Optional.absent();
+ }
}
return originalDataCache.orNull();
}
@Override
public DataObject getUpdatedSubtree() {
if (updatedDataCache == null) {
- updatedDataCache = toBindingData(path, domEvent.getUpdatedSubtree());
+ if(domEvent.getUpdatedSubtree() != null) {
+ updatedDataCache = toBindingData(path, domEvent.getUpdatedSubtree());
+ } else {
+ updatedDataCache = Optional.absent();
+ }
}
-
return updatedDataCache.orNull();
}
@Override
public String toString() {
return Objects.toStringHelper(TranslatedDataChangeEvent.class) //
- .add("created", getCreatedData()) //
- .add("updated", getUpdatedData()) //
- .add("removed", getRemovedPaths()) //
- .add("dom", domEvent) //
- .toString();
+ .add("created", getCreatedData()) //
+ .add("updated", getUpdatedData()) //
+ .add("removed", getRemovedPaths()) //
+ .add("dom", domEvent) //
+ .toString();
}
}
import java.util.concurrent.Callable;
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.yangtools.concepts.util.ClassLoaderUtils;
import org.opendaylight.yangtools.yang.binding.Augmentation;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
+import com.google.common.base.Optional;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.Iterables;
public org.opendaylight.yangtools.yang.data.api.InstanceIdentifier toNormalized(
final InstanceIdentifier<? extends DataObject> binding) {
- // Used instance-identifier codec do not support serialization of last path
+ // Used instance-identifier codec do not support serialization of last
+ // path
// argument if it is Augmentation (behaviour expected by old datastore)
// in this case, we explicitly check if last argument is augmentation
// to process it separately
}
- public InstanceIdentifier<? extends DataObject> toBinding(
+ /**
+ *
+ * Returns a Binding-Aware instance identifier from normalized
+ * instance-identifier if it is possible to create representation.
+ *
+ * Returns Optional.absent for cases where target is mixin node except
+ * augmentation.
+ *
+ */
+ public Optional<InstanceIdentifier<? extends DataObject>> toBinding(
final org.opendaylight.yangtools.yang.data.api.InstanceIdentifier normalized)
throws DeserializationException {
PathArgument lastArgument = Iterables.getLast(normalized.getPath());
- // Used instance-identifier codec do not support serialization of last path
- // argument if it is AugmentationIdentifier (behaviour expected by old datastore)
+ // Used instance-identifier codec do not support serialization of last
+ // path
+ // argument if it is AugmentationIdentifier (behaviour expected by old
+ // datastore)
// in this case, we explicitly check if last argument is augmentation
// to process it separately
if (lastArgument instanceof AugmentationIdentifier) {
return toBindingImpl(normalized);
}
- private InstanceIdentifier<? extends DataObject> toBindingAugmented(
- final org.opendaylight.yangtools.yang.data.api.InstanceIdentifier normalized) throws DeserializationException {
- InstanceIdentifier<? extends DataObject> potential = toBindingImpl(normalized);
+ private Optional<InstanceIdentifier<? extends DataObject>> toBindingAugmented(
+ final org.opendaylight.yangtools.yang.data.api.InstanceIdentifier normalized)
+ throws DeserializationException {
+ Optional<InstanceIdentifier<? extends DataObject>> potential = toBindingImpl(normalized);
// Shorthand check, if codec already supports deserialization
// of AugmentationIdentifier we will return
- if(isAugmentationIdentifier(potential)) {
+ if (potential.isPresent() && isAugmentationIdentifier(potential.get())) {
return potential;
}
+ int normalizedCount = getAugmentationCount(normalized);
AugmentationIdentifier lastArgument = (AugmentationIdentifier) Iterables.getLast(normalized.getPath());
- // Here we employ small trick - Binding-aware Codec injects an pointer to augmentation class
- // if child is referenced - so we will reference child and then shorten path.
+ // Here we employ small trick - Binding-aware Codec injects an pointer
+ // to augmentation class
+ // if child is referenced - so we will reference child and then shorten
+ // path.
+ LOG.trace("Looking for candidates to match {}", normalized);
for (QName child : lastArgument.getPossibleChildNames()) {
org.opendaylight.yangtools.yang.data.api.InstanceIdentifier childPath = new org.opendaylight.yangtools.yang.data.api.InstanceIdentifier(
- ImmutableList.<PathArgument> builder()
- .addAll(normalized.getPath()).add(new NodeIdentifier(child)).build());
+ ImmutableList.<PathArgument> builder().addAll(normalized.getPath()).add(new NodeIdentifier(child))
+ .build());
try {
+ if (isNotRepresentable(childPath)) {
+ LOG.trace("Path {} is not BI-representable, skipping it", childPath);
+ continue;
+ }
+ } catch (DataNormalizationException e) {
+ LOG.warn("Failed to denormalize path {}, skipping it", childPath, e);
+ continue;
+ }
- InstanceIdentifier<? extends DataObject> potentialPath = shortenToLastAugment(toBindingImpl(childPath));
- return potentialPath;
- } catch (Exception e) {
- LOG.trace("Unable to deserialize aug. child path for {}",childPath,e);
+ Optional<InstanceIdentifier<? extends DataObject>> baId = toBindingImpl(childPath);
+ if (!baId.isPresent()) {
+ LOG.debug("No binding-aware identifier found for path {}, skipping it", childPath);
+ continue;
}
+
+ InstanceIdentifier<? extends DataObject> potentialPath = shortenToLastAugment(baId.get());
+ int potentialAugmentCount = getAugmentationCount(potentialPath);
+ if (potentialAugmentCount == normalizedCount) {
+ LOG.trace("Found matching path {}", potentialPath);
+ return Optional.<InstanceIdentifier<? extends DataObject>> of(potentialPath);
+ }
+
+ LOG.trace("Skipping mis-matched potential path {}", potentialPath);
}
- return toBindingImpl(normalized);
+
+ LOG.trace("Failed to find augmentation matching {}", normalized);
+ return Optional.absent();
}
- private InstanceIdentifier<? extends DataObject> toBindingImpl(
+ private Optional<InstanceIdentifier<? extends DataObject>> toBindingImpl(
final org.opendaylight.yangtools.yang.data.api.InstanceIdentifier normalized)
throws DeserializationException {
org.opendaylight.yangtools.yang.data.api.InstanceIdentifier legacyPath;
+
try {
+ if (isNotRepresentable(normalized)) {
+ return Optional.absent();
+ }
legacyPath = legacyToNormalized.toLegacy(normalized);
} catch (DataNormalizationException e) {
throw new IllegalStateException("Could not denormalize path.", e);
}
LOG.trace("InstanceIdentifier Path Deserialization: Legacy representation {}, Normalized representation: {}",
legacyPath, normalized);
- return bindingToLegacy.fromDataDom(legacyPath);
+ return Optional.<InstanceIdentifier<? extends DataObject>> of(bindingToLegacy.fromDataDom(legacyPath));
+ }
+
+ private boolean isNotRepresentable(final org.opendaylight.yangtools.yang.data.api.InstanceIdentifier normalized)
+ throws DataNormalizationException {
+ DataNormalizationOperation<?> op = findNormalizationOperation(normalized);
+ if( op.isMixin() && op.getIdentifier() instanceof NodeIdentifier) {
+ return true;
+ }
+ if(op.isLeaf()) {
+ return true;
+ }
+ return false;
+ }
+
+ private DataNormalizationOperation<?> findNormalizationOperation(
+ final org.opendaylight.yangtools.yang.data.api.InstanceIdentifier normalized)
+ throws DataNormalizationException {
+ DataNormalizationOperation<?> current = legacyToNormalized.getRootOperation();
+ for (PathArgument arg : normalized.getPath()) {
+ current = current.getChild(arg);
+ }
+ return current;
}
private static final Entry<org.opendaylight.yangtools.yang.binding.InstanceIdentifier<? extends DataObject>, DataObject> toEntry(
public DataObject toBinding(final InstanceIdentifier<?> path, final NormalizedNode<?, ?> normalizedNode)
throws DeserializationException {
CompositeNode legacy = null;
- if(isAugmentationIdentifier(path) && normalizedNode instanceof AugmentationNode) {
+ if (isAugmentationIdentifier(path) && normalizedNode instanceof AugmentationNode) {
QName augIdentifier = BindingReflections.findQName(path.getTargetType());
ContainerNode virtualNode = Builders.containerBuilder() //
.withNodeIdentifier(new NodeIdentifier(augIdentifier)) //
return legacyToNormalized;
}
- public Entry<org.opendaylight.yangtools.yang.binding.InstanceIdentifier<? extends DataObject>, DataObject> toBinding(
+ public Optional<Entry<org.opendaylight.yangtools.yang.binding.InstanceIdentifier<? extends DataObject>, DataObject>> toBinding(
final Entry<org.opendaylight.yangtools.yang.data.api.InstanceIdentifier, ? extends NormalizedNode<?, ?>> normalized)
throws DeserializationException {
- InstanceIdentifier<? extends DataObject> bindingPath = toBinding(normalized.getKey());
- DataObject bindingData = toBinding(bindingPath, normalized.getValue());
- return toEntry(bindingPath, bindingData);
+ Optional<InstanceIdentifier<? extends DataObject>> potentialPath = toBinding(normalized.getKey());
+ if (potentialPath.isPresent()) {
+ InstanceIdentifier<? extends DataObject> bindingPath = potentialPath.get();
+ DataObject bindingData = toBinding(bindingPath, normalized.getValue());
+ if (bindingData == null) {
+ LOG.warn("Failed to deserialize {} to Binding format. Binding path is: {}", normalized, bindingPath);
+ }
+ return Optional.of(toEntry(bindingPath, bindingData));
+ } else {
+ return Optional.absent();
+ }
}
@Override
org.opendaylight.yangtools.yang.data.api.InstanceIdentifier processed = toNormalizedImpl(augPath);
// If used instance identifier codec added supports for deserialization
// of last AugmentationIdentifier we will just reuse it
- if(isAugmentationIdentifier(processed)) {
+ if (isAugmentationIdentifier(processed)) {
return processed;
}
- // Here we employ small trick - DataNormalizer injecst augmentation identifier if child is
- // also part of the path (since using a child we can safely identify augmentation)
+ // Here we employ small trick - DataNormalizer injects augmentation
+ // identifier if child is
+ // also part of the path (since using a child we can safely identify
+ // augmentation)
// so, we scan augmentation for children add it to path
// and use original algorithm, then shorten it to last augmentation
- for (@SuppressWarnings("rawtypes") Class augChild : getAugmentationChildren(augPath.getTargetType())) {
+ for (@SuppressWarnings("rawtypes")
+ Class augChild : getAugmentationChildren(augPath.getTargetType())) {
@SuppressWarnings("unchecked")
InstanceIdentifier<?> childPath = augPath.child(augChild);
org.opendaylight.yangtools.yang.data.api.InstanceIdentifier normalized = toNormalizedImpl(childPath);
return processed;
}
-
-
private org.opendaylight.yangtools.yang.data.api.InstanceIdentifier shortenToLastAugmentation(
final org.opendaylight.yangtools.yang.data.api.InstanceIdentifier normalized) {
int position = 0;
final InstanceIdentifier<? extends DataObject> binding) {
int position = 0;
int foundPosition = -1;
- for(org.opendaylight.yangtools.yang.binding.InstanceIdentifier.PathArgument arg : binding.getPathArguments()) {
+ for (org.opendaylight.yangtools.yang.binding.InstanceIdentifier.PathArgument arg : binding.getPathArguments()) {
position++;
if (isAugmentation(arg.getType())) {
foundPosition = position;
return InstanceIdentifier.create(Iterables.limit(binding.getPathArguments(), foundPosition));
}
-
-
private org.opendaylight.yangtools.yang.data.api.InstanceIdentifier toNormalizedImpl(
final InstanceIdentifier<? extends DataObject> binding) {
final org.opendaylight.yangtools.yang.data.api.InstanceIdentifier legacyPath = bindingToLegacy
try {
return ClassLoaderUtils.withClassLoader(method.getDeclaringClass().getClassLoader(),
new Callable<Class>() {
-
- @SuppressWarnings("rawtypes")
@Override
- public Class call() throws Exception {
+ public Class call() {
Type listResult = ClassLoaderUtils.getFirstGenericParameter(method
.getGenericReturnType());
if (listResult instanceof Class
return InstanceIdentifier.create(wildArgs);
}
-
private static boolean isAugmentation(final Class<? extends DataObject> type) {
return Augmentation.class.isAssignableFrom(type);
}
- private static boolean isAugmentationIdentifier(final InstanceIdentifier<?> path) {
- return Augmentation.class.isAssignableFrom(path.getTargetType());
+ private static boolean isAugmentationIdentifier(final InstanceIdentifier<?> potential) {
+ return Augmentation.class.isAssignableFrom(potential.getTargetType());
}
private boolean isAugmentationIdentifier(final org.opendaylight.yangtools.yang.data.api.InstanceIdentifier processed) {
return Iterables.getLast(processed.getPath()) instanceof AugmentationIdentifier;
}
+
+ private static int getAugmentationCount(final InstanceIdentifier<?> potential) {
+ int count = 0;
+ for(org.opendaylight.yangtools.yang.binding.InstanceIdentifier.PathArgument arg : potential.getPathArguments()) {
+ if(isAugmentation(arg.getType())) {
+ count++;
+ }
+
+ }
+ return count;
+ }
+
+ private static int getAugmentationCount(final org.opendaylight.yangtools.yang.data.api.InstanceIdentifier potential) {
+ int count = 0;
+ for(PathArgument arg : potential.getPath()) {
+ if(arg instanceof AugmentationIdentifier) {
+ count++;
+ }
+ }
+ return count;
+ }
}
Provider, //
AutoCloseable {
-
-
private final Logger LOG = LoggerFactory.getLogger(BindingIndependentConnector.class);
-
private static final org.opendaylight.yangtools.yang.data.api.InstanceIdentifier ROOT_BI = org.opendaylight.yangtools.yang.data.api.InstanceIdentifier
.builder().toInstance();
private DataModificationTransaction createBindingToDomTransaction(
final DataModification<InstanceIdentifier<? extends DataObject>, DataObject> source) {
DataModificationTransaction target = biDataService.beginTransaction();
- LOG.debug("Created DOM Transaction {} for {},", target.getIdentifier(),source.getIdentifier());
+ LOG.debug("Created DOM Transaction {} for {},", target.getIdentifier(), source.getIdentifier());
for (InstanceIdentifier<? extends DataObject> entry : source.getRemovedConfigurationData()) {
org.opendaylight.yangtools.yang.data.api.InstanceIdentifier biEntry = mappingService.toDataDom(entry);
target.removeConfigurationData(biEntry);
- LOG.debug("Delete of Binding Configuration Data {} is translated to {}",entry,biEntry);
+ LOG.debug("Delete of Binding Configuration Data {} is translated to {}", entry, biEntry);
}
for (InstanceIdentifier<? extends DataObject> entry : source.getRemovedOperationalData()) {
org.opendaylight.yangtools.yang.data.api.InstanceIdentifier biEntry = mappingService.toDataDom(entry);
target.removeOperationalData(biEntry);
- LOG.debug("Delete of Binding Operational Data {} is translated to {}",entry,biEntry);
+ LOG.debug("Delete of Binding Operational Data {} is translated to {}", entry, biEntry);
}
for (Entry<InstanceIdentifier<? extends DataObject>, DataObject> entry : source.getUpdatedConfigurationData()
.entrySet()) {
Entry<org.opendaylight.yangtools.yang.data.api.InstanceIdentifier, CompositeNode> biEntry = mappingService
.toDataDom(entry);
target.putConfigurationData(biEntry.getKey(), biEntry.getValue());
- LOG.debug("Update of Binding Configuration Data {} is translated to {}",entry,biEntry);
+ LOG.debug("Update of Binding Configuration Data {} is translated to {}", entry, biEntry);
}
for (Entry<InstanceIdentifier<? extends DataObject>, DataObject> entry : source.getUpdatedOperationalData()
.entrySet()) {
Entry<org.opendaylight.yangtools.yang.data.api.InstanceIdentifier, CompositeNode> biEntry = mappingService
.toDataDom(entry);
target.putOperationalData(biEntry.getKey(), biEntry.getValue());
- LOG.debug("Update of Binding Operational Data {} is translated to {}",entry,biEntry);
+ LOG.debug("Update of Binding Operational Data {} is translated to {}", entry, biEntry);
}
return target;
return biDataService;
}
- protected void setDomDataService(final org.opendaylight.controller.sal.core.api.data.DataProviderService biDataService) {
+ protected void setDomDataService(
+ final org.opendaylight.controller.sal.core.api.data.DataProviderService biDataService) {
this.biDataService = biDataService;
}
}
public void startDataForwarding() {
- if(baDataService instanceof AbstractForwardedDataBroker) {
+ if (baDataService instanceof AbstractForwardedDataBroker) {
dataForwarding = true;
return;
}
final DataProviderService baData;
if (baDataService instanceof BindingMountPointImpl) {
- baData = ((BindingMountPointImpl)baDataService).getDataBrokerImpl();
+ baData = ((BindingMountPointImpl) baDataService).getDataBrokerImpl();
LOG.debug("Extracted BA Data provider {} from mount point {}", baData, baDataService);
} else {
baData = baDataService;
}
DataModificationTransaction domTransaction = createBindingToDomTransaction(bindingTransaction);
BindingToDomTransaction wrapped = new BindingToDomTransaction(domTransaction, bindingTransaction);
- LOG.trace("Forwarding Binding Transaction: {} as DOM Transaction: {} .", bindingTransaction.getIdentifier(),
- domTransaction.getIdentifier());
+ LOG.trace("Forwarding Binding Transaction: {} as DOM Transaction: {} .",
+ bindingTransaction.getIdentifier(), domTransaction.getIdentifier());
return wrapped;
}
}
DataCommitHandler<org.opendaylight.yangtools.yang.data.api.InstanceIdentifier, CompositeNode> {
@Override
- public void onRegister(final DataCommitHandlerRegistration<InstanceIdentifier<? extends DataObject>, DataObject> registration) {
+ public void onRegister(
+ final DataCommitHandlerRegistration<InstanceIdentifier<? extends DataObject>, DataObject> registration) {
org.opendaylight.yangtools.yang.data.api.InstanceIdentifier domPath = mappingService.toDataDom(registration
.getPath());
}
@Override
- public void onUnregister(final DataCommitHandlerRegistration<InstanceIdentifier<? extends DataObject>, DataObject> registration) {
+ public void onUnregister(
+ final DataCommitHandlerRegistration<InstanceIdentifier<? extends DataObject>, DataObject> registration) {
// NOOP for now
// FIXME: do registration based on only active commit handlers.
}
*
*/
private class DomToBindingRpcForwardingManager implements
- RouteChangeListener<RpcContextIdentifier, InstanceIdentifier<?>>,
- RouterInstantiationListener,
+ RouteChangeListener<RpcContextIdentifier, InstanceIdentifier<?>>, RouterInstantiationListener,
GlobalRpcRegistrationListener {
private final Map<Class<? extends RpcService>, DomToBindingRpcForwarder> forwarders = new WeakHashMap<>();
}
} catch (Exception e) {
- LOG.error("Could not forward Rpcs of type {}", service.getName(),e);
+ LOG.error("Could not forward Rpcs of type {}", service.getName(), e);
}
registrations = ImmutableSet.of();
}
* @param service
* @param context
*/
- public DomToBindingRpcForwarder(final Class<? extends RpcService> service, final Class<? extends BaseIdentity> context) {
+ public DomToBindingRpcForwarder(final Class<? extends RpcService> service,
+ final Class<? extends BaseIdentity> context) {
this.rpcServiceType = new WeakReference<Class<? extends RpcService>>(service);
this.supportedRpcs = mappingService.getRpcQNamesFor(service);
Builder<RoutedRpcRegistration> registrationsBuilder = ImmutableSet
registrations = registrationsBuilder.build();
}
- public void registerPaths(final Class<? extends BaseIdentity> context, final Class<? extends RpcService> service,
- final Set<InstanceIdentifier<?>> set) {
+ public void registerPaths(final Class<? extends BaseIdentity> context,
+ final Class<? extends RpcService> service, final Set<InstanceIdentifier<?>> set) {
QName ctx = BindingReflections.findQName(context);
for (org.opendaylight.yangtools.yang.data.api.InstanceIdentifier path : FluentIterable.from(set).transform(
toDOMInstanceIdentifier)) {
}
}
-
@Override
public Object invoke(final Object proxy, final Method method, final Object[] args) throws Throwable {
if (EQUALS_METHOD.equals(method)) {
}
}
-
@Override
public ListenableFuture<RpcResult<CompositeNode>> invokeRpc(final QName rpc, final CompositeNode domInput) {
checkArgument(rpc != null);
strategy = new DefaultInvocationStrategy(rpc, targetMethod, outputClass.get(), inputClass
.get());
} else {
- strategy = new NoInputNoOutputInvocationStrategy(rpc, targetMethod);
+ strategy = new NoInputInvocationStrategy(rpc, targetMethod, outputClass.get());
}
- } else if(inputClass.isPresent()){
- strategy = new NoOutputInvocationStrategy(rpc,targetMethod, inputClass.get());
+ } else if (inputClass.isPresent()) {
+ strategy = new NoOutputInvocationStrategy(rpc, targetMethod, inputClass.get());
} else {
- strategy = new NoInputNoOutputInvocationStrategy(rpc,targetMethod);
+ strategy = new NoInputNoOutputInvocationStrategy(rpc, targetMethod);
}
return strategy;
}
public abstract RpcResult<CompositeNode> uncheckedInvoke(RpcService rpcService, CompositeNode domInput)
throws Exception;
- public RpcResult<CompositeNode> invokeOn(final RpcService rpcService, final CompositeNode domInput) throws Exception {
+ public RpcResult<CompositeNode> invokeOn(final RpcService rpcService, final CompositeNode domInput)
+ throws Exception {
return uncheckedInvoke(rpcService, domInput);
}
}
@SuppressWarnings("unchecked")
@Override
- public RpcResult<CompositeNode> uncheckedInvoke(final RpcService rpcService, final CompositeNode domInput) throws Exception {
+ public RpcResult<CompositeNode> uncheckedInvoke(final RpcService rpcService, final CompositeNode domInput)
+ throws Exception {
DataContainer bindingInput = mappingService.dataObjectFromDataDom(inputClass.get(), domInput);
Future<RpcResult<?>> futureResult = (Future<RpcResult<?>>) targetMethod.invoke(rpcService, bindingInput);
if (futureResult == null) {
RpcResult<?> bindingResult = futureResult.get();
final Object resultObj = bindingResult.getResult();
if (resultObj instanceof DataObject) {
- final CompositeNode output = mappingService.toDataDom((DataObject)resultObj);
- return Rpcs.getRpcResult(true, output, Collections.<RpcError>emptySet());
+ final CompositeNode output = mappingService.toDataDom((DataObject) resultObj);
+ return Rpcs.getRpcResult(true, output, Collections.<RpcError> emptySet());
}
return Rpcs.getRpcResult(true);
}
@Override
public ListenableFuture<RpcResult<?>> forwardToDomBroker(final DataObject input) {
- if(biRpcRegistry == null) {
+ if (biRpcRegistry == null) {
return Futures.<RpcResult<?>> immediateFuture(Rpcs.getRpcResult(false));
}
CompositeNode xml = mappingService.toDataDom(input);
CompositeNode wrappedXml = ImmutableCompositeNode.create(rpc, ImmutableList.<Node<?>> of(xml));
- return Futures.transform(biRpcRegistry.invokeRpc(rpc, wrappedXml), new Function<RpcResult<CompositeNode>, RpcResult<?>>() {
- @Override
- public RpcResult<?> apply(RpcResult<CompositeNode> input) {
- Object baResultValue = null;
- if (input.getResult() != null) {
- baResultValue = mappingService.dataObjectFromDataDom(outputClass.get(), input.getResult());
- }
- return Rpcs.getRpcResult(input.isSuccessful(), baResultValue, input.getErrors());
- }
- });
+ return Futures.transform(biRpcRegistry.invokeRpc(rpc, wrappedXml),
+ new Function<RpcResult<CompositeNode>, RpcResult<?>>() {
+ @Override
+ public RpcResult<?> apply(final RpcResult<CompositeNode> input) {
+ Object baResultValue = null;
+ if (input.getResult() != null) {
+ baResultValue = mappingService.dataObjectFromDataDom(outputClass.get(),
+ input.getResult());
+ }
+ return Rpcs.getRpcResult(input.isSuccessful(), baResultValue, input.getErrors());
+ }
+ });
+ }
+ }
+
+ private class NoInputInvocationStrategy extends RpcInvocationStrategy {
+
+ @SuppressWarnings("rawtypes")
+ private final WeakReference<Class> outputClass;
+
+ @SuppressWarnings({ "rawtypes", "unchecked" })
+ public NoInputInvocationStrategy(final QName rpc, final Method targetMethod, final Class<?> outputClass) {
+ super(rpc, targetMethod);
+ this.outputClass = new WeakReference(outputClass);
+ }
+
+ @SuppressWarnings("unchecked")
+ @Override
+ public RpcResult<CompositeNode> uncheckedInvoke(final RpcService rpcService, final CompositeNode domInput)
+ throws Exception {
+ Future<RpcResult<?>> futureResult = (Future<RpcResult<?>>) targetMethod.invoke(rpcService);
+ if (futureResult == null) {
+ return Rpcs.getRpcResult(false);
+ }
+ RpcResult<?> bindingResult = futureResult.get();
+ final Object resultObj = bindingResult.getResult();
+ if (resultObj instanceof DataObject) {
+ final CompositeNode output = mappingService.toDataDom((DataObject) resultObj);
+ return Rpcs.getRpcResult(true, output, Collections.<RpcError> emptySet());
+ }
+ return Rpcs.getRpcResult(true);
+ }
+
+ @Override
+ public Future<RpcResult<?>> forwardToDomBroker(final DataObject input) {
+ if (biRpcRegistry != null) {
+ CompositeNode xml = mappingService.toDataDom(input);
+ CompositeNode wrappedXml = ImmutableCompositeNode.create(rpc, ImmutableList.<Node<?>> of(xml));
+ return Futures.transform(biRpcRegistry.invokeRpc(rpc, wrappedXml),
+ new Function<RpcResult<CompositeNode>, RpcResult<?>>() {
+ @Override
+ public RpcResult<?> apply(final RpcResult<CompositeNode> input) {
+ Object baResultValue = null;
+ if (input.getResult() != null) {
+ baResultValue = mappingService.dataObjectFromDataDom(outputClass.get(),
+ input.getResult());
+ }
+ return Rpcs.getRpcResult(input.isSuccessful(), baResultValue, input.getErrors());
+ }
+ });
+ } else {
+ return Futures.<RpcResult<?>> immediateFuture(Rpcs.getRpcResult(false));
+ }
}
}
}
@Override
- public RpcResult<CompositeNode> uncheckedInvoke(final RpcService rpcService, final CompositeNode domInput) throws Exception {
+ public RpcResult<CompositeNode> uncheckedInvoke(final RpcService rpcService, final CompositeNode domInput)
+ throws Exception {
@SuppressWarnings("unchecked")
Future<RpcResult<Void>> result = (Future<RpcResult<Void>>) targetMethod.invoke(rpcService);
RpcResult<Void> bindingResult = result.get();
private class NoOutputInvocationStrategy extends RpcInvocationStrategy {
-
@SuppressWarnings("rawtypes")
private final WeakReference<Class> inputClass;
@SuppressWarnings({ "rawtypes", "unchecked" })
public NoOutputInvocationStrategy(final QName rpc, final Method targetMethod,
final Class<? extends DataContainer> inputClass) {
- super(rpc,targetMethod);
+ super(rpc, targetMethod);
this.inputClass = new WeakReference(inputClass);
}
-
@Override
- public RpcResult<CompositeNode> uncheckedInvoke(final RpcService rpcService, final CompositeNode domInput) throws Exception {
+ public RpcResult<CompositeNode> uncheckedInvoke(final RpcService rpcService, final CompositeNode domInput)
+ throws Exception {
DataContainer bindingInput = mappingService.dataObjectFromDataDom(inputClass.get(), domInput);
Future<RpcResult<?>> result = (Future<RpcResult<?>>) targetMethod.invoke(rpcService, bindingInput);
if (result == null) {
@Override
public ListenableFuture<RpcResult<?>> forwardToDomBroker(final DataObject input) {
- if(biRpcRegistry == null) {
+ if (biRpcRegistry == null) {
return Futures.<RpcResult<?>> immediateFuture(Rpcs.getRpcResult(false));
}
CompositeNode xml = mappingService.toDataDom(input);
- CompositeNode wrappedXml = ImmutableCompositeNode.create(rpc,ImmutableList.<Node<?>>of(xml));
+ CompositeNode wrappedXml = ImmutableCompositeNode.create(rpc, ImmutableList.<Node<?>> of(xml));
- return Futures.transform(biRpcRegistry.invokeRpc(rpc, wrappedXml), new Function<RpcResult<CompositeNode>, RpcResult<?>>() {
- @Override
- public RpcResult<?> apply(RpcResult<CompositeNode> input) {
- return Rpcs.<Void>getRpcResult(input.isSuccessful(), null, input.getErrors());
- }
- });
+ return Futures.transform(biRpcRegistry.invokeRpc(rpc, wrappedXml),
+ new Function<RpcResult<CompositeNode>, RpcResult<?>>() {
+ @Override
+ public RpcResult<?> apply(final RpcResult<CompositeNode> input) {
+ return Rpcs.<Void> getRpcResult(input.isSuccessful(), null, input.getErrors());
+ }
+ });
}
}
--- /dev/null
+package org.opendaylight.controller.sal.binding.test.bugfix;
+
+import static org.junit.Assert.assertFalse;
+
+import java.util.concurrent.ExecutionException;
+
+import org.junit.Test;
+import org.opendaylight.controller.md.sal.common.api.data.DataChangeEvent;
+import org.opendaylight.controller.sal.binding.api.data.DataChangeListener;
+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.flow.inventory.rev130819.FlowCapableNode;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.FlowId;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.tables.Table;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.tables.TableKey;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.tables.table.Flow;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.tables.table.FlowBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.tables.table.FlowKey;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.statistics.rev130819.FlowStatisticsData;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.statistics.rev130819.FlowStatisticsDataBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.statistics.rev130819.flow.statistics.FlowStatisticsBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.types.rev131026.flow.MatchBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.NodeId;
+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.yangtools.concepts.ListenerRegistration;
+import org.opendaylight.yangtools.yang.binding.DataObject;
+import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
+
+import com.google.common.util.concurrent.SettableFuture;
+
+public class DeleteNestedAugmentationListenParentTest extends AbstractDataServiceTest {
+
+ private static final NodeKey NODE_KEY = new NodeKey(new NodeId("foo"));
+
+ private static final TableKey TABLE_KEY = new TableKey((short) 0);
+
+ private static final FlowKey FLOW_KEY = new FlowKey(new FlowId("100"));
+
+ private static final InstanceIdentifier<FlowCapableNode> LISTENER_PATH = InstanceIdentifier.builder(Nodes.class) //
+ .child(Node.class)
+ .augmentation(FlowCapableNode.class).build();
+
+
+ private static final InstanceIdentifier<FlowCapableNode> NODE_AUGMENT_PATH = InstanceIdentifier.builder(Nodes.class)
+ .child(Node.class,NODE_KEY)
+ .augmentation(FlowCapableNode.class)
+ .build();
+
+ private static final InstanceIdentifier<Flow> FLOW_PATH = NODE_AUGMENT_PATH.builder()
+ .child(Table.class,TABLE_KEY)
+ .child(Flow.class,FLOW_KEY)
+ .build();
+
+
+ @Test
+ public void deleteChildListenParent() throws InterruptedException, ExecutionException {
+ DataModificationTransaction initTx = baDataService.beginTransaction();
+
+ initTx.putOperationalData(FLOW_PATH, flow());
+ initTx.commit().get();
+
+ final SettableFuture<DataChangeEvent<InstanceIdentifier<?>, DataObject>> event = SettableFuture.create();
+
+ ListenerRegistration<DataChangeListener> listenerReg = baDataService.registerDataChangeListener(FLOW_PATH, new DataChangeListener() {
+
+ @Override
+ public void onDataChanged(final DataChangeEvent<InstanceIdentifier<?>, DataObject> change) {
+ event.set(change);
+ }
+ });
+
+ DataModificationTransaction deleteTx = baDataService.beginTransaction();
+ deleteTx.removeOperationalData(FLOW_PATH.augmentation(FlowStatisticsData.class));
+ deleteTx.commit().get();
+
+ DataChangeEvent<InstanceIdentifier<?>, DataObject> receivedEvent = event.get();
+ assertFalse(receivedEvent.getRemovedOperationalData().contains(NODE_AUGMENT_PATH));
+ }
+
+ private Flow flow() {
+ FlowBuilder builder = new FlowBuilder()
+ .setKey(FLOW_KEY)
+ .addAugmentation(FlowStatisticsData.class,new FlowStatisticsDataBuilder()
+ .setFlowStatistics(new FlowStatisticsBuilder()
+ .setBarrier(true)
+ .setMatch(new MatchBuilder()
+ .build())
+ .build())
+ .build())
+ ;//.build();
+ return builder.build();
+ }
+
+}
\ No newline at end of file
+++ /dev/null
-<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
- xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
- <modelVersion>4.0.0</modelVersion>
- <parent>
- <groupId>org.opendaylight.controller</groupId>
- <artifactId>sal-parent</artifactId>
- <version>1.0-SNAPSHOT</version>
- </parent>
- <artifactId>sal-binding-spi</artifactId>
- <scm>
- <connection>scm:git:ssh://git.opendaylight.org:29418/controller.git</connection>
- <developerConnection>scm:git:ssh://git.opendaylight.org:29418/controller.git</developerConnection>
- <url>https://wiki.opendaylight.org/view/OpenDaylight_Controller:MD-SAL</url>
- </scm>
-
- <dependencies>
- <dependency>
- <groupId>org.opendaylight.controller</groupId>
- <artifactId>sal-binding-api</artifactId>
- <version>1.0-SNAPSHOT</version>
- </dependency>
- <dependency>
- <groupId>org.opendaylight.controller</groupId>
- <artifactId>sal-core-api</artifactId>
- <version>1.0-SNAPSHOT</version>
- </dependency>
- <dependency>
- <groupId>org.opendaylight.controller</groupId>
- <artifactId>concepts-lang</artifactId>
- <version>0.5-SNAPSHOT</version>
- </dependency>
- </dependencies>
-</project>
+++ /dev/null
-/*
- * 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.sal.binding.spi;
-
-import org.opendaylight.controller.concepts.lang.Transformer;
-import org.opendaylight.yangtools.yang.binding.DataObject;
-import org.opendaylight.yangtools.yang.common.QName;
-import org.opendaylight.yangtools.yang.data.api.CompositeNode;
-
-public interface DataDomToJavaTransformer<P extends DataObject> extends Transformer<CompositeNode, P> {
-
- /**
- * Returns a QName of valid input composite node.
- *
- * @return
- */
- QName getQName();
-}
+++ /dev/null
-/*
- * 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.sal.binding.spi;
-
-import org.opendaylight.controller.concepts.lang.InputClassBasedTransformer;
-import org.opendaylight.yangtools.yang.binding.DataObject;
-import org.opendaylight.yangtools.yang.data.api.CompositeNode;
-
-public interface JavaToDataDomTransformer<I extends DataObject> extends
- InputClassBasedTransformer<DataObject, I, CompositeNode> {
-}
+++ /dev/null
-/*
- * 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.sal.binding.spi;
-
-import org.opendaylight.yangtools.yang.binding.DataObject;
-import org.opendaylight.yangtools.yang.common.QName;
-import org.opendaylight.yangtools.yang.data.api.CompositeNode;
-/**
- * Translator between Binding-Independent format and generated Binding Data Objects
- *
- *
- *
- *
- * @param <T> Result Type
- */
-public interface Mapper<T extends DataObject> {
-
- QName getQName();
- Class<T> getDataObjectClass();
- T objectFromDom(CompositeNode object);
-
- /**
- *
- * @param obj
- * @return
- * @throws IllegalArgumentException
- */
- CompositeNode domFromObject(DataObject obj) throws IllegalArgumentException;
-
-}
+++ /dev/null
-/*
- * 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.sal.binding.spi;
-
-import org.opendaylight.yangtools.yang.binding.DataObject;
-import org.opendaylight.yangtools.yang.binding.RpcService;
-import org.opendaylight.yangtools.yang.common.QName;
-import org.opendaylight.yangtools.yang.data.api.CompositeNode;
-
-public interface MappingProvider {
-
- <T extends DataObject> Mapper<T> mapperForClass(Class<T> type);
- Mapper<DataObject> mapperForQName(QName name);
-
- /**
- * Returns {@link RpcMapper} associated to class
- *
- * @param type Class for which RpcMapper should provide mapping
- * @return
- */
- <T extends RpcService> RpcMapper<T> rpcMapperForClass(Class<T> type);
-
- /**
- * Returns {@link RpcMapper} associated to the {@link RpcService} proxy.
- *
- * @param proxy
- * @return
- */
- RpcMapper<? extends RpcService> rpcMapperForProxy(RpcService proxy);
-
- /**
- *
- *
- * @param rpc
- * @param inputNode
- * @return
- */
- RpcMapper<? extends RpcService> rpcMapperForData(QName rpc,
- CompositeNode inputNode);
-
- <T extends MappingExtension> MappingExtensionFactory<T> getExtensionFactory(Class<T> cls);
-
- public interface MappingExtension {
-
- }
-
- public interface MappingExtensionFactory<T> {
- T forClass(Class<?> obj);
- }
-
-
-
-}
+++ /dev/null
-/*
- * 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.sal.binding.spi;
-
-import java.util.Set;
-import java.util.concurrent.Future;
-
-import org.opendaylight.controller.sal.binding.api.BindingAwareBroker;
-import org.opendaylight.yangtools.yang.binding.DataObject;
-import org.opendaylight.yangtools.yang.binding.RpcService;
-import org.opendaylight.yangtools.yang.common.QName;
-import org.opendaylight.yangtools.yang.common.RpcResult;
-
-public interface RpcMapper<T extends RpcService> {
-
- Set<QName> getRpcQNames();
-
- /**
- * Returns a class object representing subinterface
- * to whom, this mapper is assigned.
- *
- * @return
- */
- Class<T> getServiceClass();
-
- /**
- * Returns a Binding Mapper for Rpc Input Data
- * @return
- */
- Mapper<?> getInputMapper();
- /**
- * Returns a Binding Mapper for Rpc Output Data
- *
- * @return
- */
- Mapper<?> getOutputMapper();
-
- /**
- * Returns a consumer proxy, which is responsible
- * for invoking the rpc functionality of {@link BindingAwareBroker} implementation.
- *
- * @return Proxy of {@link RpcService} assigned to this mapper.
- */
- T getConsumerProxy(RpcProxyInvocationHandler handler);
-
- /**
- * Invokes the method of RpcService representing the supplied rpc.
- *
- * @param rpc QName of Rpc
- * @param impl Implementation of RpcService on which the method should be invoked
- * @param baInput Input Data to RPC method
- * @return Result of RPC invocation.
- */
- RpcResult<? extends DataObject> invokeRpcImplementation(QName rpc,
- RpcService impl, DataObject baInput);
-
- public interface RpcProxyInvocationHandler {
-
- Future<RpcResult<? extends DataObject>> invokeRpc(RpcService proxy, QName rpc, DataObject input);
- }
-}
import org.opendaylight.yangtools.yang.model.api.ListSchemaNode;
import org.opendaylight.yangtools.yang.model.api.SchemaContext;
+import com.google.common.base.Optional;
import com.google.common.collect.FluentIterable;
import com.google.common.collect.ImmutableMap;
import com.google.common.collect.ImmutableSet;
public abstract NormalizedNode<?, ?> normalize(Node<?> legacyData);
+ public abstract boolean isLeaf();
+
private static abstract class SimpleTypeNormalization<T extends PathArgument> extends DataNormalizationOperation<T> {
protected SimpleTypeNormalization(final T identifier) {
return null;
}
+ @Override
+ public boolean isLeaf() {
+ return true;
+ }
+
}
private static final class LeafNormalization extends SimpleTypeNormalization<NodeIdentifier> {
return builder.build();
}
+ @Override
+ public boolean isLeaf() {
+ return false;
+ }
+
@SuppressWarnings("rawtypes")
protected abstract NormalizedNodeContainerBuilder createBuilder(final CompositeNode compositeNode);
if (potential != null) {
return potential;
}
- potential = fromSchema(schema, child);
+ potential = fromLocalSchema(child);
return register(potential);
}
+ private DataNormalizationOperation<?> fromLocalSchema(final PathArgument child) throws DataNormalizationException {
+ if (child instanceof AugmentationIdentifier) {
+ return fromSchemaAndQNameChecked(schema, ((AugmentationIdentifier) child).getPossibleChildNames()
+ .iterator().next());
+ }
+ return fromSchemaAndQNameChecked(schema, child.getNodeType());
+ }
+
@Override
public DataNormalizationOperation<?> getChild(final QName child) throws DataNormalizationException {
DataNormalizationOperation<?> potential = byQName.get(child);
if (potential != null) {
return potential;
}
- potential = fromSchemaAndPathArgument(schema, child);
+ potential = fromLocalSchemaAndQName(schema, child);
return register(potential);
}
+ protected DataNormalizationOperation<?> fromLocalSchemaAndQName(final DataNodeContainer schema2, final QName child) throws DataNormalizationException {
+ return fromSchemaAndQNameChecked(schema2, child);
+ }
+
private DataNormalizationOperation<?> register(final DataNormalizationOperation<?> potential) {
if (potential != null) {
byArg.put(potential.getIdentifier(), potential);
}
}
- private static final class AugmentationNormalization extends MixinNormalizationOp<AugmentationIdentifier> {
-
- private final Map<QName, DataNormalizationOperation<?>> byQName;
- private final Map<PathArgument, DataNormalizationOperation<?>> byArg;
+ private static final class AugmentationNormalization extends DataContainerNormalizationOperation<AugmentationIdentifier> {
public AugmentationNormalization(final AugmentationSchema augmentation, final DataNodeContainer schema) {
- super(augmentationIdentifierFrom(augmentation));
-
- ImmutableMap.Builder<QName, DataNormalizationOperation<?>> byQNameBuilder = ImmutableMap.builder();
- ImmutableMap.Builder<PathArgument, DataNormalizationOperation<?>> byArgBuilder = ImmutableMap.builder();
-
- for (DataSchemaNode augNode : augmentation.getChildNodes()) {
- DataSchemaNode resolvedNode = schema.getDataChildByName(augNode.getQName());
- DataNormalizationOperation<?> resolvedOp = fromDataSchemaNode(resolvedNode);
- byArgBuilder.put(resolvedOp.getIdentifier(), resolvedOp);
- for (QName resQName : resolvedOp.getQNameIdentifiers()) {
- byQNameBuilder.put(resQName, resolvedOp);
- }
- }
- byQName = byQNameBuilder.build();
- byArg = byArgBuilder.build();
-
+ //super();
+ super(augmentationIdentifierFrom(augmentation), augmentationProxy(augmentation,schema));
}
@Override
- public DataNormalizationOperation<?> getChild(final PathArgument child) {
- return byArg.get(child);
+ public boolean isMixin() {
+ return true;
}
+
+
@Override
- public DataNormalizationOperation<?> getChild(final QName child) {
- return byQName.get(child);
+ protected DataNormalizationOperation<?> fromLocalSchemaAndQName(final DataNodeContainer schema, final QName child)
+ throws DataNormalizationException {
+ Optional<DataSchemaNode> potential = findChildSchemaNode(schema, child);
+ if (!potential.isPresent()) {
+ return null;
+ }
+
+ DataSchemaNode result = potential.get();
+ // We try to look up if this node was added by augmentation
+ if ((schema instanceof DataSchemaNode) && result.isAugmenting()) {
+ return fromAugmentation(schema, (AugmentationTarget) schema, result);
+ }
+ return fromDataSchemaNode(result);
}
@Override
}
}
- private static DataNormalizationOperation<?> fromSchemaAndPathArgument(final DataNodeContainer schema,
- final QName child) throws DataNormalizationException {
- DataSchemaNode potential = schema.getDataChildByName(child);
+ private static final Optional<DataSchemaNode> findChildSchemaNode(final DataNodeContainer parent,final QName child) {
+ DataSchemaNode potential = parent.getDataChildByName(child);
if (potential == null) {
Iterable<org.opendaylight.yangtools.yang.model.api.ChoiceNode> choices = FluentIterable.from(
- schema.getChildNodes()).filter(org.opendaylight.yangtools.yang.model.api.ChoiceNode.class);
+ parent.getChildNodes()).filter(org.opendaylight.yangtools.yang.model.api.ChoiceNode.class);
potential = findChoice(choices, child);
}
+ return Optional.fromNullable(potential);
+ }
- if (potential == null) {
+ private static DataNormalizationOperation<?> fromSchemaAndQNameChecked(final DataNodeContainer schema,
+ final QName child) throws DataNormalizationException {
+
+ Optional<DataSchemaNode> potential = findChildSchemaNode(schema, child);
+ if (!potential.isPresent()) {
throw new DataNormalizationException(String.format("Supplied QName %s is not valid according to schema %s, potential children nodes: %s", child, schema,schema.getChildNodes()));
}
- if ((schema instanceof DataSchemaNode) && !((DataSchemaNode) schema).isAugmenting() && potential.isAugmenting()) {
- return fromAugmentation(schema, (AugmentationTarget) schema, potential);
+ DataSchemaNode result = potential.get();
+ // We try to look up if this node was added by augmentation
+ if ((schema instanceof DataSchemaNode) && result.isAugmenting()) {
+ return fromAugmentation(schema, (AugmentationTarget) schema, result);
}
- return fromDataSchemaNode(potential);
+ return fromDataSchemaNode(result);
}
private static org.opendaylight.yangtools.yang.model.api.ChoiceNode findChoice(
org.opendaylight.yangtools.yang.model.api.ChoiceNode foundChoice = null;
choiceLoop: for (org.opendaylight.yangtools.yang.model.api.ChoiceNode choice : choices) {
for (ChoiceCaseNode caze : choice.getCases()) {
- if (caze.getDataChildByName(child) != null) {
+ if (findChildSchemaNode(caze, child).isPresent()) {
foundChoice = choice;
break choiceLoop;
}
return new AugmentationIdentifier(null, potentialChildren.build());
}
- private static AugmentationNormalization fromAugmentation(final DataNodeContainer schema,
- final AugmentationTarget augments, final DataSchemaNode potential) {
+ private static DataNodeContainer augmentationProxy(final AugmentationSchema augmentation, final DataNodeContainer schema) {
+ Set<DataSchemaNode> children = new HashSet<>();
+ for (DataSchemaNode augNode : augmentation.getChildNodes()) {
+ children.add(schema.getDataChildByName(augNode.getQName()));
+ }
+ return new DataSchemaContainerProxy(children);
+ }
+
+ /**
+ * Returns a DataNormalizationOperation for provided child node
+ *
+ * If supplied child is added by Augmentation this operation returns
+ * a DataNormalizationOperation for augmentation,
+ * otherwise returns a DataNormalizationOperation for child as
+ * call for {@link #fromDataSchemaNode(DataSchemaNode)}.
+ *
+ *
+ * @param parent
+ * @param parentAug
+ * @param child
+ * @return
+ */
+ private static DataNormalizationOperation<?> fromAugmentation(final DataNodeContainer parent,
+ final AugmentationTarget parentAug, final DataSchemaNode child) {
AugmentationSchema augmentation = null;
- for (AugmentationSchema aug : augments.getAvailableAugmentations()) {
- DataSchemaNode child = aug.getDataChildByName(potential.getQName());
- if (child != null) {
+ for (AugmentationSchema aug : parentAug.getAvailableAugmentations()) {
+ DataSchemaNode potential = aug.getDataChildByName(child.getQName());
+ if (potential != null) {
augmentation = aug;
break;
}
}
if (augmentation != null) {
- return new AugmentationNormalization(augmentation, schema);
+ return new AugmentationNormalization(augmentation, parent);
} else {
- return null;
- }
- }
-
- private static DataNormalizationOperation<?> fromSchema(final DataNodeContainer schema, final PathArgument child) throws DataNormalizationException {
- if (child instanceof AugmentationIdentifier) {
- return fromSchemaAndPathArgument(schema, ((AugmentationIdentifier) child).getPossibleChildNames()
- .iterator().next());
+ return fromDataSchemaNode(child);
}
- return fromSchemaAndPathArgument(schema, child.getNodeType());
}
public static DataNormalizationOperation<?> fromDataSchemaNode(final DataSchemaNode potential) {
--- /dev/null
+/*
+ * Copyright (c) 2014 Cisco Systems, Inc. and others. All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+package org.opendaylight.controller.md.sal.common.impl.util.compat;
+
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.Map;
+import java.util.Set;
+
+import org.opendaylight.yangtools.yang.common.QName;
+import org.opendaylight.yangtools.yang.model.api.DataNodeContainer;
+import org.opendaylight.yangtools.yang.model.api.DataSchemaNode;
+import org.opendaylight.yangtools.yang.model.api.GroupingDefinition;
+import org.opendaylight.yangtools.yang.model.api.TypeDefinition;
+import org.opendaylight.yangtools.yang.model.api.UsesNode;
+
+class DataSchemaContainerProxy implements DataNodeContainer {
+
+ private final Set<DataSchemaNode> realChildSchemas;
+ private final Map<QName, DataSchemaNode> mappedChildSchemas;
+
+ public DataSchemaContainerProxy(final Set<DataSchemaNode> realChildSchema) {
+ realChildSchemas = realChildSchema;
+ mappedChildSchemas = new HashMap<QName, DataSchemaNode>();
+ for(DataSchemaNode schema : realChildSchemas) {
+ mappedChildSchemas.put(schema.getQName(),schema);
+ }
+ }
+
+ @Override
+ public DataSchemaNode getDataChildByName(final QName name) {
+ return mappedChildSchemas.get(name);
+ }
+
+ @Override
+ public Set<DataSchemaNode> getChildNodes() {
+ return realChildSchemas;
+ }
+
+ @Override
+ public DataSchemaNode getDataChildByName(final String arg0) {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public Set<GroupingDefinition> getGroupings() {
+ return Collections.emptySet();
+ }
+
+ @Override
+ public Set<TypeDefinition<?>> getTypeDefinitions() {
+ return Collections.emptySet();
+ }
+
+ @Override
+ public Set<UsesNode> getUses() {
+ return Collections.emptySet();
+ }
+
+}
*/
package org.opendaylight.controller.sal.common.util;
-public class Arguments {
+public final class Arguments {
private Arguments() {
throw new UnsupportedOperationException("Utility class");
}
-
+
/**
* Checks if value is instance of provided class
- *
- *
+ *
+ *
* @param value Value to check
* @param type Type to check
* @return Reference which was checked
@SuppressWarnings("unchecked")
public static <T> T checkInstanceOf(Object value, Class<T> type) {
if(!type.isInstance(value))
- throw new IllegalArgumentException();
+ throw new IllegalArgumentException(String.format("Value %s is not of type %s", value, type));
return (T) value;
}
}
+++ /dev/null
-<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">\r
- <modelVersion>4.0.0</modelVersion>\r
- <parent>\r
- <groupId>org.opendaylight.controller</groupId>\r
- <artifactId>sal-parent</artifactId>\r
- <version>1.0-SNAPSHOT</version>\r
- </parent>\r
- <artifactId>sal-data-api</artifactId>\r
- <scm>\r
- <connection>scm:git:ssh://git.opendaylight.org:29418/controller.git</connection>\r
- <developerConnection>scm:git:ssh://git.opendaylight.org:29418/controller.git</developerConnection>\r
- <url>https://wiki.opendaylight.org/view/OpenDaylight_Controller:MD-SAL</url>\r
- </scm>\r
-\r
-</project>\r
* component of the controller or application supplies a concrete implementation
* of this interface.
*
- * A user-implemented component (application) which faciliates the SAL and SAL
+ * A user-implemented component (application) which facilitates the SAL and SAL
* services to access infrastructure services or providers' functionality.
*
*
* of this interface.
*
* <p>
- * A user-implemented component (application) which faciliates the SAL and SAL
+ * A user-implemented component (application) which facilitates the SAL and SAL
* services to access infrastructure services and to provide functionality to
* {@link Consumer}s and other providers.
*
+++ /dev/null
-/*
- * Copyright (c) 2014 Cisco Systems, Inc. and others. All rights reserved.
- *
- * This program and the accompanying materials are made available under the
- * terms of the Eclipse Public License v1.0 which accompanies this distribution,
- * and is available at http://www.eclipse.org/legal/epl-v10.html
- */
-package org.opendaylight.controller.md.sal.dom.store.impl;
-
-import org.opendaylight.controller.md.sal.dom.store.impl.tree.StoreMetadataNode;
-import org.opendaylight.controller.md.sal.dom.store.impl.tree.TreeNodeUtils;
-import org.opendaylight.yangtools.yang.data.api.InstanceIdentifier;
-import org.opendaylight.yangtools.yang.data.api.InstanceIdentifier.NodeIdentifier;
-import org.opendaylight.yangtools.yang.data.api.schema.NormalizedNode;
-import org.opendaylight.yangtools.yang.data.impl.schema.Builders;
-import org.opendaylight.yangtools.yang.model.api.SchemaContext;
-
-import com.google.common.base.Optional;
-
-class DataAndMetadataSnapshot {
-
- private final StoreMetadataNode metadataTree;
- private final Optional<SchemaContext> schemaContext;
-
- private DataAndMetadataSnapshot(final StoreMetadataNode metadataTree, final Optional<SchemaContext> schemaCtx) {
- this.metadataTree = metadataTree;
- this.schemaContext = schemaCtx;
- }
-
- public static Builder builder() {
- return new Builder();
- }
-
- public static DataAndMetadataSnapshot createEmpty() {
- return createEmpty(new NodeIdentifier(SchemaContext.NAME));
- }
-
-
- public static DataAndMetadataSnapshot createEmpty(final NodeIdentifier rootNode) {
- NormalizedNode<?, ?> data = Builders.containerBuilder().withNodeIdentifier(rootNode).build();
- StoreMetadataNode metadata = StoreMetadataNode.createEmpty(data);
- return new DataAndMetadataSnapshot(metadata,Optional.<SchemaContext>absent());
- }
-
- public static DataAndMetadataSnapshot createEmpty(final SchemaContext ctx) {
- NodeIdentifier rootNodeIdentifier = new NodeIdentifier(ctx.getQName());
- NormalizedNode<?, ?> data = Builders.containerBuilder().withNodeIdentifier(rootNodeIdentifier).build();
- StoreMetadataNode metadata = StoreMetadataNode.createEmpty(data);
- return new DataAndMetadataSnapshot(metadata, Optional.of(ctx));
- }
-
- public Optional<SchemaContext> getSchemaContext() {
- return schemaContext;
- }
-
- public NormalizedNode<?, ?> getDataTree() {
- return metadataTree.getData();
- }
-
- public StoreMetadataNode getMetadataTree() {
- return metadataTree;
- }
-
- public Optional<StoreMetadataNode> read(final InstanceIdentifier path) {
- return TreeNodeUtils.findNode(metadataTree, path);
- }
-
- public static class Builder {
- private NormalizedNode<?, ?> dataTree;
- private StoreMetadataNode metadataTree;
- private SchemaContext schemaContext;
-
- public NormalizedNode<?, ?> getDataTree() {
- return dataTree;
- }
-
- public Builder setMetadataTree(final StoreMetadataNode metadataTree) {
- this.metadataTree = metadataTree;
- return this;
- }
-
- public Builder setSchemaContext(final SchemaContext schemaContext) {
- this.schemaContext = schemaContext;
- return this;
- }
-
- public DataAndMetadataSnapshot build() {
- return new DataAndMetadataSnapshot(metadataTree, Optional.fromNullable(schemaContext));
- }
-
- }
-}
--- /dev/null
+/*
+ * Copyright (c) 2014 Cisco Systems, Inc. and others. All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+package org.opendaylight.controller.md.sal.dom.store.impl;
+
+import org.opendaylight.yangtools.yang.data.api.InstanceIdentifier;
+
+public class DataPreconditionFailedException extends Exception {
+
+ /**
+ *
+ */
+ private static final long serialVersionUID = 596430355175413427L;
+ private final InstanceIdentifier path;
+
+ public DataPreconditionFailedException(final InstanceIdentifier path) {
+ this.path = path;
+ }
+
+ public DataPreconditionFailedException(final InstanceIdentifier path,final String message) {
+ super(message);
+ this.path = path;
+ }
+
+
+ public DataPreconditionFailedException(final InstanceIdentifier path,final Throwable cause) {
+ super(cause);
+ this.path = path;
+ }
+
+ public DataPreconditionFailedException(final InstanceIdentifier path,final String message, final Throwable cause) {
+ super(message, cause);
+ this.path = path;
+ }
+
+ public DataPreconditionFailedException(final InstanceIdentifier path,final String message, final Throwable cause, final boolean enableSuppression,
+ final boolean writableStackTrace) {
+ super(message, cause, enableSuppression, writableStackTrace);
+ this.path = path;
+ }
+
+ public InstanceIdentifier getPath() {
+ return path;
+ }
+
+}
--- /dev/null
+/*
+ * Copyright (c) 2014 Cisco Systems, Inc. and others. All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+package org.opendaylight.controller.md.sal.dom.store.impl;
+
+import java.util.concurrent.locks.ReadWriteLock;
+import java.util.concurrent.locks.ReentrantReadWriteLock;
+
+import org.opendaylight.controller.md.sal.dom.store.impl.tree.StoreMetadataNode;
+import org.opendaylight.yangtools.yang.data.api.InstanceIdentifier;
+import org.opendaylight.yangtools.yang.data.api.InstanceIdentifier.NodeIdentifier;
+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.NormalizedNodeUtils;
+import org.opendaylight.yangtools.yang.model.api.SchemaContext;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import com.google.common.annotations.VisibleForTesting;
+import com.google.common.base.Optional;
+import com.google.common.base.Preconditions;
+
+/**
+ * Read-only snapshot of the data tree.
+ */
+final class DataTree {
+ public static final class Snapshot {
+ private final SchemaContext schemaContext;
+ private final StoreMetadataNode rootNode;
+
+ @VisibleForTesting
+ Snapshot(final SchemaContext schemaContext, final StoreMetadataNode rootNode) {
+ this.schemaContext = Preconditions.checkNotNull(schemaContext);
+ this.rootNode = Preconditions.checkNotNull(rootNode);
+ }
+
+ public SchemaContext getSchemaContext() {
+ return schemaContext;
+ }
+
+ public Optional<NormalizedNode<?, ?>> readNode(final InstanceIdentifier path) {
+ return NormalizedNodeUtils.findNode(rootNode.getData(), path);
+ }
+
+ // FIXME: this is a leak of information
+ @Deprecated
+ StoreMetadataNode getRootNode() {
+ return rootNode;
+ }
+
+ @Override
+ public String toString() {
+ return rootNode.getSubtreeVersion().toString();
+ }
+ }
+
+ private static final Logger LOG = LoggerFactory.getLogger(DataTree.class);
+ private final ReadWriteLock rwLock = new ReentrantReadWriteLock(true);
+ private StoreMetadataNode rootNode;
+ private SchemaContext currentSchemaContext;
+
+ private DataTree(StoreMetadataNode rootNode, final SchemaContext schemaContext) {
+ this.rootNode = Preconditions.checkNotNull(rootNode);
+ this.currentSchemaContext = schemaContext;
+ }
+
+ public synchronized void setSchemaContext(final SchemaContext newSchemaContext) {
+ Preconditions.checkNotNull(newSchemaContext);
+
+ LOG.info("Attepting to install schema context {}", newSchemaContext);
+
+ /*
+ * FIXME: we should walk the schema contexts, both current and new and see
+ * whether they are compatible here. Reject incompatible changes.
+ */
+
+ // Ready to change the context now, make sure no operations are running
+ rwLock.writeLock().lock();
+ try {
+ this.currentSchemaContext = newSchemaContext;
+ } finally {
+ rwLock.writeLock().unlock();
+ }
+ }
+
+ public static DataTree create(final SchemaContext schemaContext) {
+ final NodeIdentifier root = new NodeIdentifier(SchemaContext.NAME);
+ final NormalizedNode<?, ?> data = Builders.containerBuilder().withNodeIdentifier(root).build();
+
+ return new DataTree(StoreMetadataNode.createEmpty(data), schemaContext);
+ }
+
+ public Snapshot takeSnapshot() {
+ rwLock.readLock().lock();
+
+ try {
+ return new Snapshot(currentSchemaContext, rootNode);
+ } finally {
+ rwLock.readLock().unlock();
+ }
+ }
+
+ public void commitSnapshot(Snapshot currentSnapshot, StoreMetadataNode newDataTree) {
+ // Ready to change the context now, make sure no operations are running
+ rwLock.writeLock().lock();
+ try {
+ Preconditions.checkState(currentSnapshot.rootNode == rootNode,
+ String.format("Store snapshot %s and transaction snapshot %s differ.",
+ rootNode, currentSnapshot.rootNode));
+
+ this.rootNode = newDataTree;
+ } finally {
+ rwLock.writeLock().unlock();
+ }
+ }
+}
import java.util.Collections;
import java.util.concurrent.Callable;
import java.util.concurrent.atomic.AtomicLong;
-import java.util.concurrent.atomic.AtomicReference;
import org.opendaylight.controller.md.sal.common.api.data.AsyncDataBroker.DataChangeScope;
import org.opendaylight.controller.md.sal.common.api.data.AsyncDataChangeListener;
import org.opendaylight.yangtools.yang.data.api.InstanceIdentifier;
import org.opendaylight.yangtools.yang.data.api.InstanceIdentifier.PathArgument;
import org.opendaylight.yangtools.yang.data.api.schema.NormalizedNode;
-import org.opendaylight.yangtools.yang.data.impl.schema.NormalizedNodeUtils;
import org.opendaylight.yangtools.yang.model.api.SchemaContext;
import org.opendaylight.yangtools.yang.model.api.SchemaContextListener;
import org.slf4j.Logger;
private static final Logger LOG = LoggerFactory.getLogger(InMemoryDOMDataStore.class);
private static final InstanceIdentifier PUBLIC_ROOT_PATH = InstanceIdentifier.builder().build();
-
private final ListeningExecutorService executor;
private final String name;
private final AtomicLong txCounter = new AtomicLong(0);
- private final ListenerTree listenerTree;
- private final AtomicReference<DataAndMetadataSnapshot> snapshot;
-
- private ModificationApplyOperation operationTree;
-
- private SchemaContext schemaContext;
+ private final ListenerTree listenerTree = ListenerTree.create();
+ private final DataTree dataTree = DataTree.create(null);
+ private ModificationApplyOperation operationTree = new AlwaysFailOperation();
public InMemoryDOMDataStore(final String name, final ListeningExecutorService executor) {
this.name = Preconditions.checkNotNull(name);
this.executor = Preconditions.checkNotNull(executor);
- this.listenerTree = ListenerTree.create();
- this.snapshot = new AtomicReference<DataAndMetadataSnapshot>(DataAndMetadataSnapshot.createEmpty());
- this.operationTree = new AlwaysFailOperation();
}
@Override
@Override
public DOMStoreReadTransaction newReadOnlyTransaction() {
- return new SnapshotBackedReadTransaction(nextIdentifier(), snapshot.get());
+ return new SnapshotBackedReadTransaction(nextIdentifier(), dataTree.takeSnapshot());
}
@Override
public DOMStoreReadWriteTransaction newReadWriteTransaction() {
- return new SnapshotBackedReadWriteTransaction(nextIdentifier(), snapshot.get(), this, operationTree);
+ return new SnapshotBackedReadWriteTransaction(nextIdentifier(), dataTree.takeSnapshot(), this, operationTree);
}
@Override
public DOMStoreWriteTransaction newWriteOnlyTransaction() {
- return new SnapshotBackedWriteTransaction(nextIdentifier(), snapshot.get(), this, operationTree);
+ return new SnapshotBackedWriteTransaction(nextIdentifier(), dataTree.takeSnapshot(), this, operationTree);
}
@Override
public synchronized void onGlobalContextUpdated(final SchemaContext ctx) {
- operationTree = SchemaAwareApplyOperationRoot.from(ctx);
- schemaContext = ctx;
+ /*
+ * Order of operations is important: dataTree may reject the context
+ * and creation of ModificationApplyOperation may fail. So pre-construct
+ * the operation, then update the data tree and then move the operation
+ * into view.
+ */
+ final ModificationApplyOperation newOperationTree = SchemaAwareApplyOperationRoot.from(ctx);
+ dataTree.setSchemaContext(ctx);
+ operationTree = newOperationTree;
}
@Override
final InstanceIdentifier path, final L listener, final DataChangeScope scope) {
/*
- * Make sure commit is not occurring right now. Listener has to be registered and its
- * state capture enqueued at a consistent point.
+ * Make sure commit is not occurring right now. Listener has to be
+ * registered and its state capture enqueued at a consistent point.
*
- * FIXME: improve this to read-write lock, such that multiple listener registrations
- * can occur simultaneously
+ * FIXME: improve this to read-write lock, such that multiple listener
+ * registrations can occur simultaneously
*/
final DataChangeListenerRegistration<L> reg;
synchronized (this) {
- LOG.debug("{}: Registering data change listener {} for {}",name,listener,path);
+ LOG.debug("{}: Registering data change listener {} for {}", name, listener, path);
reg = listenerTree.registerDataChangeListener(path, listener, scope);
- Optional<StoreMetadataNode> currentState = snapshot.get().read(path);
+ Optional<NormalizedNode<?, ?>> currentState = dataTree.takeSnapshot().readNode(path);
if (currentState.isPresent()) {
- final NormalizedNode<?, ?> data = currentState.get().getData();
+ final NormalizedNode<?, ?> data = currentState.get();
final DOMImmutableDataChangeEvent event = DOMImmutableDataChangeEvent.builder(DataChangeScope.BASE) //
.setAfter(data) //
};
}
- private synchronized DOMStoreThreePhaseCommitCohort submit(
- final SnapshotBackedWriteTransaction writeTx) {
- LOG.debug("Tx: {} is submitted. Modifications: {}",writeTx.getIdentifier(),writeTx.getMutatedView());
+ private synchronized DOMStoreThreePhaseCommitCohort submit(final SnapshotBackedWriteTransaction writeTx) {
+ LOG.debug("Tx: {} is submitted. Modifications: {}", writeTx.getIdentifier(), writeTx.getMutatedView());
return new ThreePhaseCommitImpl(writeTx);
}
return name + "-" + txCounter.getAndIncrement();
}
- private void commit(final DataAndMetadataSnapshot currentSnapshot,
- final StoreMetadataNode newDataTree, final ResolveDataChangeEventsTask listenerResolver) {
- LOG.debug("Updating Store snaphot version: {} with version:{}",currentSnapshot.getMetadataTree().getSubtreeVersion(),newDataTree.getSubtreeVersion());
+ private void commit(final DataTree.Snapshot currentSnapshot, final StoreMetadataNode newDataTree,
+ final ResolveDataChangeEventsTask listenerResolver) {
+ LOG.debug("Updating Store snaphot version: {} with version:{}", currentSnapshot, newDataTree.getSubtreeVersion());
- if(LOG.isTraceEnabled()) {
- LOG.trace("Data Tree is {}",StoreUtils.toStringTree(newDataTree));
+ if (LOG.isTraceEnabled()) {
+ LOG.trace("Data Tree is {}", StoreUtils.toStringTree(newDataTree.getData()));
}
- final DataAndMetadataSnapshot newSnapshot = DataAndMetadataSnapshot.builder() //
- .setMetadataTree(newDataTree) //
- .setSchemaContext(schemaContext) //
- .build();
-
/*
- * The commit has to occur atomically with regard to listener registrations.
+ * The commit has to occur atomically with regard to listener
+ * registrations.
*/
synchronized (this) {
- final boolean success = snapshot.compareAndSet(currentSnapshot, newSnapshot);
- checkState(success, "Store snapshot and transaction snapshot differ. This should never happen.");
+ dataTree.commitSnapshot(currentSnapshot, newDataTree);
for (ChangeListenerNotifyTask task : listenerResolver.call()) {
- LOG.trace("Scheduling invocation of listeners: {}",task);
+ LOG.trace("Scheduling invocation of listeners: {}", task);
executor.submit(task);
}
}
/**
* Add class-specific toString attributes.
*
- * @param toStringHelper ToStringHelper instance
+ * @param toStringHelper
+ * ToStringHelper instance
* @return ToStringHelper instance which was passed in
*/
protected ToStringHelper addToStringAttributes(final ToStringHelper toStringHelper) {
}
}
- private static class SnapshotBackedReadTransaction extends AbstractDOMStoreTransaction implements DOMStoreReadTransaction {
- private DataAndMetadataSnapshot stableSnapshot;
+ private static final class SnapshotBackedReadTransaction extends AbstractDOMStoreTransaction implements
+ DOMStoreReadTransaction {
+ private DataTree.Snapshot stableSnapshot;
- public SnapshotBackedReadTransaction(final Object identifier, final DataAndMetadataSnapshot snapshot) {
+ public SnapshotBackedReadTransaction(final Object identifier, final DataTree.Snapshot snapshot) {
super(identifier);
this.stableSnapshot = Preconditions.checkNotNull(snapshot);
- LOG.debug("ReadOnly Tx: {} allocated with snapshot {}", identifier, snapshot.getMetadataTree().getSubtreeVersion());
+ LOG.debug("ReadOnly Tx: {} allocated with snapshot {}", identifier, snapshot);
}
@Override
public ListenableFuture<Optional<NormalizedNode<?, ?>>> read(final InstanceIdentifier path) {
checkNotNull(path, "Path must not be null.");
checkState(stableSnapshot != null, "Transaction is closed");
- return Futures.immediateFuture(NormalizedNodeUtils.findNode(stableSnapshot.getDataTree(), path));
+ return Futures.immediateFuture(stableSnapshot.readNode(path));
}
}
- private static class SnapshotBackedWriteTransaction extends AbstractDOMStoreTransaction implements DOMStoreWriteTransaction {
+ private static class SnapshotBackedWriteTransaction extends AbstractDOMStoreTransaction implements
+ DOMStoreWriteTransaction {
private MutableDataTree mutableTree;
private InMemoryDOMDataStore store;
private boolean ready = false;
- public SnapshotBackedWriteTransaction(final Object identifier, final DataAndMetadataSnapshot snapshot,
+ public SnapshotBackedWriteTransaction(final Object identifier, final DataTree.Snapshot snapshot,
final InMemoryDOMDataStore store, final ModificationApplyOperation applyOper) {
super(identifier);
mutableTree = MutableDataTree.from(snapshot, applyOper);
this.store = store;
- LOG.debug("Write Tx: {} allocated with snapshot {}",identifier,snapshot.getMetadataTree().getSubtreeVersion());
+ LOG.debug("Write Tx: {} allocated with snapshot {}", identifier, snapshot);
}
@Override
public void write(final InstanceIdentifier path, final NormalizedNode<?, ?> data) {
checkNotReady();
try {
- LOG.trace("Tx: {} Write: {}:{}",getIdentifier(),path,data);
+ LOG.trace("Tx: {} Write: {}:{}", getIdentifier(), path, data);
mutableTree.write(path, data);
- // FIXME: Add checked exception
+ // FIXME: Add checked exception
} catch (Exception e) {
- LOG.error("Tx: {}, failed to write {}:{} in {}",getIdentifier(),path,data,mutableTree,e);
+ LOG.error("Tx: {}, failed to write {}:{} in {}", getIdentifier(), path, data, mutableTree, e);
}
}
public void merge(final InstanceIdentifier path, final NormalizedNode<?, ?> data) {
checkNotReady();
try {
- LOG.trace("Tx: {} Merge: {}:{}",getIdentifier(),path,data);
+ LOG.trace("Tx: {} Merge: {}:{}", getIdentifier(), path, data);
mutableTree.merge(path, data);
- // FIXME: Add checked exception
+ // FIXME: Add checked exception
} catch (Exception e) {
- LOG.error("Tx: {}, failed to write {}:{} in {}",getIdentifier(),path,data,mutableTree,e);
+ LOG.error("Tx: {}, failed to write {}:{} in {}", getIdentifier(), path, data, mutableTree, e);
}
}
public void delete(final InstanceIdentifier path) {
checkNotReady();
try {
- LOG.trace("Tx: {} Delete: {}",getIdentifier(),path);
+ LOG.trace("Tx: {} Delete: {}", getIdentifier(), path);
mutableTree.delete(path);
- // FIXME: Add checked exception
+ // FIXME: Add checked exception
} catch (Exception e) {
- LOG.error("Tx: {}, failed to delete {} in {}",getIdentifier(),path,mutableTree,e);
+ LOG.error("Tx: {}, failed to delete {} in {}", getIdentifier(), path, mutableTree, e);
}
}
private static class SnapshotBackedReadWriteTransaction extends SnapshotBackedWriteTransaction implements
DOMStoreReadWriteTransaction {
- protected SnapshotBackedReadWriteTransaction(final Object identifier, final DataAndMetadataSnapshot snapshot,
+ protected SnapshotBackedReadWriteTransaction(final Object identifier, final DataTree.Snapshot snapshot,
final InMemoryDOMDataStore store, final ModificationApplyOperation applyOper) {
super(identifier, snapshot, store, applyOper);
}
@Override
public ListenableFuture<Optional<NormalizedNode<?, ?>>> read(final InstanceIdentifier path) {
- LOG.trace("Tx: {} Read: {}",getIdentifier(),path);
+ LOG.trace("Tx: {} Read: {}", getIdentifier(), path);
try {
return Futures.immediateFuture(getMutatedView().read(path));
} catch (Exception e) {
- LOG.error("Tx: {} Failed Read of {}",getIdentifier(),path,e);
+ LOG.error("Tx: {} Failed Read of {}", getIdentifier(), path, e);
throw e;
}
}
private final SnapshotBackedWriteTransaction transaction;
private final NodeModification modification;
- private DataAndMetadataSnapshot storeSnapshot;
+ private DataTree.Snapshot storeSnapshot;
private Optional<StoreMetadataNode> proposedSubtree;
private ResolveDataChangeEventsTask listenerResolver;
@Override
public ListenableFuture<Boolean> canCommit() {
- final DataAndMetadataSnapshot snapshotCapture = snapshot.get();
+ final DataTree.Snapshot snapshotCapture = dataTree.takeSnapshot();
final ModificationApplyOperation snapshotOperation = operationTree;
return executor.submit(new Callable<Boolean>() {
@Override
public Boolean call() throws Exception {
- boolean applicable = snapshotOperation.isApplicable(modification,
- Optional.of(snapshotCapture.getMetadataTree()));
- LOG.debug("Store Transcation: {} : canCommit : {}", transaction.getIdentifier(), applicable);
+ Boolean applicable = false;
+ try {
+ snapshotOperation.checkApplicable(PUBLIC_ROOT_PATH, modification,
+ Optional.of(snapshotCapture.getRootNode()));
+ applicable = true;
+ } catch (DataPreconditionFailedException e) {
+ LOG.warn("Store Tx: {} Data Precondition failed for {}.",transaction.getIdentifier(),e.getPath(),e);
+ applicable = false;
+ }
+ LOG.debug("Store Transaction: {} : canCommit : {}", transaction.getIdentifier(), applicable);
return applicable;
}
});
@Override
public ListenableFuture<Void> preCommit() {
- storeSnapshot = snapshot.get();
- if(modification.getModificationType() == ModificationType.UNMODIFIED) {
+ storeSnapshot = dataTree.takeSnapshot();
+ if (modification.getModificationType() == ModificationType.UNMODIFIED) {
return Futures.immediateFuture(null);
}
return executor.submit(new Callable<Void>() {
-
-
@Override
public Void call() throws Exception {
- StoreMetadataNode metadataTree = storeSnapshot.getMetadataTree();
+ StoreMetadataNode metadataTree = storeSnapshot.getRootNode();
proposedSubtree = operationTree.apply(modification, Optional.of(metadataTree),
increase(metadataTree.getSubtreeVersion()));
@Override
public ListenableFuture<Void> commit() {
- if(modification.getModificationType() == ModificationType.UNMODIFIED) {
+ if (modification.getModificationType() == ModificationType.UNMODIFIED) {
return Futures.immediateFuture(null);
}
- checkState(proposedSubtree != null,"Proposed subtree must be computed");
- checkState(storeSnapshot != null,"Proposed subtree must be computed");
+ checkState(proposedSubtree != null, "Proposed subtree must be computed");
+ checkState(storeSnapshot != null, "Proposed subtree must be computed");
// return ImmediateFuture<>;
- InMemoryDOMDataStore.this.commit(storeSnapshot, proposedSubtree.get(),listenerResolver);
+ InMemoryDOMDataStore.this.commit(storeSnapshot, proposedSubtree.get(), listenerResolver);
return Futures.<Void> immediateFuture(null);
}
}
@Override
- public boolean isApplicable(final NodeModification modification, final Optional<StoreMetadataNode> storeMetadata) {
+ public void checkApplicable(final InstanceIdentifier path,final NodeModification modification, final Optional<StoreMetadataNode> storeMetadata) {
throw new IllegalStateException("Schema Context is not available.");
}
import org.opendaylight.controller.md.sal.dom.store.impl.tree.NodeModification;
import org.opendaylight.controller.md.sal.dom.store.impl.tree.StoreMetadataNode;
import org.opendaylight.controller.md.sal.dom.store.impl.tree.StoreTreeNode;
+import org.opendaylight.yangtools.yang.data.api.InstanceIdentifier;
import org.opendaylight.yangtools.yang.data.api.InstanceIdentifier.PathArgument;
import com.google.common.base.Optional;
*/
Optional<StoreMetadataNode> apply(NodeModification modification, Optional<StoreMetadataNode> storeMeta, UnsignedLong subtreeVersion);
- /**
- *
- * Checks if provided node modification could be applied to current metadata node.
- *
- * @param modification Modification
- * @param current Metadata Node to which modification should be applied
- * @return true if modification is applicable
- * false if modification is no applicable
- */
- boolean isApplicable(NodeModification modification, Optional<StoreMetadataNode> current);
-
/**
*
* Performs structural verification of NodeModification, such as writen values / types
*/
@Override
Optional<ModificationApplyOperation> getChild(PathArgument child);
+
+ /**
+ *
+ * Checks if provided node modification could be applied to current metadata node.
+ *
+ * @param modification Modification
+ * @param current Metadata Node to which modification should be applied
+ * @return true if modification is applicable
+ * false if modification is no applicable
+ * @throws DataPreconditionFailedException
+ */
+ void checkApplicable(InstanceIdentifier path, NodeModification modification, Optional<StoreMetadataNode> current) throws DataPreconditionFailedException;
}
private static final Logger LOG = LoggerFactory.getLogger(MutableDataTree.class);
private final AtomicBoolean sealed = new AtomicBoolean();
private final ModificationApplyOperation strategyTree;
- private final DataAndMetadataSnapshot snapshot;
private final NodeModification rootModification;
+ private final DataTree.Snapshot snapshot;
- private MutableDataTree(final DataAndMetadataSnapshot snapshot, final ModificationApplyOperation strategyTree) {
- this.snapshot = snapshot;
- this.strategyTree = strategyTree;
- this.rootModification = NodeModification.createUnmodified(snapshot.getMetadataTree());
+ private MutableDataTree(final DataTree.Snapshot snapshot, final ModificationApplyOperation strategyTree) {
+ this.snapshot = Preconditions.checkNotNull(snapshot);
+ this.strategyTree = Preconditions.checkNotNull(strategyTree);
+ this.rootModification = NodeModification.createUnmodified(snapshot.getRootNode());
}
public void write(final InstanceIdentifier path, final NormalizedNode<?, ?> value) {
return potentialSnapshot.get();
}
return resolveModificationStrategy(path).apply(modification, modification.getOriginal(),
- StoreUtils.increase(snapshot.getMetadataTree().getSubtreeVersion()));
+ StoreUtils.increase(snapshot.getRootNode().getSubtreeVersion()));
} catch (Exception e) {
LOG.error("Could not create snapshot for {}:{}", path,modification,e);
throw e;
return OperationWithModification.from(operation, modification);
}
- public static MutableDataTree from(final DataAndMetadataSnapshot snapshot, final ModificationApplyOperation resolver) {
+ public static MutableDataTree from(final DataTree.Snapshot snapshot, final ModificationApplyOperation resolver) {
return new MutableDataTree(snapshot, resolver);
}
return applyOperation;
}
- public boolean isApplicable(final Optional<StoreMetadataNode> data) {
- return applyOperation.isApplicable(modification, data);
- }
-
public Optional<StoreMetadataNode> apply(final Optional<StoreMetadataNode> data, final UnsignedLong subtreeVersion) {
return applyOperation.apply(modification, data, subtreeVersion);
}
final Collection<Node> listeners, final NormalizedNode<?, ?> beforeData,
final NormalizedNode<?, ?> afterData) {
- if (beforeData instanceof NormalizedNodeContainer<?, ?, ?> && !listeners.isEmpty()) {
+ if (beforeData instanceof NormalizedNodeContainer<?, ?, ?>) {
// Node is container (contains child) and we have interested
// listeners registered for it, that means we need to do
// resolution of changes on children level and can not
// shortcut resolution.
-
+ LOG.trace("Resolving subtree replace event for {} before {}, after {}",path,beforeData,afterData);
@SuppressWarnings("unchecked")
NormalizedNodeContainer<?, PathArgument, NormalizedNode<PathArgument, ?>> beforeCont = (NormalizedNodeContainer<?, PathArgument, NormalizedNode<PathArgument, ?>>) beforeData;
@SuppressWarnings("unchecked")
// Node is either of Leaf type (does not contain child nodes)
// or we do not have listeners, so normal equals method is
// sufficient for determining change.
-
+ LOG.trace("Resolving leaf replace event for {} , before {}, after {}",path,beforeData,afterData);
DOMImmutableDataChangeEvent event = builder(DataChangeScope.BASE).setBefore(beforeData).setAfter(afterData)
.addUpdated(path, beforeData, afterData).build();
addPartialTask(listeners, event);
private DOMImmutableDataChangeEvent resolveSameEventRecursivelly(final InstanceIdentifier path,
final Collection<Node> listeners, final NormalizedNode<PathArgument, ?> node,
final SimpleEventFactory eventFactory) {
-
final DOMImmutableDataChangeEvent event = eventFactory.create(path, node);
DOMImmutableDataChangeEvent propagateEvent = event;
- // We have listeners for this node or it's children, so we will try
+ // We have listeners for this node or it's children, so we will try
// to do additional processing
if (node instanceof NormalizedNodeContainer<?, ?, ?>) {
+ LOG.trace("Resolving subtree recursive event for {}, type {}", path, eventFactory);
+
Builder eventBuilder = builder(DataChangeScope.BASE);
eventBuilder.merge(event);
eventBuilder.setBefore(event.getOriginalSubtree());
NormalizedNodeContainer<?, PathArgument, NormalizedNode<PathArgument, ?>> container = (NormalizedNodeContainer<?, PathArgument, NormalizedNode<PathArgument, ?>>) node;
for (NormalizedNode<PathArgument, ?> child : container.getValue()) {
PathArgument childId = child.getIdentifier();
+ LOG.trace("Resolving event for child {}", childId);
Collection<Node> childListeners = getListenerChildrenWildcarded(listeners, childId);
eventBuilder.merge(resolveSameEventRecursivelly(append(path, childId), childListeners, child, eventFactory));
}
propagateEvent = builder(DataChangeScope.BASE).build();
}
if (!listeners.isEmpty()) {
- addPartialTask(listeners, event);
+ addPartialTask(listeners, propagateEvent);
}
return propagateEvent;
}
private DOMImmutableDataChangeEvent addPartialTask(final Collection<ListenerTree.Node> listeners,
final DOMImmutableDataChangeEvent event) {
-
for (ListenerTree.Node listenerNode : listeners) {
if (!listenerNode.getListeners().isEmpty()) {
+ LOG.trace("Adding event {} for listeners {}",event,listenerNode);
events.put(listenerNode, event);
}
}
import org.opendaylight.controller.md.sal.dom.store.impl.tree.StoreMetadataNode;
import org.opendaylight.controller.md.sal.dom.store.impl.tree.StoreNodeCompositeBuilder;
import org.opendaylight.yangtools.yang.common.QName;
+import org.opendaylight.yangtools.yang.data.api.InstanceIdentifier;
import org.opendaylight.yangtools.yang.data.api.InstanceIdentifier.AugmentationIdentifier;
import org.opendaylight.yangtools.yang.data.api.InstanceIdentifier.NodeIdentifier;
import org.opendaylight.yangtools.yang.data.api.InstanceIdentifier.NodeIdentifierWithPredicates;
protected abstract void verifyWritenStructure(NormalizedNode<?, ?> writenValue);
@Override
- public boolean isApplicable(final NodeModification modification, final Optional<StoreMetadataNode> current) {
+ public void checkApplicable(final InstanceIdentifier path,final NodeModification modification, final Optional<StoreMetadataNode> current) throws DataPreconditionFailedException {
switch (modification.getModificationType()) {
case DELETE:
- return isDeleteApplicable(modification, current);
+ checkDeleteApplicable(modification, current);
case SUBTREE_MODIFIED:
- return isSubtreeModificationApplicable(modification, current);
+ checkSubtreeModificationApplicable(path,modification, current);
+ return;
case WRITE:
- return isWriteApplicable(modification, current);
+ checkWriteApplicable(path,modification, current);
+ return;
case MERGE:
- return isMergeApplicable(modification,current);
+ checkMergeApplicable(path,modification,current);
+ return;
case UNMODIFIED:
- return true;
+ return;
default:
- return false;
+ throw new UnsupportedOperationException("Suplied modification type "+modification.getModificationType()+ "is not supported.");
}
+
}
- private boolean isMergeApplicable(final NodeModification modification, final Optional<StoreMetadataNode> current) {
+ protected void checkMergeApplicable(final InstanceIdentifier path,final NodeModification modification, final Optional<StoreMetadataNode> current) throws DataPreconditionFailedException {
Optional<StoreMetadataNode> original = modification.getOriginal();
if (original.isPresent() && current.isPresent()) {
- return isNotConflicting(original.get(), current.get());
- } else if (current.isPresent()) {
- return true;
+ /*
+ * We need to do conflict detection only and only if the value of leaf changed
+ * before two transactions. If value of leaf is unchanged between two transactions
+ * it should not cause transaction to fail, since result of this merge
+ * leads to same data.
+ */
+ if(!original.get().getData().equals(current.get().getData())) {
+
+ checkNotConflicting(path,original.get(), current.get());
+ }
}
- return true;
}
- protected boolean isWriteApplicable(final NodeModification modification, final Optional<StoreMetadataNode> current) {
+ protected void checkWriteApplicable(final InstanceIdentifier path,final NodeModification modification, final Optional<StoreMetadataNode> current) throws DataPreconditionFailedException {
Optional<StoreMetadataNode> original = modification.getOriginal();
if (original.isPresent() && current.isPresent()) {
- return isNotConflicting(original.get(), current.get());
- } else if (current.isPresent()) {
- return false;
+ checkNotConflicting(path,original.get(), current.get());
+ } else if(original.isPresent()) {
+ throw new DataPreconditionFailedException(path,"Node was deleted by other transaction.");
}
- return true;
-
}
- protected final boolean isNotConflicting(final StoreMetadataNode original, final StoreMetadataNode current) {
- return original.getNodeVersion().equals(current.getNodeVersion())
- && original.getSubtreeVersion().equals(current.getSubtreeVersion());
+ protected static final void checkNotConflicting(final InstanceIdentifier path,final StoreMetadataNode original, final StoreMetadataNode current) throws DataPreconditionFailedException {
+ checkDataPrecondition(path, original.getNodeVersion().equals(current.getNodeVersion()),"Node was replaced by other transaction.");
+ checkDataPrecondition(path,original.getSubtreeVersion().equals(current.getSubtreeVersion()), "Node children was modified by other transaction");
}
- protected abstract boolean isSubtreeModificationApplicable(final NodeModification modification,
- final Optional<StoreMetadataNode> current);
+ protected abstract void checkSubtreeModificationApplicable(InstanceIdentifier path,final NodeModification modification,
+ final Optional<StoreMetadataNode> current) throws DataPreconditionFailedException;
- private boolean isDeleteApplicable(final NodeModification modification, final Optional<StoreMetadataNode> current) {
- // FiXME: Add delete conflict detection.
- return true;
+ private void checkDeleteApplicable(final NodeModification modification, final Optional<StoreMetadataNode> current) {
}
@Override
}
@Override
- protected boolean isSubtreeModificationApplicable(final NodeModification modification,
- final Optional<StoreMetadataNode> current) {
- return false;
+ protected void checkSubtreeModificationApplicable(final InstanceIdentifier path,final NodeModification modification,
+ final Optional<StoreMetadataNode> current) throws DataPreconditionFailedException {
+ throw new DataPreconditionFailedException(path, "Subtree modification is not allowed.");
}
}
}
}
+ @Override
+ protected void checkWriteApplicable(final InstanceIdentifier path, final NodeModification modification,
+ final Optional<StoreMetadataNode> current) throws DataPreconditionFailedException {
+ // FIXME: Implement proper write check for replacement of node container
+ // prerequisite is to have transaction chain available for clients
+ // otherwise this will break chained writes to same node.
+ }
+
@SuppressWarnings("rawtypes")
@Override
protected void verifyWritenStructure(final NormalizedNode<?, ?> writenValue) {
}
@Override
- protected boolean isSubtreeModificationApplicable(final NodeModification modification,
- final Optional<StoreMetadataNode> current) {
- if (false == current.isPresent()) {
- return false;
- }
- boolean result = true;
+ protected void checkSubtreeModificationApplicable(final InstanceIdentifier path,final NodeModification modification,
+ final Optional<StoreMetadataNode> current) throws DataPreconditionFailedException {
+ checkDataPrecondition(path, current.isPresent(), "Node was deleted by other transaction.");
+ checkChildPreconditions(path,modification,current);
+
+ }
+
+ private void checkChildPreconditions(final InstanceIdentifier path, final NodeModification modification, final Optional<StoreMetadataNode> current) throws DataPreconditionFailedException {
StoreMetadataNode currentMeta = current.get();
for (NodeModification childMod : modification.getModifications()) {
PathArgument childId = childMod.getIdentifier();
Optional<StoreMetadataNode> childMeta = currentMeta.getChild(childId);
- result &= resolveChildOperation(childId).isApplicable(childMod, childMeta);
+ InstanceIdentifier childPath = StoreUtils.append(path, childId);
+ resolveChildOperation(childId).checkApplicable(childPath,childMod, childMeta);
+ }
+ }
+
+ @Override
+ protected void checkMergeApplicable(final InstanceIdentifier path, final NodeModification modification,
+ final Optional<StoreMetadataNode> current) throws DataPreconditionFailedException {
+ if(current.isPresent()) {
+ checkChildPreconditions(path,modification,current);
}
- return result;
}
@SuppressWarnings("rawtypes")
protected AugmentationModificationStrategy(final AugmentationSchema schema, final DataNodeContainer resolved) {
super(createAugmentProxy(schema,resolved), AugmentationNode.class);
- // FIXME: Use resolved children instead of unresolved.
-
}
@Override
}
@Override
- protected boolean isSubtreeModificationApplicable(final NodeModification modification,
- final Optional<StoreMetadataNode> current) {
- return false;
+ protected void checkSubtreeModificationApplicable(final InstanceIdentifier path,final NodeModification modification,
+ final Optional<StoreMetadataNode> current) throws DataPreconditionFailedException {
+ throw new DataPreconditionFailedException(path, "Subtree modification is not allowed.");
}
}
return new AugmentationSchemaProxy(schema, realChildSchemas);
}
+ public static boolean checkDataPrecondition(final InstanceIdentifier path, final boolean condition, final String message) throws DataPreconditionFailedException {
+ if(!condition) {
+ throw new DataPreconditionFailedException(path, message);
+ }
+ return condition;
+ }
+
}
*/
package org.opendaylight.controller.md.sal.dom.store.impl;
-import java.util.Collections;
-import java.util.Map;
import java.util.Set;
-import org.opendaylight.controller.md.sal.common.api.data.AsyncDataChangeEvent;
-import org.opendaylight.controller.md.sal.dom.store.impl.tree.StoreMetadataNode;
import org.opendaylight.yangtools.concepts.Identifiable;
import org.opendaylight.yangtools.yang.data.api.InstanceIdentifier;
import org.opendaylight.yangtools.yang.data.api.InstanceIdentifier.AugmentationIdentifier;
import com.google.common.base.Strings;
import com.google.common.collect.FluentIterable;
import com.google.common.collect.ImmutableList;
-import com.google.common.collect.ImmutableMap;
import com.google.common.primitives.UnsignedLong;
public final class StoreUtils {
+ private static final int STRINGTREE_INDENT = 4;
private final static Function<Identifiable<Object>, Object> EXTRACT_IDENTIFIER = new Function<Identifiable<Object>, Object>() {
@Override
}
};
- public static final UnsignedLong increase(final UnsignedLong original) {
- return original.plus(UnsignedLong.ONE);
- }
-
- public static final InstanceIdentifier append(final InstanceIdentifier parent, final PathArgument arg) {
-
- return new InstanceIdentifier(ImmutableList.<PathArgument> builder().addAll(parent.getPath()).add(arg).build());
- }
-
- public static AsyncDataChangeEvent<InstanceIdentifier, NormalizedNode<?, ?>> initialChangeEvent(
- final InstanceIdentifier path, final StoreMetadataNode data) {
- return new InitialDataChangeEvent(path, data.getData());
+ private StoreUtils() {
+ throw new UnsupportedOperationException("Utility class should not be instantiated");
}
/*
return (Function) EXTRACT_IDENTIFIER;
}
- private static final class InitialDataChangeEvent implements
- AsyncDataChangeEvent<InstanceIdentifier, NormalizedNode<?, ?>> {
-
- private final ImmutableMap<InstanceIdentifier, NormalizedNode<?, ?>> payload;
- private final NormalizedNode<?, ?> data;
-
- public InitialDataChangeEvent(final InstanceIdentifier path, final NormalizedNode<?, ?> data) {
- payload = ImmutableMap.<InstanceIdentifier, NormalizedNode<?, ?>> of(path, data);
- this.data = data;
- }
-
- @Override
- public Map<InstanceIdentifier, NormalizedNode<?, ?>> getCreatedData() {
- return payload;
- }
-
- @Override
- public Map<InstanceIdentifier, ? extends NormalizedNode<?, ?>> getOriginalData() {
- return Collections.emptyMap();
- }
-
- @Override
- public NormalizedNode<?, ?> getOriginalSubtree() {
- return null;
- }
-
- @Override
- public Set<InstanceIdentifier> getRemovedPaths() {
- return Collections.emptySet();
- }
-
- @Override
- public Map<InstanceIdentifier, NormalizedNode<?, ?>> getUpdatedData() {
- return payload;
- }
+ public static final UnsignedLong increase(final UnsignedLong original) {
+ return original.plus(UnsignedLong.ONE);
+ }
- @Override
- public NormalizedNode<?, ?> getUpdatedSubtree() {
- return data;
- }
+ public static final InstanceIdentifier append(final InstanceIdentifier parent, final PathArgument arg) {
+ return new InstanceIdentifier(ImmutableList.<PathArgument> builder().addAll(parent.getPath()).add(arg).build());
}
public static <V> Set<V> toIdentifierSet(final Iterable<? extends Identifiable<V>> children) {
return FluentIterable.from(children).transform(StoreUtils.<V> identifierExtractor()).toSet();
}
- public static String toStringTree(final StoreMetadataNode metaNode) {
+ public static String toStringTree(final NormalizedNode<?, ?> node) {
StringBuilder builder = new StringBuilder();
- toStringTree(builder, metaNode, 0);
+ toStringTree(builder, node, 0);
return builder.toString();
}
- private static void toStringTree(final StringBuilder builder, final StoreMetadataNode metaNode, final int offset) {
- String prefix = Strings.repeat(" ", offset);
- builder.append(prefix).append(toStringTree(metaNode.getIdentifier()));
- NormalizedNode<?, ?> dataNode = metaNode.getData();
- if (dataNode instanceof NormalizedNodeContainer<?, ?, ?>) {
+ private static void toStringTree(final StringBuilder builder, final NormalizedNode<?, ?> node, final int offset) {
+ final String prefix = Strings.repeat(" ", offset);
+
+ builder.append(prefix).append(toStringTree(node.getIdentifier()));
+ if (node instanceof NormalizedNodeContainer<?, ?, ?>) {
+ final NormalizedNodeContainer<?, ?, ?> container = (NormalizedNodeContainer<?, ?, ?>) node;
+
builder.append(" {\n");
- for (StoreMetadataNode child : metaNode.getChildren()) {
- toStringTree(builder, child, offset + 4);
+ for (NormalizedNode<?, ?> child : container.getValue()) {
+ toStringTree(builder, child, offset + STRINGTREE_INDENT);
}
+
builder.append(prefix).append('}');
} else {
- builder.append(' ').append(dataNode.getValue());
+ builder.append(' ').append(node.getValue());
}
builder.append('\n');
}
import static com.google.common.base.Preconditions.checkState;
import java.util.Collections;
-import java.util.LinkedHashMap;
+import java.util.HashMap;
import java.util.Map;
import org.opendaylight.yangtools.concepts.Identifiable;
import com.google.common.base.Optional;
import com.google.common.base.Preconditions;
-import com.google.common.collect.Iterables;
import com.google.common.primitives.UnsignedLong;
public class StoreMetadataNode implements Immutable, Identifiable<PathArgument>, StoreTreeNode<StoreMetadataNode> {
return this.data;
}
- public Iterable<StoreMetadataNode> getChildren() {
- return Iterables.unmodifiableIterable(children.values());
- }
-
@Override
public Optional<StoreMetadataNode> getChild(final PathArgument key) {
return Optional.fromNullable(children.get(key));
private boolean dirty = false;
private Builder() {
- children = new LinkedHashMap<>();
+ children = new HashMap<>();
}
public Builder(StoreMetadataNode node) {
- children = new LinkedHashMap<>(node.children);
+ children = new HashMap<>(node.children);
}
public UnsignedLong getVersion() {
public Builder add(final StoreMetadataNode node) {
if (dirty) {
- children = new LinkedHashMap<>(children);
+ children = new HashMap<>(children);
dirty = false;
}
children.put(node.getIdentifier(), node);
public Builder remove(final PathArgument id) {
if (dirty) {
- children = new LinkedHashMap<>(children);
+ children = new HashMap<>(children);
dirty = false;
}
children.remove(id);
import java.util.concurrent.ExecutionException;
import org.junit.Before;
+import org.junit.Ignore;
import org.junit.Test;
import org.opendaylight.controller.sal.core.spi.data.DOMStoreReadTransaction;
import org.opendaylight.controller.sal.core.spi.data.DOMStoreReadWriteTransaction;
}
@Test
+ @Ignore
public void testTransactionConflict() throws InterruptedException, ExecutionException {
DOMStoreReadWriteTransaction txOne = domStore.newReadWriteTransaction();
DOMStoreReadWriteTransaction txTwo = domStore.newReadWriteTransaction();
@Test
public void basicReadWrites() {
- MutableDataTree modificationTree = MutableDataTree.from(
- DataAndMetadataSnapshot.builder() //
- .setMetadataTree(StoreMetadataNode.createRecursively(createDocumentOne(), UnsignedLong.valueOf(5))) //
- .setSchemaContext(schemaContext) //
- .build(), new SchemaAwareApplyOperationRoot(schemaContext));
+ MutableDataTree modificationTree = MutableDataTree.from(new DataTree.Snapshot(schemaContext,
+ StoreMetadataNode.createRecursively(createDocumentOne(), UnsignedLong.valueOf(5))),
+ new SchemaAwareApplyOperationRoot(schemaContext));
Optional<NormalizedNode<?, ?>> originalBarNode = modificationTree.read(OUTER_LIST_2_PATH);
assertTrue(originalBarNode.isPresent());
assertSame(BAR_NODE, originalBarNode.get());
/**
* Creates empty Snapshot with associated schema context.
*/
- DataAndMetadataSnapshot emptySnapshot = DataAndMetadataSnapshot.createEmpty(schemaContext);
+ DataTree t = DataTree.create(schemaContext);
/**
*
* context.
*
*/
- MutableDataTree modificationTree = MutableDataTree.from(emptySnapshot, new SchemaAwareApplyOperationRoot(
+ MutableDataTree modificationTree = MutableDataTree.from(t.takeSnapshot(), new SchemaAwareApplyOperationRoot(
schemaContext));
return modificationTree;
}
+++ /dev/null
-<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"\r
- xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">\r
- <modelVersion>4.0.0</modelVersion>\r
- <parent>\r
- <groupId>org.opendaylight.controller</groupId>\r
- <artifactId>sal-parent</artifactId>\r
- <version>1.0-SNAPSHOT</version>\r
- </parent>\r
- <artifactId>sal-core-demo</artifactId>\r
- <scm>\r
- <connection>scm:git:ssh://git.opendaylight.org:29418/controller.git</connection>\r
- <developerConnection>scm:git:ssh://git.opendaylight.org:29418/controller.git</developerConnection>\r
- <url>https://wiki.opendaylight.org/view/OpenDaylight_Controller:MD-SAL</url>\r
- </scm>\r
-\r
- <dependencies>\r
- <dependency>\r
- <groupId>org.opendaylight.controller</groupId>\r
- <artifactId>sal-broker-impl</artifactId>\r
- <version>1.0-SNAPSHOT</version>\r
- </dependency>\r
- <dependency>\r
- <groupId>org.opendaylight.controller</groupId>\r
- <artifactId>yang-data-util</artifactId>\r
- </dependency>\r
- <dependency>\r
- <groupId>org.slf4j</groupId>\r
- <artifactId>slf4j-simple</artifactId>\r
- <version>1.7.2</version>\r
- <scope>runtime</scope>\r
- </dependency>\r
- </dependencies>\r
- <build>\r
- <plugins>\r
- <plugin>\r
- <artifactId>maven-assembly-plugin</artifactId>\r
- <version>2.4</version>\r
- <configuration>\r
- <descriptorRefs>\r
- <descriptorRef>jar-with-dependencies</descriptorRef>\r
- </descriptorRefs>\r
- <archive>\r
- <manifest>\r
- <mainClass>org.opendaylight.controller.sal.demo.SALDemo</mainClass>\r
- </manifest>\r
- </archive>\r
- </configuration>\r
- <executions>\r
- <execution>\r
- <id>make-assembly</id>\r
- <phase>package</phase>\r
- <goals>\r
- <goal>single</goal>\r
- </goals>\r
- </execution>\r
- </executions>\r
- </plugin>\r
-\r
- </plugins>\r
-\r
- </build>\r
-</project>\r
+++ /dev/null
-/*\r
- * Copyright (c) 2013 Cisco Systems, Inc. and others. All rights reserved.\r
- *\r
- * This program and the accompanying materials are made available under the\r
- * terms of the Eclipse Public License v1.0 which accompanies this distribution,\r
- * and is available at http://www.eclipse.org/legal/epl-v10.html\r
- */\r
-package org.opendaylight.controller.sal.demo;\r
-\r
-import java.util.Collection;\r
-import java.util.HashSet;\r
-import java.util.Set;\r
-\r
-import org.opendaylight.controller.sal.core.api.Consumer;\r
-import org.opendaylight.controller.sal.core.api.Broker.ConsumerSession;\r
-import org.opendaylight.controller.sal.core.api.notify.NotificationListener;\r
-import org.opendaylight.controller.sal.core.api.notify.NotificationService;\r
-import org.opendaylight.controller.yang.common.QName;\r
-import org.opendaylight.controller.yang.data.api.CompositeNode;\r
-import org.slf4j.Logger;\r
-import org.slf4j.LoggerFactory;\r
-\r
-\r
-public class DemoConsumerImpl implements Consumer {\r
-\r
- private ConsumerSession session;\r
- private NotificationService notificationService;\r
- private final String name;\r
- private static Logger log = LoggerFactory.getLogger("AlertLogger");\r
-\r
- private boolean changeAware;\r
-\r
- public DemoConsumerImpl(String name) {\r
- this.name = name;\r
- }\r
-\r
- private NotificationListener alertLogger = new NotificationListener() {\r
-\r
- @Override\r
- public void onNotification(CompositeNode notification) {\r
- System.out.println(name\r
- + ": Received alert: "\r
- + notification.getFirstSimpleByName(\r
- DemoUtils.contentNodeName).getValue());\r
- log.info("AlertLogger: Received notification: " + notification);\r
- }\r
-\r
- @Override\r
- public Set<QName> getSupportedNotifications() {\r
- Set<QName> supported = new HashSet<QName>();\r
- supported.add(DemoUtils.alertNotification);\r
- return supported;\r
- }\r
- };\r
-\r
- private NotificationListener changeLogger = new NotificationListener() {\r
-\r
- @Override\r
- public void onNotification(CompositeNode notification) {\r
- System.out.println(name\r
- + ": Received change: "\r
- + notification.getFirstSimpleByName(\r
- DemoUtils.contentNodeName).getValue());\r
- log.info("ChangeLogger: Received notification: " + notification);\r
- }\r
-\r
- @Override\r
- public Set<QName> getSupportedNotifications() {\r
- Set<QName> supported = new HashSet<QName>();\r
- supported.add(DemoUtils.alertNotification);\r
- return supported;\r
- }\r
- };\r
-\r
- @Override\r
- public void onSessionInitiated(ConsumerSession session) {\r
- this.session = session;\r
- this.notificationService = session\r
- .getService(NotificationService.class);\r
- notificationService.addNotificationListener(\r
- DemoUtils.alertNotification, alertLogger);\r
- if (isChangeAware()) {\r
- notificationService.addNotificationListener(\r
- DemoUtils.changeNotification, changeLogger);\r
- }\r
- }\r
-\r
- @Override\r
- public Collection<ConsumerFunctionality> getConsumerFunctionality() {\r
- Set<ConsumerFunctionality> func = new HashSet<ConsumerFunctionality>();\r
- func.add(alertLogger);\r
- return func;\r
- }\r
-\r
- public void closeSession() {\r
- session.close();\r
- }\r
-\r
- public boolean isChangeAware() {\r
- return changeAware;\r
- }\r
-\r
- public void setChangeAware(boolean changeAware) {\r
- this.changeAware = changeAware;\r
- }\r
-\r
-}\r
+++ /dev/null
-/*
- * 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.sal.demo;
-
-import java.util.ArrayList;
-import java.util.Collection;
-import java.util.Collections;
-import java.util.List;
-
-import org.opendaylight.controller.sal.core.api.Broker.ProviderSession;
-import org.opendaylight.controller.sal.core.api.notify.NotificationProviderService;
-import org.opendaylight.controller.yang.data.api.Node;
-import org.opendaylight.controller.yang.data.util.Nodes;
-
-
-public class DemoProviderImpl implements
- org.opendaylight.controller.sal.core.api.Provider {
-
- private ProviderSession session;
- private NotificationProviderService notifier;
-
- @Override
- public void onSessionInitiated(ProviderSession session) {
- this.session = session;
- notifier = session.getService(NotificationProviderService.class);
- }
-
- @Override
- public Collection<ProviderFunctionality> getProviderFunctionality() {
- return Collections.emptySet();
- }
-
- public void sendAlertNotification(String content) {
- List<Node<?>> nodes = new ArrayList<Node<?>>();
- nodes.add(DemoUtils.contentNode(content));
-
- if (notifier == null) {
- System.out.println("Provider: Error: Session not available");
- System.out
- .println(" Notification Service not available");
- return;
- }
- notifier.sendNotification(Nodes.containerNode(
- DemoUtils.alertNotification, nodes));
- }
-
- public void sendChangeNotification(String content) {
- List<Node<?>> nodes = new ArrayList<Node<?>>();
- nodes.add(DemoUtils.contentNode(content));
-
- if (notifier == null) {
- System.out.println("Provider: Error: Session not available");
- System.out
- .println(" Notification Service not available");
- return;
- }
- notifier.sendNotification(Nodes.containerNode(
- DemoUtils.changeNotification, nodes));
- }
-
- public void closeSession() {
- session.close();
- }
-}
+++ /dev/null
-/*
- * 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.sal.demo;
-
-import java.net.URI;
-import java.net.URISyntaxException;
-import java.util.Date;
-
-import org.opendaylight.controller.yang.common.QName;
-import org.opendaylight.controller.yang.data.api.Node;
-import org.opendaylight.controller.yang.data.util.Nodes;
-
-
-public class DemoUtils {
-
- public static final URI namespace = uri("urn:cisco:prototype:sal:demo");
- public static final Date revision = new Date();
-
- public static final QName alertNotification = qName("alert");
- public static final QName changeNotification = qName("change");
-
- public static final QName contentNodeName = qName("content");
-
- public static URI uri(String str) {
- try {
- return new URI(str);
- } catch (URISyntaxException e) {
- throw new IllegalArgumentException(e);
- }
- }
-
- public static QName qName(String str) {
- return new QName(namespace, revision, str);
- }
-
- public static Node<?> contentNode(String content) {
- return Nodes.leafNode(contentNodeName, content);
- }
-}
+++ /dev/null
-/*\r
- * Copyright (c) 2013 Cisco Systems, Inc. and others. All rights reserved.\r
- *\r
- * This program and the accompanying materials are made available under the\r
- * terms of the Eclipse Public License v1.0 which accompanies this distribution,\r
- * and is available at http://www.eclipse.org/legal/epl-v10.html\r
- */\r
-package org.opendaylight.controller.sal.demo;\r
-\r
-import java.io.BufferedReader;\r
-import java.io.IOException;\r
-import java.io.InputStreamReader;\r
-\r
-import org.opendaylight.controller.sal.core.impl.BrokerImpl;\r
-import org.opendaylight.controller.sal.core.impl.NotificationModule;\r
-\r
-\r
-import org.slf4j.Logger;\r
-import org.slf4j.LoggerFactory;\r
-\r
-public class SALDemo {\r
- protected static final Logger logger = LoggerFactory\r
- .getLogger(SALDemo.class);\r
-\r
- static BrokerImpl broker;\r
- static DemoProviderImpl provider;\r
- static DemoConsumerImpl consumer1;\r
- static DemoConsumerImpl consumer2;\r
-\r
- public static void main(String[] args) {\r
-\r
- initialize();\r
- initializeProvider();\r
- displayHelp();\r
-\r
- BufferedReader in = new BufferedReader(new InputStreamReader(System.in));\r
- String s;\r
- try {\r
- while (true) {\r
-\r
- System.out.print("\nEnter your choice (0 - list): ");\r
- s = in.readLine();\r
- int choice = Integer.parseInt(s.trim());\r
- try {\r
- switch (choice) {\r
- case 0:\r
- displayHelp();\r
- break;\r
- case 1:\r
- registerProvider();\r
- break;\r
- case 2:\r
- registerConsumer1();\r
- break;\r
- case 3:\r
- registerConsumer2();\r
- break;\r
- case 4:\r
- sendAlert(in);\r
- break;\r
- case 5:\r
- sendChange(in);\r
- break;\r
- case 6:\r
- unregisterConsumer1();\r
- break;\r
- case 7:\r
- unregisterConsumer2();\r
- break;\r
- case 8:\r
- unregisterProvider();\r
- break;\r
- case 9:\r
- return;\r
- default:\r
- System.out.println("Please enter valid input.");\r
- break;\r
- }\r
- } catch (Exception e) {\r
- System.out\r
- .println("Operation failed. Reason exception raised: "\r
- + e.getClass().getSimpleName());\r
- System.out.println(" Message: " + e.getMessage());\r
- }\r
-\r
- }\r
- } catch (IOException e) {\r
-\r
- logger.error("",e);\r
- }\r
- }\r
-\r
- private static void registerConsumer1() {\r
- broker.registerConsumer(consumer1);\r
- }\r
-\r
- private static void registerConsumer2() {\r
- broker.registerConsumer(consumer2);\r
- }\r
-\r
- private static void sendAlert(BufferedReader in) throws IOException {\r
- System.out.print("Please enter notification content:");\r
- String content = in.readLine();\r
- provider.sendAlertNotification(content);\r
- }\r
-\r
- private static void sendChange(BufferedReader in) throws IOException {\r
- System.out.print("Please enter notification content:");\r
- String content = in.readLine();\r
- provider.sendChangeNotification(content);\r
- }\r
-\r
- private static void unregisterConsumer1() {\r
- consumer1.closeSession();\r
- }\r
-\r
- private static void unregisterConsumer2() {\r
- consumer2.closeSession();\r
- }\r
-\r
- private static void unregisterProvider() {\r
- provider.closeSession();\r
- }\r
-\r
- private static void displayHelp() {\r
- System.out.println("Usage: ");\r
- System.out.println(" 0) Display Help");\r
- System.out.println(" 1) Register Provider");\r
- System.out.println(" 2) Register Consumer 1 (listening on alert)");\r
- System.out\r
- .println(" 3) Register Consumer 2 (listening on alert,change)");\r
- System.out.println(" 4) Send Alert Notification");\r
- System.out.println(" 5) Send Change Notification");\r
- System.out.println(" 6) Unregister Consumer 1");\r
- System.out.println(" 7) Unregister Consumer 2");\r
- System.out.println(" 8) Unregister Provider");\r
- System.out.println(" 9) Exit");\r
-\r
- }\r
-\r
- private static void initializeProvider() {\r
- provider = new DemoProviderImpl();\r
- }\r
-\r
- private static void initialize() {\r
- System.out.println("Initializing broker");\r
- broker = new BrokerImpl();\r
- NotificationModule notifyModule = new NotificationModule();\r
- broker.addModule(notifyModule);\r
-\r
- consumer1 = new DemoConsumerImpl("Consumer 1");\r
- consumer2 = new DemoConsumerImpl("Consumer 2");\r
- consumer2.setChangeAware(true);\r
- }\r
-\r
- private static void registerProvider() {\r
- broker.registerProvider(provider);\r
- }\r
-}\r
+++ /dev/null
-/*\r
- * Copyright (c) 2013 Cisco Systems, Inc. and others. All rights reserved.\r
- *\r
- * This program and the accompanying materials are made available under the\r
- * terms of the Eclipse Public License v1.0 which accompanies this distribution,\r
- * and is available at http://www.eclipse.org/legal/epl-v10.html\r
- */\r
-package org.opendaylight.controller.sal.demo;
\ No newline at end of file
import org.opendaylight.controller.netconf.client.NetconfClientDispatcherImpl;
import org.opendaylight.controller.netconf.client.conf.NetconfClientConfiguration;
import org.opendaylight.controller.netconf.client.conf.NetconfClientConfigurationBuilder;
+import org.opendaylight.controller.netconf.client.conf.NetconfReconnectingClientConfiguration;
+import org.opendaylight.controller.netconf.client.conf.NetconfReconnectingClientConfigurationBuilder;
import org.opendaylight.controller.netconf.util.handler.ssh.authentication.LoginPassword;
import org.opendaylight.controller.sal.binding.api.data.DataProviderService;
import org.opendaylight.controller.sal.connect.netconf.NetconfDevice;
import org.opendaylight.controller.sal.connect.netconf.NetconfDeviceListener;
import org.opendaylight.protocol.framework.ReconnectStrategy;
+import org.opendaylight.protocol.framework.ReconnectStrategyFactory;
import org.opendaylight.protocol.framework.TimedReconnectStrategy;
import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.Nodes;
import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.nodes.Node;
this.bundleContext = bundleContext;
}
- public NetconfClientConfiguration getClientConfig(final NetconfDevice device) {
+ public NetconfReconnectingClientConfiguration getClientConfig(final NetconfDevice device) {
InetSocketAddress socketAddress = getSocketAddress();
ReconnectStrategy strategy = getReconnectStrategy();
long clientConnectionTimeoutMillis = getConnectionTimeoutMillis();
- return NetconfClientConfigurationBuilder.create()
+ return NetconfReconnectingClientConfigurationBuilder.create()
.withAddress(socketAddress)
.withConnectionTimeoutMillis(clientConnectionTimeoutMillis)
.withReconnectStrategy(strategy)
.withProtocol(getTcpOnly() ?
NetconfClientConfiguration.NetconfClientProtocol.TCP :
NetconfClientConfiguration.NetconfClientProtocol.SSH)
+ .withConnectStrategyFactory(new ReconnectStrategyFactory() {
+ @Override
+ public ReconnectStrategy createReconnectStrategy() {
+ return getReconnectStrategy();
+ }
+ })
.build();
}
logger.trace("Setting {} on {} to infinity", maxConnectionAttemptsJmxAttribute, this);
connectionAttempts = null;
}
- double sleepFactor = 1.0;
+ double sleepFactor = 1.5;
int minSleep = 1000;
Long maxSleep = null;
Long deadline = null;
import org.opendaylight.controller.md.sal.common.api.data.DataReader;
import org.opendaylight.controller.netconf.client.NetconfClientDispatcher;
import org.opendaylight.controller.netconf.client.conf.NetconfClientConfiguration;
+import org.opendaylight.controller.netconf.client.conf.NetconfReconnectingClientConfiguration;
import org.opendaylight.controller.sal.binding.api.data.DataProviderService;
import org.opendaylight.controller.sal.core.api.Broker.ProviderSession;
import org.opendaylight.controller.sal.core.api.Broker.RpcRegistration;
private boolean rollbackSupported;
- private NetconfClientConfiguration clientConfig;
+ private NetconfReconnectingClientConfiguration clientConfig;
private volatile DataProviderService dataProviderService;
public NetconfDevice(String name) {
logger.info("Starting NETCONF Client {} for address {}", name, socketAddress);
- dispatcher.createClient(clientConfig);
+ dispatcher.createReconnectingClient(clientConfig);
}
Optional<SchemaContext> getSchemaContext() {
this.dispatcher = dispatcher;
}
- public void setClientConfig(final NetconfClientConfiguration clientConfig) {
+ public void setClientConfig(final NetconfReconnectingClientConfiguration clientConfig) {
this.clientConfig = clientConfig;
}
<groupId>io.netty</groupId>
<artifactId>netty-codec-http</artifactId>
</dependency>
- <dependency>
- <groupId>org.eclipse.xtend</groupId>
- <artifactId>org.eclipse.xtend.lib</artifactId>
- </dependency>
<dependency>
<groupId>org.opendaylight.controller</groupId>
<artifactId>sal-remote</artifactId>
<instructions>
<Bundle-Name>MD SAL Restconf Connector</Bundle-Name>
<Private-Package>org.opendaylight.controller.sal.rest.*,
- org.opendaylight.controller.sal.restconf.impl,
- org.eclipse.xtend2.lib,
- org.eclipse.xtend.lib,
- org.eclipse.xtext.xbase.*,</Private-Package>
+ org.opendaylight.controller.sal.restconf.impl,</Private-Package>
<Import-Package>*,
com.sun.jersey.spi.container.servlet</Import-Package>
<Bundle-Activator>org.opendaylight.controller.sal.rest.impl.RestconfProvider</Bundle-Activator>
</instructions>
</configuration>
</plugin>
- <plugin>
- <groupId>org.eclipse.xtend</groupId>
- <artifactId>xtend-maven-plugin</artifactId>
- </plugin>
</plugins>
</build>
<scm>
--- /dev/null
+/**
+ * Copyright (c) 2014 Cisco Systems, Inc. and others. All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+package org.opendaylight.controller.sal.restconf.impl;
+
+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.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.RestconfProvider;
+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.data.api.CompositeNode;
+import org.opendaylight.yangtools.yang.data.api.InstanceIdentifier;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+public class BrokerFacade implements DataReader<InstanceIdentifier, CompositeNode> {
+ 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 BrokerFacade() {
+ }
+
+ public void setContext( final ConsumerSession context ) {
+ this.context = context;
+ }
+
+ public void setDataService( final DataBrokerService dataService ) {
+ this.dataService = dataService;
+ }
+
+ public static BrokerFacade getInstance() {
+ return BrokerFacade.INSTANCE;
+ }
+
+ private void checkPreconditions() {
+ if( context == null || dataService == null ) {
+ ResponseException _responseException = new ResponseException( Status.SERVICE_UNAVAILABLE,
+ RestconfProvider.NOT_INITALIZED_MSG );
+ throw _responseException;
+ }
+ }
+
+ @Override
+ public CompositeNode readConfigurationData( final InstanceIdentifier path ) {
+ this.checkPreconditions();
+
+ LOG.trace( "Read Configuration via Restconf: {}", path );
+
+ return dataService.readConfigurationData( path );
+ }
+
+ public CompositeNode readConfigurationDataBehindMountPoint( final MountInstance mountPoint,
+ final InstanceIdentifier path ) {
+ this.checkPreconditions();
+
+ LOG.trace( "Read Configuration via Restconf: {}", path );
+
+ return mountPoint.readConfigurationData( path );
+ }
+
+ @Override
+ public CompositeNode readOperationalData( final InstanceIdentifier path ) {
+ this.checkPreconditions();
+
+ BrokerFacade.LOG.trace( "Read Operational via Restconf: {}", path );
+
+ return dataService.readOperationalData( path );
+ }
+
+ public CompositeNode readOperationalDataBehindMountPoint( final MountInstance mountPoint,
+ final InstanceIdentifier path ) {
+ this.checkPreconditions();
+
+ BrokerFacade.LOG.trace( "Read Operational via Restconf: {}", path );
+
+ return mountPoint.readOperationalData( path );
+ }
+
+ public RpcResult<CompositeNode> invokeRpc( final QName type, final CompositeNode payload ) {
+ this.checkPreconditions();
+
+ final Future<RpcResult<CompositeNode>> future = context.rpc( type, payload );
+
+ try {
+ return future.get();
+ }
+ catch( Exception e ) {
+ throw new ResponseException( e, "Error invoking RPC " + type );
+ }
+ }
+
+ public Future<RpcResult<TransactionStatus>> commitConfigurationDataPut( final InstanceIdentifier path,
+ final CompositeNode payload ) {
+ this.checkPreconditions();
+
+ final DataModificationTransaction transaction = dataService.beginTransaction();
+ BrokerFacade.LOG.trace( "Put Configuration via Restconf: {}", path );
+ transaction.putConfigurationData( path, payload );
+ return transaction.commit();
+ }
+
+ public Future<RpcResult<TransactionStatus>> commitConfigurationDataPutBehindMountPoint(
+ final MountInstance mountPoint, final InstanceIdentifier path, final CompositeNode payload ) {
+ this.checkPreconditions();
+
+ final DataModificationTransaction transaction = mountPoint.beginTransaction();
+ BrokerFacade.LOG.trace( "Put Configuration via Restconf: {}", path );
+ transaction.putConfigurationData( path, payload );
+ return transaction.commit();
+ }
+
+ public Future<RpcResult<TransactionStatus>> commitConfigurationDataPost( final InstanceIdentifier 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());
+ // FIXME: return correct ietf-restconf:errors -> follow specification
+ // (http://tools.ietf.org/html/draft-bierman-netconf-restconf-03#page-48)
+ throw new ResponseException(Status.CONFLICT, errMsg);
+ }
+ BrokerFacade.LOG.trace( "Post Configuration via Restconf: {}", path );
+ transaction.putConfigurationData( path, payload );
+ return transaction.commit();
+ }
+
+ public Future<RpcResult<TransactionStatus>> commitConfigurationDataPostBehindMountPoint(
+ final MountInstance mountPoint, final InstanceIdentifier 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());
+ // FIXME: return correct ietf-restconf:errors -> follow specification
+ // (http://tools.ietf.org/html/draft-bierman-netconf-restconf-03#page-48)
+ throw new ResponseException(Status.CONFLICT, errMsg);
+ }
+ BrokerFacade.LOG.trace( "Post Configuration via Restconf: {}", path );
+ transaction.putConfigurationData( path, payload );
+ return transaction.commit();
+ }
+
+ public Future<RpcResult<TransactionStatus>> commitConfigurationDataDelete( final InstanceIdentifier path ) {
+ this.checkPreconditions();
+
+ final DataModificationTransaction transaction = dataService.beginTransaction();
+ LOG.info( "Delete Configuration via Restconf: {}", path );
+ transaction.removeConfigurationData( path );
+ return transaction.commit();
+ }
+
+ public Future<RpcResult<TransactionStatus>> commitConfigurationDataDeleteBehindMountPoint(
+ final MountInstance mountPoint, final InstanceIdentifier path ) {
+ this.checkPreconditions();
+
+ final DataModificationTransaction transaction = mountPoint.beginTransaction();
+ LOG.info( "Delete Configuration via Restconf: {}", path );
+ transaction.removeConfigurationData( path );
+ return transaction.commit();
+ }
+
+ public void registerToListenDataChanges( final ListenerAdapter listener ) {
+ this.checkPreconditions();
+
+ if( listener.isListening() ) {
+ return;
+ }
+
+ InstanceIdentifier path = listener.getPath();
+ final ListenerRegistration<DataChangeListener> registration =
+ dataService.registerDataChangeListener( path, listener );
+
+ listener.setRegistration( registration );
+ }
+}
+++ /dev/null
-/*
- * Copyright (c) 2014 Cisco Systems, Inc. and others. All rights reserved.
- *
- * This program and the accompanying materials are made available under the
- * terms of the Eclipse Public License v1.0 which accompanies this distribution,
- * and is available at http://www.eclipse.org/legal/epl-v10.html
- */
-package org.opendaylight.controller.sal.restconf.impl
-
-import javax.ws.rs.core.Response
-import org.opendaylight.controller.md.sal.common.api.data.DataReader
-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.mount.MountInstance
-import org.opendaylight.controller.sal.rest.impl.RestconfProvider
-import org.opendaylight.controller.sal.streams.listeners.ListenerAdapter
-import org.opendaylight.yangtools.yang.common.QName
-import org.opendaylight.yangtools.yang.common.RpcResult
-import org.opendaylight.yangtools.yang.data.api.CompositeNode
-import org.opendaylight.yangtools.yang.data.api.InstanceIdentifier
-import org.slf4j.LoggerFactory
-
-class BrokerFacade implements DataReader<InstanceIdentifier, CompositeNode> {
-
-
- val static LOG = LoggerFactory.getLogger(BrokerFacade)
- val static BrokerFacade INSTANCE = new BrokerFacade
-
- @Property
- private ConsumerSession context;
-
- @Property
- private DataBrokerService dataService;
-
- private new() {
- if (INSTANCE !== null) {
- throw new IllegalStateException("Already instantiated");
- }
- }
-
- def static BrokerFacade getInstance() {
- return INSTANCE
- }
-
- private def void checkPreconditions() {
- if (context === null || dataService === null) {
- throw new ResponseException(Response.Status.SERVICE_UNAVAILABLE, RestconfProvider::NOT_INITALIZED_MSG)
- }
- }
-
- override readConfigurationData(InstanceIdentifier path) {
- checkPreconditions
- LOG.trace("Read Configuration via Restconf: {}", path)
- return dataService.readConfigurationData(path);
- }
-
- def readConfigurationDataBehindMountPoint(MountInstance mountPoint, InstanceIdentifier path) {
- checkPreconditions
- LOG.trace("Read Configuration via Restconf: {}", path)
- return mountPoint.readConfigurationData(path);
- }
-
- override readOperationalData(InstanceIdentifier path) {
- checkPreconditions
- LOG.trace("Read Operational via Restconf: {}", path)
- return dataService.readOperationalData(path);
- }
-
- def readOperationalDataBehindMountPoint(MountInstance mountPoint, InstanceIdentifier path) {
- checkPreconditions
- LOG.trace("Read Operational via Restconf: {}", path)
- return mountPoint.readOperationalData(path);
- }
-
- def RpcResult<CompositeNode> invokeRpc(QName type, CompositeNode payload) {
- checkPreconditions
- val future = context.rpc(type, payload);
- return future.get;
- }
-
- def commitConfigurationDataPut(InstanceIdentifier path, CompositeNode payload) {
- checkPreconditions
- val transaction = dataService.beginTransaction;
- LOG.trace("Put Configuration via Restconf: {}", path)
- transaction.putConfigurationData(path, payload);
- return transaction.commit
- }
-
- def commitConfigurationDataPutBehindMountPoint(MountInstance mountPoint, InstanceIdentifier path, CompositeNode payload) {
- checkPreconditions
- val transaction = mountPoint.beginTransaction;
- LOG.trace("Put Configuration via Restconf: {}", path)
- transaction.putConfigurationData(path, payload);
- return transaction.commit
- }
-
- def commitConfigurationDataPost(InstanceIdentifier path, CompositeNode payload) {
- checkPreconditions
- val transaction = dataService.beginTransaction;
- transaction.putConfigurationData(path, payload);
- if (payload == transaction.createdConfigurationData.get(path)) {
- LOG.trace("Post Configuration via Restconf: {}", path)
- return transaction.commit
- }
- LOG.trace("Post Configuration via Restconf was not executed because data already exists: {}", path)
- return null;
- }
-
- def commitConfigurationDataPostBehindMountPoint(MountInstance mountPoint, InstanceIdentifier path, CompositeNode payload) {
- checkPreconditions
- val transaction = mountPoint.beginTransaction;
- transaction.putConfigurationData(path, payload);
- if (payload == transaction.createdConfigurationData.get(path)) {
- LOG.trace("Post Configuration via Restconf: {}", path)
- return transaction.commit
- }
- LOG.trace("Post Configuration via Restconf was not executed because data already exists: {}", path)
- return null;
- }
-
- def commitConfigurationDataDelete(InstanceIdentifier path) {
- checkPreconditions
- val transaction = dataService.beginTransaction;
- LOG.info("Delete Configuration via Restconf: {}", path)
- transaction.removeConfigurationData(path)
- return transaction.commit
- }
-
- def commitConfigurationDataDeleteBehindMountPoint(MountInstance mountPoint, InstanceIdentifier path) {
- checkPreconditions
- val transaction = mountPoint.beginTransaction;
- LOG.info("Delete Configuration via Restconf: {}", path)
- transaction.removeConfigurationData(path)
- return transaction.commit
- }
-
- def registerToListenDataChanges(ListenerAdapter listener) {
- checkPreconditions
- if (listener.listening) {
- return;
- }
- val registration = dataService.registerDataChangeListener(listener.path, listener)
- listener.setRegistration(registration)
- }
-
-}
--- /dev/null
+/**
+ * Copyright (c) 2014 Cisco Systems, Inc. and others. All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+package org.opendaylight.controller.sal.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.FluentIterable;
+import com.google.common.collect.HashBiMap;
+import com.google.common.collect.Iterables;
+import com.google.common.collect.Lists;
+
+import java.io.UnsupportedEncodingException;
+import java.net.URI;
+import java.net.URLDecoder;
+import java.net.URLEncoder;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.Comparator;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+import java.util.concurrent.ConcurrentHashMap;
+
+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.sal.rest.impl.RestUtil;
+import org.opendaylight.controller.sal.rest.impl.RestconfProvider;
+import org.opendaylight.controller.sal.restconf.impl.InstanceIdWithSchemaNode;
+import org.opendaylight.controller.sal.restconf.impl.ResponseException;
+import org.opendaylight.controller.sal.restconf.impl.RestCodec;
+import org.opendaylight.yangtools.concepts.Codec;
+import org.opendaylight.yangtools.yang.common.QName;
+import org.opendaylight.yangtools.yang.data.api.InstanceIdentifier;
+import org.opendaylight.yangtools.yang.data.api.InstanceIdentifier.InstanceIdentifierBuilder;
+import org.opendaylight.yangtools.yang.data.api.InstanceIdentifier.NodeIdentifier;
+import org.opendaylight.yangtools.yang.data.api.InstanceIdentifier.NodeIdentifierWithPredicates;
+import org.opendaylight.yangtools.yang.data.api.InstanceIdentifier.PathArgument;
+import org.opendaylight.yangtools.yang.model.api.ChoiceCaseNode;
+import org.opendaylight.yangtools.yang.model.api.ChoiceNode;
+import org.opendaylight.yangtools.yang.model.api.ContainerSchemaNode;
+import org.opendaylight.yangtools.yang.model.api.DataNodeContainer;
+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.Module;
+import org.opendaylight.yangtools.yang.model.api.RpcDefinition;
+import org.opendaylight.yangtools.yang.model.api.SchemaContext;
+import org.opendaylight.yangtools.yang.model.api.SchemaContextListener;
+import org.opendaylight.yangtools.yang.model.api.TypeDefinition;
+import org.opendaylight.yangtools.yang.model.api.type.IdentityrefTypeDefinition;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+public class ControllerContext implements SchemaContextListener {
+ private final static Logger LOG = LoggerFactory.getLogger( ControllerContext.class );
+
+ private final static ControllerContext INSTANCE = new ControllerContext();
+
+ private final static String NULL_VALUE = "null";
+
+ private final static String MOUNT_MODULE = "yang-ext";
+
+ private final static String MOUNT_NODE = "mount";
+
+ public final static String MOUNT = "yang-ext:mount";
+
+ private final static String URI_ENCODING_CHAR_SET = "ISO-8859-1";
+
+ private final BiMap<URI, String> uriToModuleName = HashBiMap.<URI, String> create();
+
+ private final Map<String, URI> moduleNameToUri = uriToModuleName.inverse();
+
+ private final Map<QName, RpcDefinition> qnameToRpc = new ConcurrentHashMap<>();
+
+ private volatile SchemaContext globalSchema;
+ private volatile MountService mountService;
+
+ public void setGlobalSchema( final SchemaContext globalSchema ) {
+ this.globalSchema = globalSchema;
+ }
+
+ public void setMountService( final MountService mountService ) {
+ this.mountService = mountService;
+ }
+
+ private ControllerContext() {
+ }
+
+ public static ControllerContext getInstance() {
+ return ControllerContext.INSTANCE;
+ }
+
+ private void checkPreconditions() {
+ if( globalSchema == null ) {
+ throw new ResponseException( Status.SERVICE_UNAVAILABLE, RestconfProvider.NOT_INITALIZED_MSG );
+ }
+ }
+
+ public void setSchemas( final SchemaContext schemas ) {
+ this.onGlobalContextUpdated( schemas );
+ }
+
+ public InstanceIdWithSchemaNode toInstanceIdentifier( final String restconfInstance ) {
+ return this.toIdentifier( restconfInstance, false );
+ }
+
+ public InstanceIdWithSchemaNode toMountPointIdentifier( final String restconfInstance ) {
+ return this.toIdentifier( restconfInstance, true );
+ }
+
+ private InstanceIdWithSchemaNode toIdentifier( final String restconfInstance,
+ final boolean toMountPointIdentifier ) {
+ this.checkPreconditions();
+
+ Iterable<String> split = Splitter.on( "/" ).split( restconfInstance );
+ final ArrayList<String> encodedPathArgs = Lists.<String> newArrayList( split );
+ final List<String> pathArgs = this.urlPathArgsDecode( encodedPathArgs );
+ this.omitFirstAndLastEmptyString( pathArgs );
+ if( pathArgs.isEmpty() ) {
+ return null;
+ }
+
+ String first = pathArgs.iterator().next();
+ final String startModule = ControllerContext.toModuleName( first );
+ if( startModule == null ) {
+ throw new ResponseException( Status.BAD_REQUEST,
+ "First node in URI has to be in format \"moduleName:nodeName\"" );
+ }
+
+ InstanceIdentifierBuilder builder = InstanceIdentifier.builder();
+ Module latestModule = this.getLatestModule( globalSchema, startModule );
+ InstanceIdWithSchemaNode iiWithSchemaNode = this.collectPathArguments( builder, pathArgs,
+ latestModule, null, toMountPointIdentifier );
+
+ if( iiWithSchemaNode == null ) {
+ throw new ResponseException( Status.BAD_REQUEST, "URI has bad format" );
+ }
+
+ return iiWithSchemaNode;
+ }
+
+ private List<String> omitFirstAndLastEmptyString( final List<String> list ) {
+ if( list.isEmpty() ) {
+ return list;
+ }
+
+ String head = list.iterator().next();
+ if( head.isEmpty() ) {
+ list.remove( 0 );
+ }
+
+ if( list.isEmpty() ) {
+ return list;
+ }
+
+ String last = list.get( list.size() - 1 );
+ if( last.isEmpty() ) {
+ list.remove( list.size() - 1 );
+ }
+
+ return list;
+ }
+
+ private Module getLatestModule( final SchemaContext schema, final String moduleName ) {
+ Preconditions.checkArgument( schema != null );
+ Preconditions.checkArgument( moduleName != null && !moduleName.isEmpty() );
+
+ Predicate<Module> filter = new Predicate<Module>() {
+ @Override
+ public boolean apply( Module m ) {
+ return Objects.equal( m.getName(), moduleName );
+ }
+ };
+
+ Iterable<Module> modules = Iterables.filter( schema.getModules(), filter );
+ return this.filterLatestModule( modules );
+ }
+
+ private Module filterLatestModule( final Iterable<Module> 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 );
+ }
+
+ public Module findModuleByName( final MountInstance mountPoint, final String moduleName ) {
+ Preconditions.checkArgument( moduleName != null && mountPoint != null );
+
+ final SchemaContext mountPointSchema = mountPoint.getSchemaContext();
+ return mountPointSchema == null ? null : this.getLatestModule( mountPointSchema, moduleName );
+ }
+
+ public Module findModuleByNamespace( final URI namespace ) {
+ this.checkPreconditions();
+ Preconditions.checkArgument( namespace != null );
+
+ final Set<Module> moduleSchemas = globalSchema.findModuleByNamespace( namespace );
+ return moduleSchemas == null ? null : this.filterLatestModule( moduleSchemas );
+ }
+
+ public Module findModuleByNamespace( final MountInstance mountPoint, final URI namespace ) {
+ Preconditions.checkArgument( namespace != null && mountPoint != null );
+
+ final SchemaContext mountPointSchema = mountPoint.getSchemaContext();
+ Set<Module> moduleSchemas = mountPointSchema == null ? null :
+ mountPointSchema.findModuleByNamespace( namespace );
+ return moduleSchemas == null ? null : this.filterLatestModule( moduleSchemas );
+ }
+
+ public Module findModuleByNameAndRevision( final QName module ) {
+ this.checkPreconditions();
+ Preconditions.checkArgument( module != null && module.getLocalName() != null &&
+ module.getRevision() != null );
+
+ return globalSchema.findModuleByName( module.getLocalName(), module.getRevision() );
+ }
+
+ public Module findModuleByNameAndRevision( final MountInstance mountPoint, final QName module ) {
+ this.checkPreconditions();
+ Preconditions.checkArgument( module != null && module.getLocalName() != null &&
+ module.getRevision() != null && mountPoint != null );
+
+ SchemaContext schemaContext = mountPoint.getSchemaContext();
+ return schemaContext == null ? null :
+ schemaContext.findModuleByName( module.getLocalName(), module.getRevision() );
+ }
+
+ public DataNodeContainer getDataNodeContainerFor( final InstanceIdentifier path ) {
+ this.checkPreconditions();
+
+ final List<PathArgument> elements = path.getPath();
+ PathArgument head = elements.iterator().next();
+ final QName startQName = head.getNodeType();
+ final Module initialModule = globalSchema.findModuleByNamespaceAndRevision(
+ startQName.getNamespace(), startQName.getRevision() );
+ DataNodeContainer node = initialModule;
+ for( final PathArgument element : elements ) {
+ QName _nodeType = element.getNodeType();
+ final DataSchemaNode potentialNode = ControllerContext.childByQName( node, _nodeType );
+ if( potentialNode == null || !this.isListOrContainer( potentialNode ) ) {
+ return null;
+ }
+ node = (DataNodeContainer) potentialNode;
+ }
+
+ return node;
+ }
+
+ public String toFullRestconfIdentifier( final InstanceIdentifier path ) {
+ this.checkPreconditions();
+
+ final List<PathArgument> elements = path.getPath();
+ final StringBuilder builder = new StringBuilder();
+ PathArgument head = elements.iterator().next();
+ final QName startQName = head.getNodeType();
+ final Module initialModule = globalSchema.findModuleByNamespaceAndRevision(
+ startQName.getNamespace(), startQName.getRevision() );
+ DataNodeContainer node = initialModule;
+ for( final PathArgument element : elements ) {
+ QName _nodeType = element.getNodeType();
+ final DataSchemaNode potentialNode = ControllerContext.childByQName( node, _nodeType );
+ if( !this.isListOrContainer( potentialNode ) ) {
+ return null;
+ }
+ node = ((DataNodeContainer) potentialNode);
+ builder.append( this.convertToRestconfIdentifier( element, node ) );
+ }
+
+ return builder.toString();
+ }
+
+ 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;
+ }
+
+ public String findModuleNameByNamespace( final MountInstance 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;
+ }
+
+ public URI findNamespaceByModuleName( final MountInstance mountPoint, final String moduleName ) {
+ final Module module = this.findModuleByName( mountPoint, moduleName );
+ return module == null ? null : module.getNamespace();
+ }
+
+ public Set<Module> getAllModules( final MountInstance mountPoint ) {
+ this.checkPreconditions();
+
+ SchemaContext schemaContext = mountPoint == null ? null : mountPoint.getSchemaContext();
+ return schemaContext == null ? null : schemaContext.getModules();
+ }
+
+ public Set<Module> getAllModules() {
+ this.checkPreconditions();
+ return globalSchema.getModules();
+ }
+
+ 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();
+ }
+
+ public CharSequence toRestconfIdentifier( final MountInstance 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();
+ }
+
+ private static DataSchemaNode childByQName( final ChoiceNode container, final QName name ) {
+ for( final ChoiceCaseNode caze : container.getCases() ) {
+ final DataSchemaNode ret = ControllerContext.childByQName( caze, name );
+ if( ret != null ) {
+ return ret;
+ }
+ }
+
+ return null;
+ }
+
+ private static DataSchemaNode childByQName( final ChoiceCaseNode container, final QName name ) {
+ return container.getDataChildByName( name );
+ }
+
+ private static DataSchemaNode childByQName( final ContainerSchemaNode container, final QName name ) {
+ return ControllerContext.dataNodeChildByQName( container, name );
+ }
+
+ private static DataSchemaNode childByQName( final ListSchemaNode container, final QName name ) {
+ return ControllerContext.dataNodeChildByQName( container, name );
+ }
+
+ private static DataSchemaNode childByQName( final Module container, final QName name ) {
+ return ControllerContext.dataNodeChildByQName( container, name );
+ }
+
+ private static DataSchemaNode childByQName( final DataSchemaNode container, final QName name ) {
+ return null;
+ }
+
+ private static DataSchemaNode dataNodeChildByQName( final DataNodeContainer container, final QName name ) {
+ 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( childByQName != null ) {
+ return childByQName;
+ }
+ }
+ }
+ }
+ return ret;
+ }
+
+ private String toUriString( final Object object ) throws UnsupportedEncodingException {
+ return object == null ? "" :
+ URLEncoder.encode( object.toString(), ControllerContext.URI_ENCODING_CHAR_SET );
+ }
+
+ private InstanceIdWithSchemaNode collectPathArguments( final InstanceIdentifierBuilder builder,
+ final List<String> strings, final DataNodeContainer parentNode, final MountInstance mountPoint,
+ final boolean returnJustMountPoint ) {
+ Preconditions.<List<String>> checkNotNull( strings );
+
+ if( parentNode == null ) {
+ return null;
+ }
+
+ if( strings.isEmpty() ) {
+ return new InstanceIdWithSchemaNode( builder.toInstance(),
+ ((DataSchemaNode) parentNode), mountPoint );
+ }
+
+ String head = strings.iterator().next();
+ final String nodeName = this.toNodeName( head );
+ final String moduleName = ControllerContext.toModuleName( head );
+
+ DataSchemaNode targetNode = null;
+ if( !Strings.isNullOrEmpty( moduleName ) ) {
+ if( Objects.equal( moduleName, ControllerContext.MOUNT_MODULE ) &&
+ Objects.equal( nodeName, ControllerContext.MOUNT_NODE ) ) {
+ if( mountPoint != null ) {
+ throw new ResponseException( Status.BAD_REQUEST,
+ "Restconf supports just one mount point in URI." );
+ }
+
+ if( mountService == null ) {
+ throw new ResponseException( Status.SERVICE_UNAVAILABLE,
+ "MountService was not found. Finding behind mount points does not work." );
+ }
+
+ final InstanceIdentifier partialPath = builder.toInstance();
+ final MountInstance mount = mountService.getMountPoint( partialPath );
+ if( mount == null ) {
+ LOG.debug( "Instance identifier to missing mount point: {}", partialPath );
+ throw new ResponseException( Status.BAD_REQUEST,
+ "Mount point does not exist." );
+ }
+
+ final SchemaContext mountPointSchema = mount.getSchemaContext();
+ if( mountPointSchema == null ) {
+ throw new ResponseException( Status.BAD_REQUEST,
+ "Mount point does not contain any schema with modules." );
+ }
+
+ if( returnJustMountPoint ) {
+ InstanceIdentifier instance = InstanceIdentifier.builder().toInstance();
+ return new InstanceIdWithSchemaNode( instance, mountPointSchema, mount );
+ }
+
+ if( strings.size() == 1 ) {
+ InstanceIdentifier instance = InstanceIdentifier.builder().toInstance();
+ return new InstanceIdWithSchemaNode( instance, mountPointSchema, mount );
+ }
+
+ final String moduleNameBehindMountPoint = toModuleName( strings.get( 1 ) );
+ if( moduleNameBehindMountPoint == null ) {
+ throw new ResponseException( Status.BAD_REQUEST,
+ "First node after mount point in URI has to be in format \"moduleName:nodeName\"" );
+ }
+
+ final Module moduleBehindMountPoint = this.getLatestModule( mountPointSchema,
+ moduleNameBehindMountPoint );
+ if( moduleBehindMountPoint == null ) {
+ throw new ResponseException( Status.BAD_REQUEST,
+ "URI has bad format. \"" + moduleName +
+ "\" module does not exist in mount point." );
+ }
+
+ List<String> subList = strings.subList( 1, strings.size() );
+ return this.collectPathArguments( InstanceIdentifier.builder(), subList, moduleBehindMountPoint,
+ mount, returnJustMountPoint );
+ }
+
+ Module module = null;
+ if( mountPoint == null ) {
+ module = this.getLatestModule( globalSchema, moduleName );
+ if( module == null ) {
+ throw new ResponseException( Status.BAD_REQUEST,
+ "URI has bad format. \"" + moduleName + "\" module does not exist." );
+ }
+ }
+ else {
+ SchemaContext schemaContext = mountPoint.getSchemaContext();
+ module = schemaContext == null ? null :
+ this.getLatestModule( schemaContext, moduleName );
+ if( module == null ) {
+ throw new ResponseException( Status.BAD_REQUEST,
+ "URI has bad format. \"" + moduleName +
+ "\" module does not exist in mount point." );
+ }
+ }
+
+ targetNode = this.findInstanceDataChildByNameAndNamespace(
+ parentNode, nodeName, module.getNamespace() );;
+ if( targetNode == null ) {
+ throw new ResponseException( Status.BAD_REQUEST,
+ "URI has bad format. Possible reasons:\n" +
+ "1. \"" + head + "\" was not found in parent data node.\n" +
+ "2. \"" + head + "\" is behind mount point. Then it should be in format \"/" +
+ MOUNT + "/" + head + "\"." );
+ }
+ } else {
+ final List<DataSchemaNode> potentialSchemaNodes =
+ this.findInstanceDataChildrenByName( parentNode, nodeName );
+ if( potentialSchemaNodes.size() > 1 ) {
+ final StringBuilder strBuilder = new StringBuilder();
+ for( final DataSchemaNode potentialNodeSchema : potentialSchemaNodes ) {
+ strBuilder.append( " " )
+ .append( potentialNodeSchema.getQName().getNamespace() )
+ .append( "\n" );
+ }
+
+ throw new ResponseException( Status.BAD_REQUEST,
+ "URI has bad format. Node \"" + nodeName +
+ "\" is added as augment from more than one module. " +
+ "Therefore the node must have module name and it has to be in format \"moduleName:nodeName\"." +
+ "\nThe node is added as augment from modules with namespaces:\n" +
+ strBuilder.toString() );
+ }
+
+ if( potentialSchemaNodes.isEmpty() ) {
+ throw new ResponseException( Status.BAD_REQUEST, "URI has bad format. \"" + nodeName +
+ "\" was not found in parent data node.\n" );
+ }
+
+ targetNode = potentialSchemaNodes.iterator().next();
+ }
+
+ if( !this.isListOrContainer( targetNode ) ) {
+ throw new ResponseException( Status.BAD_REQUEST,
+ "URI has bad format. Node \"" + head +
+ "\" must be Container or List yang type." );
+ }
+
+ int consumed = 1;
+ if( (targetNode instanceof ListSchemaNode) ) {
+ final ListSchemaNode listNode = ((ListSchemaNode) targetNode);
+ final int keysSize = listNode.getKeyDefinition().size();
+ if( (strings.size() - consumed) < keysSize ) {
+ throw new ResponseException( Status.BAD_REQUEST, "Missing key for list \"" +
+ listNode.getQName().getLocalName() + "\"." );
+ }
+
+ final List<String> uriKeyValues = strings.subList( consumed, consumed + keysSize );
+ final HashMap<QName, Object> keyValues = new HashMap<QName, Object>();
+ int i = 0;
+ for( final QName key : listNode.getKeyDefinition() ) {
+ {
+ final String uriKeyValue = uriKeyValues.get( i );
+ if( uriKeyValue.equals( NULL_VALUE ) ) {
+ throw new ResponseException( Status.BAD_REQUEST,
+ "URI has bad format. List \"" + listNode.getQName().getLocalName() +
+ "\" cannot contain \"null\" value as a key." );
+ }
+
+ this.addKeyValue( keyValues, listNode.getDataChildByName( key ),
+ uriKeyValue, mountPoint );
+ i++;
+ }
+ }
+
+ consumed = consumed + i;
+ builder.nodeWithKey( targetNode.getQName(), keyValues );
+ }
+ else {
+ builder.node( targetNode.getQName() );
+ }
+
+ if( (targetNode instanceof DataNodeContainer) ) {
+ final List<String> remaining = strings.subList( consumed, strings.size() );
+ return this.collectPathArguments( builder, remaining,
+ ((DataNodeContainer) targetNode), mountPoint, returnJustMountPoint );
+ }
+
+ return new InstanceIdWithSchemaNode( builder.toInstance(), targetNode, mountPoint );
+ }
+
+ public DataSchemaNode findInstanceDataChildByNameAndNamespace( final DataNodeContainer container,
+ final String name, final URI namespace ) {
+ Preconditions.<URI> checkNotNull( namespace );
+
+ final List<DataSchemaNode> potentialSchemaNodes = this.findInstanceDataChildrenByName( container, name );
+
+ Predicate<DataSchemaNode> filter = new Predicate<DataSchemaNode>() {
+ @Override
+ public boolean apply( DataSchemaNode node ) {
+ return Objects.equal( node.getQName().getNamespace(), namespace );
+ }
+ };
+
+ Iterable<DataSchemaNode> result = Iterables.filter( potentialSchemaNodes, filter );
+ return Iterables.getFirst( result, null );
+ }
+
+ public List<DataSchemaNode> findInstanceDataChildrenByName( final DataNodeContainer container,
+ final String name ) {
+ Preconditions.<DataNodeContainer> checkNotNull( container );
+ Preconditions.<String> checkNotNull( name );
+
+ List<DataSchemaNode> instantiatedDataNodeContainers = new ArrayList<DataSchemaNode>();
+ this.collectInstanceDataNodeContainers( instantiatedDataNodeContainers, container, name );
+ return instantiatedDataNodeContainers;
+ }
+
+ private void collectInstanceDataNodeContainers( final List<DataSchemaNode> potentialSchemaNodes,
+ final DataNodeContainer container, final String name ) {
+
+ Set<DataSchemaNode> childNodes = container.getChildNodes();
+
+ Predicate<DataSchemaNode> filter = new Predicate<DataSchemaNode>() {
+ @Override
+ public boolean apply( DataSchemaNode node ) {
+ return Objects.equal( node.getQName().getLocalName(), name );
+ }
+ };
+
+ Iterable<DataSchemaNode> nodes = Iterables.filter( childNodes, filter );
+
+ // 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 ) ) {
+ potentialSchemaNodes.add( potentialNode );
+ }
+ }
+
+ Iterable<ChoiceNode> choiceNodes = Iterables.<ChoiceNode> filter( container.getChildNodes(),
+ ChoiceNode.class );
+
+ final Function<ChoiceNode, Set<ChoiceCaseNode>> choiceFunction =
+ new Function<ChoiceNode, Set<ChoiceCaseNode>>() {
+ @Override
+ public Set<ChoiceCaseNode> apply( final ChoiceNode node ) {
+ return node.getCases();
+ }
+ };
+
+ Iterable<Set<ChoiceCaseNode>> map = Iterables.<ChoiceNode, Set<ChoiceCaseNode>> transform(
+ choiceNodes, choiceFunction );
+
+ final Iterable<ChoiceCaseNode> allCases = Iterables.<ChoiceCaseNode> concat( map );
+ for( final ChoiceCaseNode caze : allCases ) {
+ this.collectInstanceDataNodeContainers( potentialSchemaNodes, caze, name );
+ }
+ }
+
+ public boolean isInstantiatedDataSchema( final DataSchemaNode node ) {
+ return node instanceof LeafSchemaNode || node instanceof LeafListSchemaNode ||
+ node instanceof ContainerSchemaNode || node instanceof ListSchemaNode;
+ }
+
+ private void addKeyValue( final HashMap<QName, Object> map, final DataSchemaNode node,
+ final String uriValue, final MountInstance mountPoint ) {
+ Preconditions.<String> checkNotNull( uriValue );
+ Preconditions.checkArgument( (node instanceof LeafSchemaNode) );
+
+ final String urlDecoded = urlPathArgDecode( uriValue );
+ final TypeDefinition<? extends Object> typedef = ((LeafSchemaNode) node).getType();
+ Codec<Object, Object> codec = RestCodec.from( typedef, mountPoint );
+
+ Object decoded = codec == null ? null : codec.deserialize( urlDecoded );
+ String additionalInfo = "";
+ if( decoded == null ) {
+ TypeDefinition<? extends Object> baseType = RestUtil.resolveBaseTypeFrom( typedef );
+ if( (baseType instanceof IdentityrefTypeDefinition) ) {
+ decoded = this.toQName( urlDecoded );
+ additionalInfo = "For key which is of type identityref it should be in format module_name:identity_name.";
+ }
+ }
+
+ if( decoded == null ) {
+ throw new ResponseException( Status.BAD_REQUEST, uriValue + " from URI can\'t be resolved. " +
+ additionalInfo );
+ }
+
+ map.put( node.getQName(), decoded );
+ }
+
+ private static String toModuleName( final String str ) {
+ Preconditions.<String> checkNotNull( str );
+ if( str.contains( ":" ) ) {
+ final String[] args = str.split( ":" );
+ if( args.length == 2 ) {
+ return args[0];
+ }
+ }
+ return null;
+ }
+
+ private String toNodeName( final String str ) {
+ if( str.contains( ":" ) ) {
+ final String[] args = str.split( ":" );
+ if( args.length == 2 ) {
+ return args[1];
+ }
+ }
+ return str;
+ }
+
+ private QName toQName( final String name ) {
+ final String module = toModuleName( name );
+ final String node = this.toNodeName( name );
+ Set<Module> modules = globalSchema.getModules();
+
+ final Comparator<Module> comparator = new Comparator<Module>() {
+ @Override
+ public int compare( final Module o1, final Module o2 ) {
+ return o1.getRevision().compareTo( o2.getRevision() );
+ }
+ };
+
+ List<Module> sorted = new ArrayList<Module>( modules );
+ Collections.<Module> sort( new ArrayList<Module>( modules ), comparator );
+
+ final Function<Module, QName> transform = new Function<Module, QName>() {
+ @Override
+ public QName apply( final Module m ) {
+ return QName.create( m.getNamespace(), m.getRevision(), m.getName() );
+ }
+ };
+
+ final Predicate<QName> findFirst = new Predicate<QName>() {
+ @Override
+ public boolean apply( final QName qn ) {
+ return Objects.equal( module, qn.getLocalName() );
+ }
+ };
+
+ Optional<QName> namespace = FluentIterable.from( sorted )
+ .transform( transform )
+ .firstMatch( findFirst );
+ return namespace.isPresent() ? QName.create( namespace.get(), node ) : null;
+ }
+
+ private boolean isListOrContainer( final DataSchemaNode node ) {
+ return node instanceof ListSchemaNode || node instanceof ContainerSchemaNode;
+ }
+
+ public RpcDefinition getRpcDefinition( final String name ) {
+ final QName validName = this.toQName( name );
+ return validName == null ? null : this.qnameToRpc.get( validName );
+ }
+
+ @Override
+ public void onGlobalContextUpdated( final SchemaContext context ) {
+ if( context != null ) {
+ this.qnameToRpc.clear();
+ this.setGlobalSchema( context );
+ Set<RpcDefinition> _operations = context.getOperations();
+ for( final RpcDefinition operation : _operations ) {
+ {
+ this.qnameToRpc.put( operation.getQName(), operation );
+ }
+ }
+ }
+ }
+
+ public List<String> urlPathArgsDecode( final List<String> strings ) {
+ try {
+ List<String> decodedPathArgs = new ArrayList<String>();
+ for( final String pathArg : strings ) {
+ String _decode = URLDecoder.decode( pathArg, URI_ENCODING_CHAR_SET );
+ decodedPathArgs.add( _decode );
+ }
+ return decodedPathArgs;
+ }
+ catch( UnsupportedEncodingException e ) {
+ throw new ResponseException( Status.BAD_REQUEST,
+ "Invalid URL path '" + strings + "': " + e.getMessage() );
+ }
+ }
+
+ public String urlPathArgDecode( final String pathArg ) {
+ if( pathArg != null ) {
+ try {
+ return URLDecoder.decode( pathArg, URI_ENCODING_CHAR_SET );
+ }
+ catch( UnsupportedEncodingException e ) {
+ throw new ResponseException( Status.BAD_REQUEST,
+ "Invalid URL path arg '" + pathArg + "': " + e.getMessage() );
+ }
+ }
+
+ return null;
+ }
+
+ private CharSequence convertToRestconfIdentifier( final PathArgument argument,
+ final DataNodeContainer node ) {
+ if( argument instanceof NodeIdentifier && node instanceof ContainerSchemaNode ) {
+ return convertToRestconfIdentifier( (NodeIdentifier) argument, (ContainerSchemaNode) node );
+ }
+ else if( argument instanceof NodeIdentifierWithPredicates && node instanceof ListSchemaNode ) {
+ return convertToRestconfIdentifier( (NodeIdentifierWithPredicates) argument, (ListSchemaNode) node );
+ }
+ else if( argument != null && node != null ) {
+ throw new IllegalArgumentException(
+ "Conversion of generic path argument is not supported" );
+ }
+ else {
+ throw new IllegalArgumentException( "Unhandled parameter types: "
+ + Arrays.<Object> asList( argument, node ).toString() );
+ }
+ }
+
+ 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();
+ }
+
+ private CharSequence convertToRestconfIdentifier( final NodeIdentifierWithPredicates argument,
+ final ListSchemaNode node ) {
+ QName nodeType = argument.getNodeType();
+ final CharSequence nodeIdentifier = this.toRestconfIdentifier( nodeType );
+ final Map<QName, Object> keyValues = argument.getKeyValues();
+
+ StringBuilder builder = new StringBuilder();
+ builder.append( "/" );
+ builder.append( nodeIdentifier );
+ builder.append( "/" );
+
+ List<QName> keyDefinition = node.getKeyDefinition();
+ boolean hasElements = false;
+ for( final QName key : keyDefinition ) {
+ if( !hasElements ) {
+ hasElements = true;
+ }
+ else {
+ builder.append( "/" );
+ }
+
+ try {
+ builder.append( this.toUriString( keyValues.get( key ) ) );
+ } catch( UnsupportedEncodingException e ) {
+ LOG.error( "Error parsing URI: " + keyValues.get( key ), e );
+ return null;
+ }
+ }
+
+ return builder.toString();
+ }
+
+ private static DataSchemaNode childByQName( final Object container, final QName name ) {
+ if( container instanceof ChoiceCaseNode ) {
+ return childByQName( (ChoiceCaseNode) container, name );
+ }
+ else if( container instanceof ChoiceNode ) {
+ return childByQName( (ChoiceNode) container, name );
+ }
+ else if( container instanceof ContainerSchemaNode ) {
+ return childByQName( (ContainerSchemaNode) container, name );
+ }
+ else if( container instanceof ListSchemaNode ) {
+ return childByQName( (ListSchemaNode) container, name );
+ }
+ else if( container instanceof DataSchemaNode ) {
+ return childByQName( (DataSchemaNode) container, name );
+ }
+ else if( container instanceof Module ) {
+ return childByQName( (Module) container, name );
+ }
+ else {
+ throw new IllegalArgumentException( "Unhandled parameter types: "
+ + Arrays.<Object> asList( container, name ).toString() );
+ }
+ }
+}
+++ /dev/null
-/*
- * Copyright (c) 2014 Cisco Systems, Inc. and others. All rights reserved.
- *
- * This program and the accompanying materials are made available under the
- * terms of the Eclipse Public License v1.0 which accompanies this distribution,
- * and is available at http://www.eclipse.org/legal/epl-v10.html
- */
-package org.opendaylight.controller.sal.restconf.impl
-
-import com.google.common.base.Preconditions
-import com.google.common.base.Splitter
-import com.google.common.collect.BiMap
-import com.google.common.collect.FluentIterable
-import com.google.common.collect.HashBiMap
-import com.google.common.collect.Lists
-import java.net.URI
-import java.net.URLDecoder
-import java.net.URLEncoder
-import java.util.ArrayList
-import java.util.HashMap
-import java.util.List
-import java.util.Map
-import java.util.concurrent.ConcurrentHashMap
-import org.opendaylight.controller.sal.core.api.mount.MountInstance
-import org.opendaylight.controller.sal.core.api.mount.MountService
-import org.opendaylight.controller.sal.rest.impl.RestUtil
-import org.opendaylight.controller.sal.rest.impl.RestconfProvider
-import org.opendaylight.yangtools.yang.common.QName
-import org.opendaylight.yangtools.yang.data.api.InstanceIdentifier
-import org.opendaylight.yangtools.yang.data.api.InstanceIdentifier.InstanceIdentifierBuilder
-import org.opendaylight.yangtools.yang.data.api.InstanceIdentifier.NodeIdentifier
-import org.opendaylight.yangtools.yang.data.api.InstanceIdentifier.NodeIdentifierWithPredicates
-import org.opendaylight.yangtools.yang.data.api.InstanceIdentifier.PathArgument
-import org.opendaylight.yangtools.yang.data.impl.codec.TypeDefinitionAwareCodec
-import org.opendaylight.yangtools.yang.model.api.ChoiceCaseNode
-import org.opendaylight.yangtools.yang.model.api.ChoiceNode
-import org.opendaylight.yangtools.yang.model.api.ContainerSchemaNode
-import org.opendaylight.yangtools.yang.model.api.DataNodeContainer
-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.Module
-import org.opendaylight.yangtools.yang.model.api.RpcDefinition
-import org.opendaylight.yangtools.yang.model.api.SchemaContext
-import org.opendaylight.yangtools.yang.model.api.SchemaContextListener
-import org.opendaylight.yangtools.yang.model.api.type.IdentityrefTypeDefinition
-import org.slf4j.LoggerFactory
-
-import static com.google.common.base.Preconditions.*
-import static javax.ws.rs.core.Response.Status.*
-
-class ControllerContext implements SchemaContextListener {
- val static LOG = LoggerFactory.getLogger(ControllerContext)
- val static ControllerContext INSTANCE = new ControllerContext
- val static NULL_VALUE = "null"
- val static MOUNT_MODULE = "yang-ext"
- val static MOUNT_NODE = "mount"
- public val static MOUNT = "yang-ext:mount"
- val static URI_ENCODING_CHAR_SET = "ISO-8859-1"
- val static URI_SLASH_PLACEHOLDER = "%2F";
-
- @Property
- var SchemaContext globalSchema;
-
- @Property
- var MountService mountService;
-
- private val BiMap<URI, String> uriToModuleName = HashBiMap.create();
- private val Map<String, URI> moduleNameToUri = uriToModuleName.inverse();
- private val Map<QName, RpcDefinition> qnameToRpc = new ConcurrentHashMap();
-
- private new() {
- if (INSTANCE !== null) {
- throw new IllegalStateException("Already instantiated");
- }
- }
-
- static def getInstance() {
- return INSTANCE
- }
-
- private def void checkPreconditions() {
- if (globalSchema === null) {
- throw new ResponseException(SERVICE_UNAVAILABLE, RestconfProvider::NOT_INITALIZED_MSG)
- }
- }
-
- def setSchemas(SchemaContext schemas) {
- onGlobalContextUpdated(schemas)
- }
-
- def InstanceIdWithSchemaNode toInstanceIdentifier(String restconfInstance) {
- return restconfInstance.toIdentifier(false)
- }
-
- def InstanceIdWithSchemaNode toMountPointIdentifier(String restconfInstance) {
- return restconfInstance.toIdentifier(true)
- }
-
- private def InstanceIdWithSchemaNode toIdentifier(String restconfInstance, boolean toMountPointIdentifier) {
- checkPreconditions
- val encodedPathArgs = Lists.newArrayList(Splitter.on("/").split(restconfInstance))
- val pathArgs = urlPathArgsDecode(encodedPathArgs)
- pathArgs.omitFirstAndLastEmptyString
- if (pathArgs.empty) {
- return null;
- }
- val startModule = pathArgs.head.toModuleName();
- if (startModule === null) {
- throw new ResponseException(BAD_REQUEST, "First node in URI has to be in format \"moduleName:nodeName\"")
- }
- var InstanceIdWithSchemaNode iiWithSchemaNode = null;
- if (toMountPointIdentifier) {
- iiWithSchemaNode = collectPathArguments(InstanceIdentifier.builder(), pathArgs,
- globalSchema.getLatestModule(startModule), null, true);
- } else {
- iiWithSchemaNode = collectPathArguments(InstanceIdentifier.builder(), pathArgs,
- globalSchema.getLatestModule(startModule), null, false);
- }
- if (iiWithSchemaNode === null) {
- throw new ResponseException(BAD_REQUEST, "URI has bad format")
- }
- return iiWithSchemaNode
- }
-
- private def omitFirstAndLastEmptyString(List<String> list) {
- if (list.empty) {
- return list;
- }
- if (list.head.empty) {
- list.remove(0)
- }
- if (list.empty) {
- return list;
- }
- if (list.last.empty) {
- list.remove(list.indexOf(list.last))
- }
- return list;
- }
-
- private def getLatestModule(SchemaContext schema, String moduleName) {
- checkArgument(schema !== null);
- checkArgument(moduleName !== null && !moduleName.empty)
- val modules = schema.modules.filter[m|m.name == moduleName]
- return modules.filterLatestModule
- }
-
- private def filterLatestModule(Iterable<Module> modules) {
- var latestModule = modules.head
- for (module : modules) {
- if (module.revision.after(latestModule.revision)) {
- latestModule = module
- }
- }
- return latestModule
- }
-
- def findModuleByName(String moduleName) {
- checkPreconditions
- checkArgument(moduleName !== null && !moduleName.empty)
- return globalSchema.getLatestModule(moduleName)
- }
-
- def findModuleByName(MountInstance mountPoint, String moduleName) {
- checkArgument(moduleName !== null && mountPoint !== null)
- val mountPointSchema = mountPoint.schemaContext;
- return mountPointSchema?.getLatestModule(moduleName);
- }
-
- def findModuleByNamespace(URI namespace) {
- checkPreconditions
- checkArgument(namespace !== null)
- val moduleSchemas = globalSchema.findModuleByNamespace(namespace)
- return moduleSchemas?.filterLatestModule
- }
-
- def findModuleByNamespace(MountInstance mountPoint, URI namespace) {
- checkArgument(namespace !== null && mountPoint !== null)
- val mountPointSchema = mountPoint.schemaContext;
- val moduleSchemas = mountPointSchema?.findModuleByNamespace(namespace)
- return moduleSchemas?.filterLatestModule
- }
-
- def findModuleByNameAndRevision(QName module) {
- checkPreconditions
- checkArgument(module !== null && module.localName !== null && module.revision !== null)
- return globalSchema.findModuleByName(module.localName, module.revision)
- }
-
- def findModuleByNameAndRevision(MountInstance mountPoint, QName module) {
- checkPreconditions
- checkArgument(module !== null && module.localName !== null && module.revision !== null && mountPoint !== null)
- return mountPoint.schemaContext?.findModuleByName(module.localName, module.revision)
- }
-
- def getDataNodeContainerFor(InstanceIdentifier path) {
- checkPreconditions
- val elements = path.path;
- val startQName = elements.head.nodeType;
- val initialModule = globalSchema.findModuleByNamespaceAndRevision(startQName.namespace, startQName.revision)
- var node = initialModule as DataNodeContainer;
- for (element : elements) {
- val potentialNode = node.childByQName(element.nodeType);
- if (potentialNode === null || !potentialNode.listOrContainer) {
- return null
- }
- node = potentialNode as DataNodeContainer
- }
- return node
- }
-
- def String toFullRestconfIdentifier(InstanceIdentifier path) {
- checkPreconditions
- val elements = path.path;
- val ret = new StringBuilder();
- val startQName = elements.head.nodeType;
- val initialModule = globalSchema.findModuleByNamespaceAndRevision(startQName.namespace, startQName.revision)
- var node = initialModule as DataNodeContainer;
- for (element : elements) {
- val potentialNode = node.childByQName(element.nodeType);
- if (!potentialNode.listOrContainer) {
- return null
- }
- node = potentialNode as DataNodeContainer
- ret.append(element.convertToRestconfIdentifier(node));
- }
- return ret.toString
- }
-
- private def dispatch CharSequence convertToRestconfIdentifier(NodeIdentifier argument, ContainerSchemaNode node) {
- '''/«argument.nodeType.toRestconfIdentifier()»'''
- }
-
- private def dispatch CharSequence convertToRestconfIdentifier(NodeIdentifierWithPredicates argument, ListSchemaNode node) {
- val nodeIdentifier = argument.nodeType.toRestconfIdentifier();
- val keyValues = argument.keyValues;
- return '''/«nodeIdentifier»/«FOR key : node.keyDefinition SEPARATOR "/"»«keyValues.get(key).toUriString»«ENDFOR»'''
- }
-
- private def dispatch CharSequence convertToRestconfIdentifier(PathArgument argument, DataNodeContainer node) {
- throw new IllegalArgumentException("Conversion of generic path argument is not supported");
- }
-
- def findModuleNameByNamespace(URI namespace) {
- checkPreconditions
- var moduleName = uriToModuleName.get(namespace)
- if (moduleName === null) {
- val module = findModuleByNamespace(namespace)
- if (module === null) return null
- moduleName = module.name
- uriToModuleName.put(namespace, moduleName)
- }
- return moduleName
- }
-
- def findModuleNameByNamespace(MountInstance mountPoint, URI namespace) {
- val module = mountPoint.findModuleByNamespace(namespace);
- return module?.name
- }
-
- def findNamespaceByModuleName(String moduleName) {
- var namespace = moduleNameToUri.get(moduleName)
- if (namespace === null) {
- var module = findModuleByName(moduleName)
- if(module === null) return null
- namespace = module.namespace
- uriToModuleName.put(namespace, moduleName)
- }
- return namespace
- }
-
- def findNamespaceByModuleName(MountInstance mountPoint, String moduleName) {
- val module = mountPoint.findModuleByName(moduleName)
- return module?.namespace
- }
-
- def getAllModules(MountInstance mountPoint) {
- checkPreconditions
- return mountPoint?.schemaContext?.modules
- }
-
- def getAllModules() {
- checkPreconditions
- return globalSchema.modules
- }
-
- def CharSequence toRestconfIdentifier(QName qname) {
- checkPreconditions
- var module = uriToModuleName.get(qname.namespace)
- if (module === null) {
- val moduleSchema = globalSchema.findModuleByNamespaceAndRevision(qname.namespace, qname.revision);
- if(moduleSchema === null) return null
- uriToModuleName.put(qname.namespace, moduleSchema.name)
- module = moduleSchema.name;
- }
- return '''«module»:«qname.localName»''';
- }
-
- def CharSequence toRestconfIdentifier(MountInstance mountPoint, QName qname) {
- val moduleSchema = mountPoint?.schemaContext.findModuleByNamespaceAndRevision(qname.namespace, qname.revision);
- if(moduleSchema === null) return null
- val module = moduleSchema.name;
- return '''«module»:«qname.localName»''';
- }
-
- private static dispatch def DataSchemaNode childByQName(ChoiceNode container, QName name) {
- for (caze : container.cases) {
- val ret = caze.childByQName(name)
- if (ret !== null) {
- return ret;
- }
- }
- return null;
- }
-
- private static dispatch def DataSchemaNode childByQName(ChoiceCaseNode container, QName name) {
- val ret = container.getDataChildByName(name);
- return ret;
- }
-
- private static dispatch def DataSchemaNode childByQName(ContainerSchemaNode container, QName name) {
- return container.dataNodeChildByQName(name);
- }
-
- private static dispatch def DataSchemaNode childByQName(ListSchemaNode container, QName name) {
- return container.dataNodeChildByQName(name);
- }
-
- private static dispatch def DataSchemaNode childByQName(Module container, QName name) {
- return container.dataNodeChildByQName(name);
- }
-
- private static dispatch def DataSchemaNode childByQName(DataSchemaNode container, QName name) {
- return null;
- }
-
- private static def DataSchemaNode dataNodeChildByQName(DataNodeContainer container, QName name) {
- var ret = container.getDataChildByName(name);
- if (ret === null) {
-
- // Find in Choice Cases
- for (node : container.childNodes) {
- if (node instanceof ChoiceCaseNode) {
- val caseNode = (node as ChoiceCaseNode);
- ret = caseNode.childByQName(name);
- if (ret !== null) {
- return ret;
- }
- }
- }
- }
- return ret;
- }
-
- private def toUriString(Object object) {
- if(object === null) return "";
- return URLEncoder.encode(object.toString,URI_ENCODING_CHAR_SET)
- }
-
- private def InstanceIdWithSchemaNode collectPathArguments(InstanceIdentifierBuilder builder, List<String> strings,
- DataNodeContainer parentNode, MountInstance mountPoint, boolean returnJustMountPoint) {
- checkNotNull(strings)
- if (parentNode === null) {
- return null;
- }
- if (strings.empty) {
- return new InstanceIdWithSchemaNode(builder.toInstance, parentNode as DataSchemaNode, mountPoint)
- }
-
- val nodeName = strings.head.toNodeName
- val moduleName = strings.head.toModuleName
- var DataSchemaNode targetNode = null
- if (!moduleName.nullOrEmpty) {
- // if it is mount point
- if (moduleName == MOUNT_MODULE && nodeName == MOUNT_NODE) {
- if (mountPoint !== null) {
- throw new ResponseException(BAD_REQUEST, "Restconf supports just one mount point in URI.")
- }
-
- if (mountService === null) {
- throw new ResponseException(SERVICE_UNAVAILABLE, "MountService was not found. "
- + "Finding behind mount points does not work."
- )
- }
-
- val partialPath = builder.toInstance;
- val mount = mountService.getMountPoint(partialPath)
- if (mount === null) {
- LOG.debug("Instance identifier to missing mount point: {}", partialPath)
- throw new ResponseException(BAD_REQUEST, "Mount point does not exist.")
- }
-
- val mountPointSchema = mount.schemaContext;
- if (mountPointSchema === null) {
- throw new ResponseException(BAD_REQUEST, "Mount point does not contain any schema with modules.")
- }
-
- if (returnJustMountPoint) {
- return new InstanceIdWithSchemaNode(InstanceIdentifier.builder().toInstance, mountPointSchema, mount)
- }
-
- if (strings.size == 1) { // any data node is not behind mount point
- return new InstanceIdWithSchemaNode(InstanceIdentifier.builder().toInstance, mountPointSchema, mount)
- }
-
- val moduleNameBehindMountPoint = strings.get(1).toModuleName()
- if (moduleNameBehindMountPoint === null) {
- throw new ResponseException(BAD_REQUEST,
- "First node after mount point in URI has to be in format \"moduleName:nodeName\"")
- }
-
- val moduleBehindMountPoint = mountPointSchema.getLatestModule(moduleNameBehindMountPoint)
- if (moduleBehindMountPoint === null) {
- throw new ResponseException(BAD_REQUEST,
- "URI has bad format. \"" + moduleName + "\" module does not exist in mount point.")
- }
-
- return collectPathArguments(InstanceIdentifier.builder(), strings.subList(1, strings.size),
- moduleBehindMountPoint, mount, returnJustMountPoint);
- }
-
- var Module module = null;
- if (mountPoint === null) {
- module = globalSchema.getLatestModule(moduleName)
- if (module === null) {
- throw new ResponseException(BAD_REQUEST,
- "URI has bad format. \"" + moduleName + "\" module does not exist.")
- }
- } else {
- module = mountPoint.schemaContext?.getLatestModule(moduleName)
- if (module === null) {
- throw new ResponseException(BAD_REQUEST,
- "URI has bad format. \"" + moduleName + "\" module does not exist in mount point.")
- }
- }
- targetNode = parentNode.findInstanceDataChildByNameAndNamespace(nodeName, module.namespace)
- if (targetNode === null) {
- throw new ResponseException(BAD_REQUEST, "URI has bad format. Possible reasons:\n" +
- "1. \"" + strings.head + "\" was not found in parent data node.\n" +
- "2. \"" + strings.head + "\" is behind mount point. Then it should be in format \"/" + MOUNT + "/" + strings.head + "\".")
- }
- } else { // string without module name
- val potentialSchemaNodes = parentNode.findInstanceDataChildrenByName(nodeName)
- if (potentialSchemaNodes.size > 1) {
- val StringBuilder namespacesOfPotentialModules = new StringBuilder;
- for (potentialNodeSchema : potentialSchemaNodes) {
- namespacesOfPotentialModules.append(" ").append(potentialNodeSchema.QName.namespace.toString).append("\n")
- }
- throw new ResponseException(BAD_REQUEST, "URI has bad format. Node \"" + nodeName + "\" is added as augment from more than one module. "
- + "Therefore the node must have module name and it has to be in format \"moduleName:nodeName\"."
- + "\nThe node is added as augment from modules with namespaces:\n" + namespacesOfPotentialModules)
- }
- targetNode = potentialSchemaNodes.head
- if (targetNode === null) {
- throw new ResponseException(BAD_REQUEST, "URI has bad format. \"" + nodeName + "\" was not found in parent data node.\n")
- }
- }
-
- if (!targetNode.isListOrContainer) {
- throw new ResponseException(BAD_REQUEST,"URI has bad format. Node \"" + strings.head + "\" must be Container or List yang type.")
- }
- // Number of consumed elements
- var consumed = 1;
- if (targetNode instanceof ListSchemaNode) {
- val listNode = targetNode as ListSchemaNode;
- val keysSize = listNode.keyDefinition.size
-
- // every key has to be filled
- if ((strings.length - consumed) < keysSize) {
- throw new ResponseException(BAD_REQUEST,"Missing key for list \"" + listNode.QName.localName + "\".")
- }
- val uriKeyValues = strings.subList(consumed, consumed + keysSize);
- val keyValues = new HashMap<QName, Object>();
- var i = 0;
- for (key : listNode.keyDefinition) {
- val uriKeyValue = uriKeyValues.get(i);
-
- // key value cannot be NULL
- if (uriKeyValue.equals(NULL_VALUE)) {
- throw new ResponseException(BAD_REQUEST, "URI has bad format. List \"" + listNode.QName.localName
- + "\" cannot contain \"null\" value as a key."
- )
- }
- keyValues.addKeyValue(listNode.getDataChildByName(key), uriKeyValue, mountPoint);
- i = i + 1;
- }
- consumed = consumed + i;
- builder.nodeWithKey(targetNode.QName, keyValues);
- } else {
-
- // Only one instance of node is allowed
- builder.node(targetNode.QName);
- }
- if (targetNode instanceof DataNodeContainer) {
- val remaining = strings.subList(consumed, strings.length);
- val result = builder.collectPathArguments(remaining, targetNode as DataNodeContainer, mountPoint, returnJustMountPoint);
- return result
- }
-
- return new InstanceIdWithSchemaNode(builder.toInstance, targetNode, mountPoint)
- }
-
- def DataSchemaNode findInstanceDataChildByNameAndNamespace(DataNodeContainer container,
- String name, URI namespace) {
- Preconditions.checkNotNull(namespace)
- val potentialSchemaNodes = container.findInstanceDataChildrenByName(name)
- return potentialSchemaNodes.filter[n|n.QName.namespace == namespace].head
- }
-
- def List<DataSchemaNode> findInstanceDataChildrenByName(DataNodeContainer container, String name) {
- Preconditions.checkNotNull(container)
- Preconditions.checkNotNull(name)
- val instantiatedDataNodeContainers = new ArrayList
- instantiatedDataNodeContainers.collectInstanceDataNodeContainers(container, name)
- return instantiatedDataNodeContainers
- }
-
- private def void collectInstanceDataNodeContainers(List<DataSchemaNode> potentialSchemaNodes, DataNodeContainer container,
- String name) {
- val nodes = container.childNodes.filter[n|n.QName.localName == name]
- for (potentialNode : nodes) {
- if (potentialNode.isInstantiatedDataSchema) {
- potentialSchemaNodes.add(potentialNode)
- }
- }
- val allCases = container.childNodes.filter(ChoiceNode).map[cases].flatten
- for (caze : allCases) {
- collectInstanceDataNodeContainers(potentialSchemaNodes, caze, name)
- }
- }
-
- def boolean isInstantiatedDataSchema(DataSchemaNode node) {
- switch node {
- LeafSchemaNode: return true
- LeafListSchemaNode: return true
- ContainerSchemaNode: return true
- ListSchemaNode: return true
- default: return false
- }
- }
-
- private def void addKeyValue(HashMap<QName, Object> map, DataSchemaNode node, String uriValue, MountInstance mountPoint) {
- checkNotNull(uriValue);
- checkArgument(node instanceof LeafSchemaNode);
- val urlDecoded = URLDecoder.decode(uriValue);
- val typedef = (node as LeafSchemaNode).type;
-
- var decoded = RestCodec.from(typedef, mountPoint)?.deserialize(urlDecoded)
- var additionalInfo = ""
- if(decoded === null) {
- var baseType = RestUtil.resolveBaseTypeFrom(typedef)
- if(baseType instanceof IdentityrefTypeDefinition) {
- decoded = toQName(urlDecoded)
- additionalInfo = "For key which is of type identityref it should be in format module_name:identity_name."
- }
- }
- if (decoded === null) {
- throw new ResponseException(BAD_REQUEST, uriValue + " from URI can't be resolved. "+ additionalInfo )
- }
-
- map.put(node.QName, decoded);
- }
-
- private static def String toModuleName(String str) {
- checkNotNull(str)
- if (str.contains(":")) {
- val args = str.split(":");
- if (args.size === 2) {
- return args.get(0);
- }
- }
- return null;
- }
-
- private def String toNodeName(String str) {
- if (str.contains(":")) {
- val args = str.split(":");
- if (args.size === 2) {
- return args.get(1);
- }
- }
- return str;
- }
-
- private def QName toQName(String name) {
- val module = name.toModuleName;
- val node = name.toNodeName;
- val namespace = FluentIterable.from(globalSchema.modules.sort[o1,o2 | o1.revision.compareTo(o2.revision)])
- .transform[QName.create(namespace,revision,it.name)].findFirst[module == localName]
- if (namespace === null) {
- return null
- }
- return QName.create(namespace, node);
- }
-
- private def boolean isListOrContainer(DataSchemaNode node) {
- return ((node instanceof ListSchemaNode) || (node instanceof ContainerSchemaNode))
- }
-
- def getRpcDefinition(String name) {
- val validName = name.toQName
- if (validName === null) {
- return null
- }
- return qnameToRpc.get(validName)
- }
-
- override onGlobalContextUpdated(SchemaContext context) {
- if (context !== null) {
- qnameToRpc.clear
- this.globalSchema = context;
- for (operation : context.operations) {
- val qname = operation.QName;
- qnameToRpc.put(qname, operation);
- }
- }
- }
-
-
- def urlPathArgsDecode(List<String> strings) {
- val List<String> decodedPathArgs = new ArrayList();
- for (pathArg : strings) {
- decodedPathArgs.add(URLDecoder.decode(pathArg, URI_ENCODING_CHAR_SET))
- }
- return decodedPathArgs
- }
-
- def urlPathArgDecode(String pathArg) {
- if (pathArg !== null) {
- return URLDecoder.decode(pathArg, URI_ENCODING_CHAR_SET)
- }
- return null
- }
-
-}
public ResponseException(Status status, String msg) {
super(Response.status(status).type(MediaType.TEXT_PLAIN_TYPE).entity(msg).build());
}
+
+ public ResponseException(Throwable cause, String msg) {
+ super(cause, Response.status(Status.INTERNAL_SERVER_ERROR).
+ type(MediaType.TEXT_PLAIN_TYPE).entity(msg).build());
+ }
}
--- /dev/null
+/**
+ * Copyright (c) 2014 Cisco Systems, Inc. and others. All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+package org.opendaylight.controller.sal.restconf.impl;
+
+import java.net.URI;
+import java.text.ParseException;
+import java.text.SimpleDateFormat;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Date;
+import java.util.HashMap;
+import java.util.List;
+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.opendaylight.controller.md.sal.common.api.TransactionStatus;
+import org.opendaylight.controller.sal.core.api.mount.MountInstance;
+import org.opendaylight.controller.sal.rest.api.RestconfService;
+import org.opendaylight.controller.sal.streams.listeners.ListenerAdapter;
+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.RpcResult;
+import org.opendaylight.yangtools.yang.data.api.CompositeNode;
+import org.opendaylight.yangtools.yang.data.api.InstanceIdentifier;
+import org.opendaylight.yangtools.yang.data.api.InstanceIdentifier.InstanceIdentifierBuilder;
+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.impl.NodeFactory;
+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.FeatureDefinition;
+import org.opendaylight.yangtools.yang.model.api.GroupingDefinition;
+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.Module;
+import org.opendaylight.yangtools.yang.model.api.RpcDefinition;
+import org.opendaylight.yangtools.yang.model.api.SchemaContext;
+import org.opendaylight.yangtools.yang.model.api.SchemaPath;
+import org.opendaylight.yangtools.yang.model.api.TypeDefinition;
+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 com.google.common.base.Objects;
+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.Iterables;
+import com.google.common.collect.Lists;
+
+@SuppressWarnings("all")
+public class RestconfImpl implements RestconfService {
+ private final static RestconfImpl INSTANCE = new RestconfImpl();
+
+ private final static String MOUNT_POINT_MODULE_NAME = "ietf-netconf";
+
+ private final static SimpleDateFormat REVISION_FORMAT = new SimpleDateFormat("yyyy-MM-dd");
+
+ private final static String RESTCONF_MODULE_DRAFT02_REVISION = "2013-10-19";
+
+ private final static String RESTCONF_MODULE_DRAFT02_NAME = "ietf-restconf";
+
+ private final static String RESTCONF_MODULE_DRAFT02_NAMESPACE = "urn:ietf:params:xml:ns:yang:ietf-restconf";
+
+ private final static String RESTCONF_MODULE_DRAFT02_RESTCONF_GROUPING_SCHEMA_NODE = "restconf";
+
+ private final static String RESTCONF_MODULE_DRAFT02_RESTCONF_CONTAINER_SCHEMA_NODE = "restconf";
+
+ private final static String RESTCONF_MODULE_DRAFT02_MODULES_CONTAINER_SCHEMA_NODE = "modules";
+
+ private final static String RESTCONF_MODULE_DRAFT02_MODULE_LIST_SCHEMA_NODE = "module";
+
+ private final static String RESTCONF_MODULE_DRAFT02_STREAMS_CONTAINER_SCHEMA_NODE = "streams";
+
+ private final static String RESTCONF_MODULE_DRAFT02_STREAM_LIST_SCHEMA_NODE = "stream";
+
+ private final static String RESTCONF_MODULE_DRAFT02_OPERATIONS_CONTAINER_SCHEMA_NODE = "operations";
+
+ private final static String SAL_REMOTE_NAMESPACE = "urn:opendaylight:params:xml:ns:yang:controller:md:sal:remote";
+
+ private final static String SAL_REMOTE_RPC_SUBSRCIBE = "create-data-change-event-subscription";
+
+ private BrokerFacade broker;
+
+ private ControllerContext controllerContext;
+
+ public void setBroker(final BrokerFacade broker) {
+ this.broker = broker;
+ }
+
+ public void setControllerContext(final ControllerContext controllerContext) {
+ this.controllerContext = controllerContext;
+ }
+
+ private RestconfImpl() {
+ }
+
+ public static RestconfImpl getInstance() {
+ return INSTANCE;
+ }
+
+ @Override
+ public StructuredData getModules() {
+ final Module restconfModule = this.getRestconfModule();
+
+ final List<Node<?>> modulesAsData = new ArrayList<Node<?>>();
+ final DataSchemaNode moduleSchemaNode =
+ this.getSchemaNode(restconfModule, RESTCONF_MODULE_DRAFT02_MODULE_LIST_SCHEMA_NODE);
+
+ Set<Module> allModules = this.controllerContext.getAllModules();
+ for (final Module module : allModules) {
+ CompositeNode moduleCompositeNode = this.toModuleCompositeNode(module, moduleSchemaNode);
+ modulesAsData.add(moduleCompositeNode);
+ }
+
+ final DataSchemaNode modulesSchemaNode =
+ this.getSchemaNode(restconfModule, RESTCONF_MODULE_DRAFT02_MODULES_CONTAINER_SCHEMA_NODE);
+ QName qName = modulesSchemaNode.getQName();
+ final CompositeNode modulesNode = NodeFactory.createImmutableCompositeNode(qName, null, modulesAsData);
+ return new StructuredData(modulesNode, modulesSchemaNode, null);
+ }
+
+ @Override
+ public StructuredData getAvailableStreams() {
+ Set<String> availableStreams = Notificator.getStreamNames();
+
+ final List<Node<?>> streamsAsData = new ArrayList<Node<?>>();
+ Module restconfModule = this.getRestconfModule();
+ final DataSchemaNode streamSchemaNode =
+ this.getSchemaNode(restconfModule, RESTCONF_MODULE_DRAFT02_STREAM_LIST_SCHEMA_NODE);
+ for (final String streamName : availableStreams) {
+ streamsAsData.add(this.toStreamCompositeNode(streamName, streamSchemaNode));
+ }
+
+ final DataSchemaNode streamsSchemaNode =
+ this.getSchemaNode(restconfModule, RESTCONF_MODULE_DRAFT02_STREAMS_CONTAINER_SCHEMA_NODE);
+ QName qName = streamsSchemaNode.getQName();
+ final CompositeNode streamsNode = NodeFactory.createImmutableCompositeNode(qName, null, streamsAsData);
+ return new StructuredData(streamsNode, streamsSchemaNode, null);
+ }
+
+ @Override
+ public StructuredData getModules(final String identifier) {
+ Set<Module> modules = null;
+ MountInstance mountPoint = null;
+ if (identifier.contains(ControllerContext.MOUNT)) {
+ InstanceIdWithSchemaNode mountPointIdentifier =
+ this.controllerContext.toMountPointIdentifier(identifier);
+ mountPoint = mountPointIdentifier.getMountPoint();
+ modules = this.controllerContext.getAllModules(mountPoint);
+ }
+ else {
+ throw new ResponseException(Status.BAD_REQUEST,
+ "URI has bad format. If modules behind mount point should be showed, URI has to end with " +
+ ControllerContext.MOUNT);
+ }
+
+ final List<Node<?>> modulesAsData = new ArrayList<Node<?>>();
+ Module restconfModule = this.getRestconfModule();
+ final DataSchemaNode moduleSchemaNode =
+ this.getSchemaNode(restconfModule, RESTCONF_MODULE_DRAFT02_MODULE_LIST_SCHEMA_NODE);
+
+ for (final Module module : modules) {
+ modulesAsData.add(this.toModuleCompositeNode(module, moduleSchemaNode));
+ }
+
+ final DataSchemaNode modulesSchemaNode =
+ this.getSchemaNode(restconfModule, RESTCONF_MODULE_DRAFT02_MODULES_CONTAINER_SCHEMA_NODE);
+ QName qName = modulesSchemaNode.getQName();
+ final CompositeNode modulesNode = NodeFactory.createImmutableCompositeNode(qName, null, modulesAsData);
+ return new StructuredData(modulesNode, modulesSchemaNode, mountPoint);
+ }
+
+ @Override
+ public StructuredData getModule(final String identifier) {
+ final QName moduleNameAndRevision = this.getModuleNameAndRevision(identifier);
+ Module module = null;
+ MountInstance mountPoint = null;
+ if (identifier.contains(ControllerContext.MOUNT)) {
+ InstanceIdWithSchemaNode mountPointIdentifier =
+ this.controllerContext.toMountPointIdentifier(identifier);
+ mountPoint = mountPointIdentifier.getMountPoint();
+ module = this.controllerContext.findModuleByNameAndRevision(mountPoint, moduleNameAndRevision);
+ }
+ else {
+ module = this.controllerContext.findModuleByNameAndRevision(moduleNameAndRevision);
+ }
+
+ if (module == null) {
+ throw new ResponseException(Status.BAD_REQUEST,
+ "Module with name '" + moduleNameAndRevision.getLocalName() + "' and revision '" +
+ moduleNameAndRevision.getRevision() + "' was not found.");
+ }
+
+ Module restconfModule = this.getRestconfModule();
+ final DataSchemaNode moduleSchemaNode =
+ this.getSchemaNode(restconfModule, RESTCONF_MODULE_DRAFT02_MODULE_LIST_SCHEMA_NODE);
+ final CompositeNode moduleNode = this.toModuleCompositeNode(module, moduleSchemaNode);
+ return new StructuredData(moduleNode, moduleSchemaNode, mountPoint);
+ }
+
+ @Override
+ public StructuredData getOperations() {
+ Set<Module> allModules = this.controllerContext.getAllModules();
+ return this.operationsFromModulesToStructuredData(allModules, null);
+ }
+
+ @Override
+ public StructuredData getOperations(final String identifier) {
+ Set<Module> modules = null;
+ MountInstance mountPoint = null;
+ if (identifier.contains(ControllerContext.MOUNT)) {
+ InstanceIdWithSchemaNode mountPointIdentifier =
+ this.controllerContext.toMountPointIdentifier(identifier);
+ mountPoint = mountPointIdentifier.getMountPoint();
+ modules = this.controllerContext.getAllModules(mountPoint);
+ }
+ else {
+ throw new ResponseException(Status.BAD_REQUEST,
+ "URI has bad format. If operations behind mount point should be showed, URI has to end with " +
+ ControllerContext.MOUNT);
+ }
+
+ return this.operationsFromModulesToStructuredData(modules, mountPoint);
+ }
+
+ private StructuredData operationsFromModulesToStructuredData(final Set<Module> modules,
+ final MountInstance mountPoint) {
+ final List<Node<?>> operationsAsData = new ArrayList<Node<?>>();
+ Module restconfModule = this.getRestconfModule();
+ final DataSchemaNode operationsSchemaNode =
+ this.getSchemaNode(restconfModule, RESTCONF_MODULE_DRAFT02_OPERATIONS_CONTAINER_SCHEMA_NODE);
+ QName qName = operationsSchemaNode.getQName();
+ SchemaPath path = operationsSchemaNode.getPath();
+ ContainerSchemaNodeBuilder containerSchemaNodeBuilder =
+ new ContainerSchemaNodeBuilder(RESTCONF_MODULE_DRAFT02_NAME, 0, qName, path);
+ final ContainerSchemaNodeBuilder fakeOperationsSchemaNode = containerSchemaNodeBuilder;
+ for (final Module module : modules) {
+ Set<RpcDefinition> rpcs = module.getRpcs();
+ for (final RpcDefinition rpc : rpcs) {
+ QName rpcQName = rpc.getQName();
+ SimpleNode<Object> immutableSimpleNode =
+ NodeFactory.<Object>createImmutableSimpleNode(rpcQName, null, null);
+ operationsAsData.add(immutableSimpleNode);
+
+ String name = module.getName();
+ LeafSchemaNodeBuilder leafSchemaNodeBuilder = new LeafSchemaNodeBuilder(name, 0, rpcQName, null);
+ final LeafSchemaNodeBuilder fakeRpcSchemaNode = leafSchemaNodeBuilder;
+ fakeRpcSchemaNode.setAugmenting(true);
+
+ EmptyType instance = EmptyType.getInstance();
+ fakeRpcSchemaNode.setType(instance);
+ fakeOperationsSchemaNode.addChildNode(fakeRpcSchemaNode.build());
+ }
+ }
+
+ final CompositeNode operationsNode =
+ NodeFactory.createImmutableCompositeNode(qName, null, operationsAsData);
+ ContainerSchemaNode schemaNode = fakeOperationsSchemaNode.build();
+ return new StructuredData(operationsNode, schemaNode, mountPoint);
+ }
+
+ private Module getRestconfModule() {
+ QName qName = QName.create(RESTCONF_MODULE_DRAFT02_NAMESPACE, RESTCONF_MODULE_DRAFT02_REVISION,
+ RESTCONF_MODULE_DRAFT02_NAME);
+ final Module restconfModule = this.controllerContext.findModuleByNameAndRevision(qName);
+ if (restconfModule == null) {
+ throw new ResponseException(Status.INTERNAL_SERVER_ERROR, "Restconf module was not found.");
+ }
+
+ return restconfModule;
+ }
+
+ private QName getModuleNameAndRevision(final String identifier) {
+ final int mountIndex = identifier.indexOf(ControllerContext.MOUNT);
+ String moduleNameAndRevision = "";
+ if (mountIndex >= 0) {
+ moduleNameAndRevision = identifier.substring(mountIndex + ControllerContext.MOUNT.length());
+ }
+ else {
+ moduleNameAndRevision = identifier;
+ }
+
+ Splitter splitter = Splitter.on("/").omitEmptyStrings();
+ Iterable<String> split = splitter.split(moduleNameAndRevision);
+ final List<String> pathArgs = Lists.<String>newArrayList(split);
+ if (pathArgs.size() < 2) {
+ throw new ResponseException(Status.BAD_REQUEST,
+ "URI has bad format. End of URI should be in format \'moduleName/yyyy-MM-dd\'");
+ }
+
+ try {
+ final String moduleName = pathArgs.get( 0 );
+ String revision = pathArgs.get(1);
+ final Date moduleRevision = REVISION_FORMAT.parse(revision);
+ return QName.create(null, moduleRevision, moduleName);
+ }
+ catch (ParseException e) {
+ throw new ResponseException(Status.BAD_REQUEST, "URI has bad format. It should be \'moduleName/yyyy-MM-dd\'");
+ }
+ }
+
+ private CompositeNode toStreamCompositeNode(final String streamName, final DataSchemaNode streamSchemaNode) {
+ final List<Node<?>> streamNodeValues = new ArrayList<Node<?>>();
+ List<DataSchemaNode> instanceDataChildrenByName =
+ this.controllerContext.findInstanceDataChildrenByName(((DataNodeContainer) streamSchemaNode),
+ "name");
+ final DataSchemaNode nameSchemaNode = Iterables.getFirst(instanceDataChildrenByName, null);
+ streamNodeValues.add(NodeFactory.<String>createImmutableSimpleNode(nameSchemaNode.getQName(), null,
+ streamName));
+
+ instanceDataChildrenByName = this.controllerContext.findInstanceDataChildrenByName(
+ ((DataNodeContainer) streamSchemaNode), "description");
+ final DataSchemaNode descriptionSchemaNode = Iterables.getFirst(instanceDataChildrenByName, null);
+ streamNodeValues.add(NodeFactory.<String>createImmutableSimpleNode(descriptionSchemaNode.getQName(), null,
+ "DESCRIPTION_PLACEHOLDER"));
+
+ instanceDataChildrenByName = this.controllerContext.findInstanceDataChildrenByName(
+ ((DataNodeContainer) streamSchemaNode), "replay-support");
+ final DataSchemaNode replaySupportSchemaNode = Iterables.getFirst(instanceDataChildrenByName, null);
+ streamNodeValues.add(NodeFactory.<Boolean>createImmutableSimpleNode(replaySupportSchemaNode.getQName(), null,
+ Boolean.valueOf(true)));
+
+ instanceDataChildrenByName = this.controllerContext.findInstanceDataChildrenByName(
+ ((DataNodeContainer) streamSchemaNode), "replay-log-creation-time");
+ final DataSchemaNode replayLogCreationTimeSchemaNode = Iterables.getFirst(instanceDataChildrenByName, null);
+ streamNodeValues.add(NodeFactory.<String>createImmutableSimpleNode(replayLogCreationTimeSchemaNode.getQName(),
+ null, ""));
+
+ instanceDataChildrenByName = this.controllerContext.findInstanceDataChildrenByName(
+ ((DataNodeContainer) streamSchemaNode), "events");
+ final DataSchemaNode eventsSchemaNode = Iterables.getFirst(instanceDataChildrenByName, null);
+ streamNodeValues.add(NodeFactory.<String>createImmutableSimpleNode(eventsSchemaNode.getQName(),
+ null, ""));
+
+ return NodeFactory.createImmutableCompositeNode(streamSchemaNode.getQName(), null, streamNodeValues);
+ }
+
+ private CompositeNode toModuleCompositeNode(final Module module, final DataSchemaNode moduleSchemaNode) {
+ final List<Node<?>> moduleNodeValues = new ArrayList<Node<?>>();
+ List<DataSchemaNode> instanceDataChildrenByName =
+ this.controllerContext.findInstanceDataChildrenByName(((DataNodeContainer) moduleSchemaNode), "name");
+ final DataSchemaNode nameSchemaNode = Iterables.getFirst(instanceDataChildrenByName, null);
+ moduleNodeValues.add(NodeFactory.<String>createImmutableSimpleNode(nameSchemaNode.getQName(),
+ null, module.getName()));
+
+ instanceDataChildrenByName = this.controllerContext.findInstanceDataChildrenByName(
+ ((DataNodeContainer) moduleSchemaNode), "revision");
+ final DataSchemaNode revisionSchemaNode = Iterables.getFirst(instanceDataChildrenByName, null);
+ Date _revision = module.getRevision();
+ moduleNodeValues.add(NodeFactory.<String>createImmutableSimpleNode(revisionSchemaNode.getQName(), null,
+ REVISION_FORMAT.format(_revision)));
+
+ instanceDataChildrenByName = this.controllerContext.findInstanceDataChildrenByName(
+ ((DataNodeContainer) moduleSchemaNode), "namespace");
+ final DataSchemaNode namespaceSchemaNode = Iterables.getFirst(instanceDataChildrenByName, null);
+ moduleNodeValues.add(NodeFactory.<String>createImmutableSimpleNode(namespaceSchemaNode.getQName(), null,
+ module.getNamespace().toString()));
+
+ instanceDataChildrenByName = this.controllerContext.findInstanceDataChildrenByName(
+ ((DataNodeContainer) moduleSchemaNode), "feature");
+ final DataSchemaNode featureSchemaNode = Iterables.getFirst(instanceDataChildrenByName, null);
+ for (final FeatureDefinition feature : module.getFeatures()) {
+ moduleNodeValues.add(NodeFactory.<String>createImmutableSimpleNode(featureSchemaNode.getQName(), null,
+ feature.getQName().getLocalName()));
+ }
+
+ return NodeFactory.createImmutableCompositeNode(moduleSchemaNode.getQName(), null, moduleNodeValues);
+ }
+
+ private DataSchemaNode getSchemaNode(final Module restconfModule, final String schemaNodeName) {
+ Set<GroupingDefinition> groupings = restconfModule.getGroupings();
+
+ final Predicate<GroupingDefinition> filter = new Predicate<GroupingDefinition>() {
+ @Override
+ public boolean apply(final GroupingDefinition g) {
+ return Objects.equal(g.getQName().getLocalName(),
+ RESTCONF_MODULE_DRAFT02_RESTCONF_GROUPING_SCHEMA_NODE);
+ }
+ };
+
+ Iterable<GroupingDefinition> filteredGroups = Iterables.filter(groupings, filter);
+
+ final GroupingDefinition restconfGrouping = Iterables.getFirst(filteredGroups, null);
+
+ List<DataSchemaNode> instanceDataChildrenByName =
+ this.controllerContext.findInstanceDataChildrenByName(restconfGrouping,
+ RESTCONF_MODULE_DRAFT02_RESTCONF_CONTAINER_SCHEMA_NODE);
+ final DataSchemaNode restconfContainer = Iterables.getFirst(instanceDataChildrenByName, null);
+
+ if (Objects.equal(schemaNodeName, RESTCONF_MODULE_DRAFT02_OPERATIONS_CONTAINER_SCHEMA_NODE)) {
+ List<DataSchemaNode> instances =
+ this.controllerContext.findInstanceDataChildrenByName(((DataNodeContainer) restconfContainer),
+ RESTCONF_MODULE_DRAFT02_OPERATIONS_CONTAINER_SCHEMA_NODE);
+ return Iterables.getFirst(instances, null);
+ }
+ else if(Objects.equal(schemaNodeName, RESTCONF_MODULE_DRAFT02_STREAMS_CONTAINER_SCHEMA_NODE)) {
+ List<DataSchemaNode> instances =
+ this.controllerContext.findInstanceDataChildrenByName(((DataNodeContainer) restconfContainer),
+ RESTCONF_MODULE_DRAFT02_STREAMS_CONTAINER_SCHEMA_NODE);
+ return Iterables.getFirst(instances, null);
+ }
+ else if(Objects.equal(schemaNodeName, RESTCONF_MODULE_DRAFT02_STREAM_LIST_SCHEMA_NODE)) {
+ List<DataSchemaNode> instances =
+ this.controllerContext.findInstanceDataChildrenByName(((DataNodeContainer) restconfContainer),
+ RESTCONF_MODULE_DRAFT02_STREAMS_CONTAINER_SCHEMA_NODE);
+ final DataSchemaNode modules = Iterables.getFirst(instances, null);
+ instances = this.controllerContext.findInstanceDataChildrenByName(((DataNodeContainer) modules),
+ RESTCONF_MODULE_DRAFT02_STREAM_LIST_SCHEMA_NODE);
+ return Iterables.getFirst(instances, null);
+ }
+ else if(Objects.equal(schemaNodeName, RESTCONF_MODULE_DRAFT02_MODULES_CONTAINER_SCHEMA_NODE)) {
+ List<DataSchemaNode> instances =
+ this.controllerContext.findInstanceDataChildrenByName(((DataNodeContainer) restconfContainer),
+ RESTCONF_MODULE_DRAFT02_MODULES_CONTAINER_SCHEMA_NODE);
+ return Iterables.getFirst(instances, null);
+ }
+ else if(Objects.equal(schemaNodeName, RESTCONF_MODULE_DRAFT02_MODULE_LIST_SCHEMA_NODE)) {
+ List<DataSchemaNode> instances =
+ this.controllerContext.findInstanceDataChildrenByName(((DataNodeContainer) restconfContainer),
+ RESTCONF_MODULE_DRAFT02_MODULES_CONTAINER_SCHEMA_NODE);
+ final DataSchemaNode modules = Iterables.getFirst(instances, null);
+ instances = this.controllerContext.findInstanceDataChildrenByName(((DataNodeContainer) modules),
+ RESTCONF_MODULE_DRAFT02_MODULE_LIST_SCHEMA_NODE);
+ return Iterables.getFirst(instances, null);
+ }
+
+ return null;
+ }
+
+ @Override
+ public Object getRoot() {
+ return null;
+ }
+
+ @Override
+ public StructuredData invokeRpc(final String identifier, final CompositeNode payload) {
+ final RpcDefinition rpc = this.resolveIdentifierInInvokeRpc(identifier);
+ if (Objects.equal(rpc.getQName().getNamespace().toString(), SAL_REMOTE_NAMESPACE) &&
+ Objects.equal(rpc.getQName().getLocalName(), SAL_REMOTE_RPC_SUBSRCIBE)) {
+
+ final CompositeNode value = this.normalizeNode(payload, rpc.getInput(), null);
+ final SimpleNode<? extends Object> pathNode = value == null ? null :
+ value.getFirstSimpleByName( QName.create(rpc.getQName(), "path") );
+ final Object pathValue = pathNode == null ? null : pathNode.getValue();
+
+ if (!(pathValue instanceof InstanceIdentifier)) {
+ throw new ResponseException(Status.INTERNAL_SERVER_ERROR,
+ "Instance identifier was not normalized correctly.");
+ }
+
+ final InstanceIdentifier pathIdentifier = ((InstanceIdentifier) pathValue);
+ String streamName = null;
+ if (!Iterables.isEmpty(pathIdentifier.getPath())) {
+ String fullRestconfIdentifier = this.controllerContext.toFullRestconfIdentifier(pathIdentifier);
+ streamName = Notificator.createStreamNameFromUri(fullRestconfIdentifier);
+ }
+
+ if (Strings.isNullOrEmpty(streamName)) {
+ throw new ResponseException(Status.BAD_REQUEST,
+ "Path is empty or contains data node which is not Container or List build-in type.");
+ }
+
+ final SimpleNode<String> streamNameNode = NodeFactory.<String>createImmutableSimpleNode(
+ QName.create(rpc.getOutput().getQName(), "stream-name"), null, streamName);
+ final List<Node<?>> output = new ArrayList<Node<?>>();
+ output.add(streamNameNode);
+
+ final MutableCompositeNode responseData = NodeFactory.createMutableCompositeNode(
+ rpc.getOutput().getQName(), null, output, null, null);
+
+ if (!Notificator.existListenerFor(pathIdentifier)) {
+ Notificator.createListener(pathIdentifier, streamName);
+ }
+
+ return new StructuredData(responseData, rpc.getOutput(), null);
+ }
+
+ RpcDefinition rpcDefinition = this.controllerContext.getRpcDefinition(identifier);
+ return this.callRpc(rpcDefinition, payload);
+ }
+
+ @Override
+ public StructuredData invokeRpc(final String identifier, final String noPayload) {
+ if (!Strings.isNullOrEmpty(noPayload)) {
+ throw new ResponseException(Status.UNSUPPORTED_MEDIA_TYPE,
+ "Content-Type contains unsupported Media Type.");
+ }
+
+ final RpcDefinition rpc = this.resolveIdentifierInInvokeRpc(identifier);
+ return this.callRpc(rpc, null);
+ }
+
+ private RpcDefinition resolveIdentifierInInvokeRpc(final String identifier) {
+ if (identifier.indexOf("/") < 0) {
+ final String identifierDecoded = this.controllerContext.urlPathArgDecode(identifier);
+ final RpcDefinition rpc = this.controllerContext.getRpcDefinition(identifierDecoded);
+ if (rpc != null) {
+ return rpc;
+ }
+
+ throw new ResponseException(Status.NOT_FOUND, "RPC does not exist.");
+ }
+
+ final String slashErrorMsg = String.format(
+ "Identifier %n%s%ncan\'t contain slash character (/).%nIf slash is part of identifier name then use %%2F placeholder.",
+ identifier);
+
+ throw new ResponseException(Status.NOT_FOUND, slashErrorMsg);
+ }
+
+ private StructuredData callRpc(final RpcDefinition rpc, final CompositeNode payload) {
+ if (rpc == null) {
+ throw new ResponseException(Status.NOT_FOUND, "RPC does not exist.");
+ }
+
+ CompositeNode rpcRequest = null;
+ if (payload == null) {
+ rpcRequest = NodeFactory.createMutableCompositeNode(rpc.getQName(), null, null, null, null);
+ }
+ else {
+ final CompositeNode value = this.normalizeNode(payload, rpc.getInput(), null);
+ final List<Node<?>> input = new ArrayList<Node<?>>();
+ input.add(value);
+
+ rpcRequest = NodeFactory.createMutableCompositeNode(rpc.getQName(), null, input, null, null);
+ }
+
+ final RpcResult<CompositeNode> rpcResult = broker.invokeRpc(rpc.getQName(), rpcRequest);
+
+ if (!rpcResult.isSuccessful()) {
+ throw new ResponseException(Status.INTERNAL_SERVER_ERROR, "Operation failed");
+ }
+
+ CompositeNode result = rpcResult.getResult();
+ if (result == null) {
+ return null;
+ }
+
+ return new StructuredData(result, rpc.getOutput(), null);
+ }
+
+ @Override
+ public StructuredData readConfigurationData(final String identifier) {
+ final InstanceIdWithSchemaNode iiWithData = this.controllerContext.toInstanceIdentifier(identifier);
+ CompositeNode data = null;
+ MountInstance mountPoint = iiWithData.getMountPoint();
+ if (mountPoint != null) {
+ data = broker.readConfigurationDataBehindMountPoint(mountPoint, iiWithData.getInstanceIdentifier());
+ }
+ else {
+ data = broker.readConfigurationData(iiWithData.getInstanceIdentifier());
+ }
+
+ return new StructuredData(data, iiWithData.getSchemaNode(), iiWithData.getMountPoint());
+ }
+
+ @Override
+ public StructuredData readOperationalData(final String identifier) {
+ final InstanceIdWithSchemaNode iiWithData = this.controllerContext.toInstanceIdentifier(identifier);
+ CompositeNode data = null;
+ MountInstance mountPoint = iiWithData.getMountPoint();
+ if (mountPoint != null) {
+ data = broker.readOperationalDataBehindMountPoint(mountPoint, iiWithData.getInstanceIdentifier());
+ }
+ else {
+ data = broker.readOperationalData(iiWithData.getInstanceIdentifier());
+ }
+
+ return new StructuredData(data, iiWithData.getSchemaNode(), mountPoint);
+ }
+
+ @Override
+ public Response updateConfigurationData(final String identifier, final CompositeNode payload) {
+ final InstanceIdWithSchemaNode iiWithData = this.controllerContext.toInstanceIdentifier(identifier);
+ MountInstance mountPoint = iiWithData.getMountPoint();
+ final CompositeNode value = this.normalizeNode(payload, iiWithData.getSchemaNode(), mountPoint);
+ RpcResult<TransactionStatus> status = null;
+
+ try {
+ if (mountPoint != null) {
+ status = broker.commitConfigurationDataPutBehindMountPoint(
+ mountPoint, iiWithData.getInstanceIdentifier(), value).get();
+ } else {
+ status = broker.commitConfigurationDataPut(iiWithData.getInstanceIdentifier(), value).get();
+ }
+ }
+ catch( Exception e ) {
+ throw new ResponseException( e, "Error updating data" );
+ }
+
+ if( status.getResult() == TransactionStatus.COMMITED )
+ return Response.status(Status.OK).build();
+
+ return Response.status(Status.INTERNAL_SERVER_ERROR).build();
+ }
+
+ @Override
+ public Response createConfigurationData(final String identifier, final CompositeNode payload) {
+ URI payloadNS = this.namespace(payload);
+ if (payloadNS == null) {
+ throw new ResponseException(Status.BAD_REQUEST,
+ "Data has bad format. Root element node must have namespace (XML format) or module name(JSON format)");
+ }
+
+ InstanceIdWithSchemaNode iiWithData = null;
+ CompositeNode value = null;
+ if (this.representsMountPointRootData(payload)) {
+ // payload represents mount point data and URI represents path to the mount point
+
+ if (this.endsWithMountPoint(identifier)) {
+ throw new ResponseException(Status.BAD_REQUEST,
+ "URI has bad format. URI should be without \"" + ControllerContext.MOUNT +
+ "\" for POST operation.");
+ }
+
+ final String completeIdentifier = this.addMountPointIdentifier(identifier);
+ iiWithData = this.controllerContext.toInstanceIdentifier(completeIdentifier);
+
+ value = this.normalizeNode(payload, iiWithData.getSchemaNode(), iiWithData.getMountPoint());
+ }
+ else {
+ final InstanceIdWithSchemaNode incompleteInstIdWithData =
+ this.controllerContext.toInstanceIdentifier(identifier);
+ final DataNodeContainer parentSchema = (DataNodeContainer) incompleteInstIdWithData.getSchemaNode();
+ MountInstance mountPoint = incompleteInstIdWithData.getMountPoint();
+ final Module module = this.findModule(mountPoint, payload);
+ if (module == null) {
+ throw new ResponseException(Status.BAD_REQUEST,
+ "Module was not found for \"" + payloadNS + "\"");
+ }
+
+ String payloadName = this.getName(payload);
+ final DataSchemaNode schemaNode = this.controllerContext.findInstanceDataChildByNameAndNamespace(
+ parentSchema, payloadName, module.getNamespace());
+ value = this.normalizeNode(payload, schemaNode, mountPoint);
+
+ iiWithData = this.addLastIdentifierFromData(incompleteInstIdWithData, value, schemaNode);
+ }
+
+ RpcResult<TransactionStatus> status = null;
+ MountInstance mountPoint = iiWithData.getMountPoint();
+ try {
+ if (mountPoint != null) {
+ Future<RpcResult<TransactionStatus>> future =
+ broker.commitConfigurationDataPostBehindMountPoint(
+ mountPoint, iiWithData.getInstanceIdentifier(), value);
+ status = future == null ? null : future.get();
+ }
+ else {
+ Future<RpcResult<TransactionStatus>> future =
+ broker.commitConfigurationDataPost(iiWithData.getInstanceIdentifier(), value);
+ status = future == null ? null : future.get();
+ }
+ }
+ catch( ResponseException e) { throw e; }
+ catch( Exception e ) {
+ throw new ResponseException( e, "Error creating data" );
+ }
+
+ 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();
+ }
+
+ @Override
+ public Response createConfigurationData(final CompositeNode payload) {
+ URI payloadNS = this.namespace(payload);
+ if (payloadNS == null) {
+ throw new ResponseException(Status.BAD_REQUEST,
+ "Data has bad format. Root element node must have namespace (XML format) or module name(JSON format)");
+ }
+
+ final Module module = this.findModule(null, payload);
+ if (module == null) {
+ throw new ResponseException(Status.BAD_REQUEST,
+ "Data has bad format. Root element node has incorrect namespace (XML format) or module name(JSON format)");
+ }
+
+ String payloadName = this.getName(payload);
+ final DataSchemaNode schemaNode = this.controllerContext.findInstanceDataChildByNameAndNamespace(
+ module, payloadName, module.getNamespace());
+ final CompositeNode value = this.normalizeNode(payload, schemaNode, null);
+ final InstanceIdWithSchemaNode iiWithData = this.addLastIdentifierFromData(null, value, schemaNode);
+ RpcResult<TransactionStatus> status = null;
+ MountInstance mountPoint = iiWithData.getMountPoint();
+
+ try {
+ if (mountPoint != null) {
+ Future<RpcResult<TransactionStatus>> future =
+ broker.commitConfigurationDataPostBehindMountPoint(
+ mountPoint, iiWithData.getInstanceIdentifier(), value);
+ status = future == null ? null : future.get();
+ }
+ else {
+ Future<RpcResult<TransactionStatus>> future =
+ broker.commitConfigurationDataPost(iiWithData.getInstanceIdentifier(), value);
+ status = future == null ? null : future.get();
+ }
+ }
+ catch( ResponseException e) { throw e; }
+ catch( Exception e ) {
+ throw new ResponseException( e, "Error creating data" );
+ }
+
+ 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();
+ }
+
+ @Override
+ public Response deleteConfigurationData(final String identifier) {
+ final InstanceIdWithSchemaNode iiWithData = this.controllerContext.toInstanceIdentifier(identifier);
+ RpcResult<TransactionStatus> status = null;
+ MountInstance mountPoint = iiWithData.getMountPoint();
+
+ try {
+ if (mountPoint != null) {
+ status = broker.commitConfigurationDataDeleteBehindMountPoint(
+ mountPoint, iiWithData.getInstanceIdentifier()).get();
+ }
+ else {
+ status = broker.commitConfigurationDataDelete(iiWithData.getInstanceIdentifier()).get();
+ }
+ }
+ catch( Exception e ) {
+ throw new ResponseException( e, "Error creating data" );
+ }
+
+ if( status.getResult() == TransactionStatus.COMMITED )
+ return Response.status(Status.OK).build();
+
+ return Response.status(Status.INTERNAL_SERVER_ERROR).build();
+ }
+
+ @Override
+ public Response subscribeToStream(final String identifier, final UriInfo uriInfo) {
+ final String streamName = Notificator.createStreamNameFromUri(identifier);
+ if (Strings.isNullOrEmpty(streamName)) {
+ throw new ResponseException(Status.BAD_REQUEST, "Stream name is empty.");
+ }
+
+ final ListenerAdapter listener = Notificator.getListenerFor(streamName);
+ if (listener == null) {
+ throw new ResponseException(Status.BAD_REQUEST, "Stream was not found.");
+ }
+
+ broker.registerToListenDataChanges(listener);
+
+ final UriBuilder uriBuilder = uriInfo.getAbsolutePathBuilder();
+ UriBuilder port = uriBuilder.port(WebSocketServer.PORT);
+ 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);
+ }
+ else if (data != null) {
+ URI namespace = data.getNodeType().getNamespace();
+ if (mountPoint != null) {
+ return this.controllerContext.findModuleByNamespace(mountPoint, namespace);
+ }
+ else {
+ return this.controllerContext.findModuleByNamespace(namespace);
+ }
+ }
+ else {
+ throw new IllegalArgumentException("Unhandled parameter types: " +
+ Arrays.<Object>asList(mountPoint, data).toString());
+ }
+ }
+
+ private Module findModule(final MountInstance mountPoint, final CompositeNodeWrapper data) {
+ URI namespace = data.getNamespace();
+ Preconditions.<URI>checkNotNull(namespace);
+
+ Module module = null;
+ if (mountPoint != null) {
+ module = this.controllerContext.findModuleByNamespace(mountPoint, namespace);
+ if (module == null) {
+ module = this.controllerContext.findModuleByName(mountPoint, namespace.toString());
+ }
+ }
+ else {
+ module = this.controllerContext.findModuleByNamespace(namespace);
+ if (module == null) {
+ module = this.controllerContext.findModuleByName(namespace.toString());
+ }
+ }
+
+ return module;
+ }
+
+ private InstanceIdWithSchemaNode addLastIdentifierFromData(
+ final InstanceIdWithSchemaNode identifierWithSchemaNode,
+ final CompositeNode data, final DataSchemaNode schemaOfData) {
+ InstanceIdentifier instanceIdentifier = null;
+ if (identifierWithSchemaNode != null) {
+ instanceIdentifier = identifierWithSchemaNode.getInstanceIdentifier();
+ }
+
+ final InstanceIdentifier iiOriginal = instanceIdentifier;
+ InstanceIdentifierBuilder iiBuilder = null;
+ if (iiOriginal == null) {
+ iiBuilder = InstanceIdentifier.builder();
+ }
+ else {
+ iiBuilder = InstanceIdentifier.builder(iiOriginal);
+ }
+
+ if ((schemaOfData instanceof ListSchemaNode)) {
+ HashMap<QName,Object> keys = this.resolveKeysFromData(((ListSchemaNode) schemaOfData), data);
+ iiBuilder.nodeWithKey(schemaOfData.getQName(), keys);
+ }
+ else {
+ iiBuilder.node(schemaOfData.getQName());
+ }
+
+ InstanceIdentifier instance = iiBuilder.toInstance();
+ MountInstance mountPoint = null;
+ if (identifierWithSchemaNode != null) {
+ mountPoint=identifierWithSchemaNode.getMountPoint();
+ }
+
+ return new InstanceIdWithSchemaNode(instance, schemaOfData, mountPoint);
+ }
+
+ private HashMap<QName,Object> resolveKeysFromData(final ListSchemaNode listNode,
+ final CompositeNode dataNode) {
+ final HashMap<QName,Object> keyValues = new HashMap<QName, Object>();
+ List<QName> _keyDefinition = listNode.getKeyDefinition();
+ for (final QName key : _keyDefinition) {
+ SimpleNode<? extends Object> head = null;
+ String localName = key.getLocalName();
+ List<SimpleNode<? extends Object>> 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 ResponseException(Status.BAD_REQUEST,
+ "Data contains list \"" + dataNode.getNodeType().getLocalName() +
+ "\" which does not contain key: \"" + key.getLocalName() + "\"");
+ }
+
+ 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) {
+ 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) );
+ }
+
+ private String addMountPointIdentifier(final String identifier) {
+ boolean endsWith = identifier.endsWith("/");
+ if (endsWith) {
+ return (identifier + ControllerContext.MOUNT);
+ }
+
+ return identifier + "/" + ControllerContext.MOUNT;
+ }
+
+ private CompositeNode normalizeNode(final CompositeNode node, final DataSchemaNode schema,
+ final MountInstance mountPoint) {
+ if (schema == null) {
+ QName nodeType = node == null ? null : node.getNodeType();
+ String localName = nodeType == null ? null : nodeType.getLocalName();
+ String _plus = ("Data schema node was not found for " + localName);
+ throw new ResponseException(Status.INTERNAL_SERVER_ERROR,
+ "Data schema node was not found for " + localName );
+ }
+
+ if (!(schema instanceof DataNodeContainer)) {
+ throw new ResponseException(Status.BAD_REQUEST,
+ "Root element has to be container or list yang datatype.");
+ }
+
+ if ((node instanceof CompositeNodeWrapper)) {
+ boolean isChangeAllowed = ((CompositeNodeWrapper) node).isChangeAllowed();
+ if (isChangeAllowed) {
+ try {
+ this.normalizeNode(((CompositeNodeWrapper) node), schema, null, mountPoint);
+ }
+ catch (NumberFormatException e) {
+ throw new ResponseException(Status.BAD_REQUEST, e.getMessage());
+ }
+ }
+
+ return ((CompositeNodeWrapper) node).unwrap();
+ }
+
+ return node;
+ }
+
+ private void normalizeNode(final NodeWrapper<? extends Object> nodeBuilder,
+ final DataSchemaNode schema, final QName previousAugment,
+ final MountInstance mountPoint) {
+ if (schema == null) {
+ throw new ResponseException(Status.BAD_REQUEST,
+ "Data has bad format.\n\"" + nodeBuilder.getLocalName() +
+ "\" does not exist in yang schema.");
+ }
+
+ QName currentAugment = null;
+ if (nodeBuilder.getQname() != null) {
+ currentAugment = previousAugment;
+ }
+ else {
+ currentAugment = this.normalizeNodeName(nodeBuilder, schema, previousAugment, mountPoint);
+ if (nodeBuilder.getQname() == null) {
+ throw new ResponseException(Status.BAD_REQUEST,
+ "Data has bad format.\nIf data is in XML format then namespace for \"" +
+ nodeBuilder.getLocalName() +
+ "\" should be \"" + schema.getQName().getNamespace() + "\".\n" +
+ "If data is in JSON format then module name for \"" + nodeBuilder.getLocalName() +
+ "\" should be corresponding to namespace \"" +
+ schema.getQName().getNamespace() + "\".");
+ }
+ }
+
+ if ((nodeBuilder instanceof CompositeNodeWrapper)) {
+ final List<NodeWrapper<?>> children = ((CompositeNodeWrapper) nodeBuilder).getValues();
+ for (final NodeWrapper<? extends Object> child : children) {
+ final List<DataSchemaNode> potentialSchemaNodes =
+ this.controllerContext.findInstanceDataChildrenByName(
+ ((DataNodeContainer) schema), child.getLocalName());
+
+ if (potentialSchemaNodes.size() > 1 && child.getNamespace() == null) {
+ StringBuilder builder = new StringBuilder();
+ for (final DataSchemaNode potentialSchemaNode : potentialSchemaNodes) {
+ builder.append(" ").append(potentialSchemaNode.getQName().getNamespace().toString())
+ .append("\n");
+ }
+
+ throw new ResponseException(Status.BAD_REQUEST,
+ "Node \"" + child.getLocalName() +
+ "\" is added as augment from more than one module. " +
+ "Therefore node must have namespace (XML format) or module name (JSON format)." +
+ "\nThe node is added as augment from modules with namespaces:\n" + builder);
+ }
+
+ boolean rightNodeSchemaFound = false;
+ for (final DataSchemaNode potentialSchemaNode : potentialSchemaNodes) {
+ if (!rightNodeSchemaFound) {
+ final QName potentialCurrentAugment =
+ this.normalizeNodeName(child, potentialSchemaNode, currentAugment, mountPoint);
+ if (child.getQname() != null ) {
+ this.normalizeNode(child, potentialSchemaNode, potentialCurrentAugment, mountPoint);
+ rightNodeSchemaFound = true;
+ }
+ }
+ }
+
+ if (!rightNodeSchemaFound) {
+ throw new ResponseException(Status.BAD_REQUEST,
+ "Schema node \"" + child.getLocalName() + "\" was not found in module.");
+ }
+ }
+
+ if ((schema instanceof ListSchemaNode)) {
+ final List<QName> listKeys = ((ListSchemaNode) schema).getKeyDefinition();
+ for (final QName listKey : listKeys) {
+ boolean foundKey = false;
+ for (final NodeWrapper<? extends Object> child : children) {
+ if (Objects.equal(child.unwrap().getNodeType().getLocalName(), listKey.getLocalName())) {
+ foundKey = true;
+ }
+ }
+
+ if (!foundKey) {
+ throw new ResponseException(Status.BAD_REQUEST,
+ "Missing key in URI \"" + listKey.getLocalName() +
+ "\" of list \"" + schema.getQName().getLocalName() + "\"");
+ }
+ }
+ }
+ }
+ else {
+ if ((nodeBuilder instanceof SimpleNodeWrapper)) {
+ final SimpleNodeWrapper simpleNode = ((SimpleNodeWrapper) nodeBuilder);
+ final Object value = simpleNode.getValue();
+ Object inputValue = value;
+ TypeDefinition<? extends Object> typeDefinition = this.typeDefinition(schema);
+ if ((typeDefinition instanceof IdentityrefTypeDefinition)) {
+ if ((value instanceof String)) {
+ inputValue = new IdentityValuesDTO( nodeBuilder.getNamespace().toString(),
+ (String) value, null, (String) value );
+ } // else value is already instance of IdentityValuesDTO
+ }
+
+ Codec<Object,Object> codec = RestCodec.from(typeDefinition, mountPoint);
+ Object outputValue = codec == null ? null : codec.deserialize(inputValue);
+
+ simpleNode.setValue(outputValue);
+ }
+ else {
+ if ((nodeBuilder instanceof EmptyNodeWrapper)) {
+ final EmptyNodeWrapper emptyNodeBuilder = ((EmptyNodeWrapper) nodeBuilder);
+ if ((schema instanceof LeafSchemaNode)) {
+ emptyNodeBuilder.setComposite(false);
+ }
+ else {
+ if ((schema instanceof ContainerSchemaNode)) {
+ // FIXME: Add presence check
+ emptyNodeBuilder.setComposite(true);
+ }
+ }
+ }
+ }
+ }
+ }
+
+ private QName normalizeNodeName(final NodeWrapper<? extends Object> nodeBuilder,
+ final DataSchemaNode schema, final QName previousAugment,
+ final MountInstance mountPoint) {
+ QName validQName = schema.getQName();
+ QName currentAugment = previousAugment;
+ if (schema.isAugmenting()) {
+ currentAugment = schema.getQName();
+ }
+ else if (previousAugment != null &&
+ !Objects.equal( schema.getQName().getNamespace(), previousAugment.getNamespace())) {
+ validQName = QName.create(currentAugment, schema.getQName().getLocalName());
+ }
+
+ String moduleName = null;
+ if (mountPoint == null) {
+ moduleName = controllerContext.findModuleNameByNamespace(validQName.getNamespace());
+ }
+ else {
+ moduleName = controllerContext.findModuleNameByNamespace(mountPoint, validQName.getNamespace());
+ }
+
+ 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)*/ ) {
+
+ nodeBuilder.setQname(validQName);
+ }
+
+ return currentAugment;
+ }
+
+ private URI namespace(final CompositeNode data) {
+ if (data instanceof CompositeNodeWrapper) {
+ return ((CompositeNodeWrapper)data).getNamespace();
+ }
+ else if (data != null) {
+ return data.getNodeType().getNamespace();
+ }
+ else {
+ throw new IllegalArgumentException("Unhandled parameter types: " +
+ Arrays.<Object>asList(data).toString());
+ }
+ }
+
+ private String localName(final CompositeNode data) {
+ if (data instanceof CompositeNodeWrapper) {
+ return ((CompositeNodeWrapper)data).getLocalName();
+ }
+ else if (data != null) {
+ return data.getNodeType().getLocalName();
+ }
+ else {
+ throw new IllegalArgumentException("Unhandled parameter types: " +
+ Arrays.<Object>asList(data).toString());
+ }
+ }
+
+ private String getName(final CompositeNode data) {
+ if (data instanceof CompositeNodeWrapper) {
+ return ((CompositeNodeWrapper)data).getLocalName();
+ }
+ else if (data != null) {
+ return data.getNodeType().getLocalName();
+ }
+ else {
+ throw new IllegalArgumentException("Unhandled parameter types: " +
+ Arrays.<Object>asList(data).toString());
+ }
+ }
+
+ private TypeDefinition<? extends Object> _typeDefinition(final LeafSchemaNode node) {
+ TypeDefinition<?> baseType = node.getType();
+ while (baseType.getBaseType() != null) {
+ baseType = baseType.getBaseType();
+ }
+
+ return baseType;
+ }
+
+ private TypeDefinition<? extends Object> typeDefinition(final LeafListSchemaNode node) {
+ TypeDefinition<?> baseType = node.getType();
+ while (baseType.getBaseType() != null) {
+ baseType = baseType.getBaseType();
+ }
+
+ return baseType;
+ }
+
+ private TypeDefinition<? extends Object> typeDefinition(final DataSchemaNode node) {
+ if (node instanceof LeafListSchemaNode) {
+ return typeDefinition((LeafListSchemaNode)node);
+ }
+ else if (node instanceof LeafSchemaNode) {
+ return _typeDefinition((LeafSchemaNode)node);
+ }
+ else {
+ throw new IllegalArgumentException("Unhandled parameter types: " +
+ Arrays.<Object>asList(node).toString());
+ }
+ }
+}
+++ /dev/null
-/*
- * Copyright (c) 2014 Cisco Systems, Inc. and others. All rights reserved.
- *
- * This program and the accompanying materials are made available under the
- * terms of the Eclipse Public License v1.0 which accompanies this distribution,
- * and is available at http://www.eclipse.org/legal/epl-v10.html
- */
-package org.opendaylight.controller.sal.restconf.impl
-
-import com.google.common.base.Preconditions
-import com.google.common.base.Splitter
-import com.google.common.collect.Lists
-import java.net.URI
-import java.text.ParseException
-import java.text.SimpleDateFormat
-import java.util.ArrayList
-import java.util.HashMap
-import java.util.List
-import java.util.Set
-import javax.ws.rs.core.Response
-import javax.ws.rs.core.UriInfo
-import org.opendaylight.controller.md.sal.common.api.TransactionStatus
-import org.opendaylight.controller.sal.core.api.mount.MountInstance
-import org.opendaylight.controller.sal.rest.api.RestconfService
-import org.opendaylight.controller.sal.streams.listeners.Notificator
-import org.opendaylight.controller.sal.streams.websockets.WebSocketServer
-import org.opendaylight.yangtools.yang.common.QName
-import org.opendaylight.yangtools.yang.common.RpcResult
-import org.opendaylight.yangtools.yang.data.api.CompositeNode
-import org.opendaylight.yangtools.yang.data.api.InstanceIdentifier
-import org.opendaylight.yangtools.yang.data.api.InstanceIdentifier.InstanceIdentifierBuilder
-import org.opendaylight.yangtools.yang.data.api.Node
-import org.opendaylight.yangtools.yang.data.impl.NodeFactory
-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.Module
-import org.opendaylight.yangtools.yang.model.api.RpcDefinition
-import org.opendaylight.yangtools.yang.model.api.SchemaContext
-import org.opendaylight.yangtools.yang.model.api.TypeDefinition
-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 static javax.ws.rs.core.Response.Status.*
-
-class RestconfImpl implements RestconfService {
-
- val static RestconfImpl INSTANCE = new RestconfImpl
- val static MOUNT_POINT_MODULE_NAME = "ietf-netconf"
- val static REVISION_FORMAT = new SimpleDateFormat("yyyy-MM-dd")
- val static RESTCONF_MODULE_DRAFT02_REVISION = "2013-10-19"
- val static RESTCONF_MODULE_DRAFT02_NAME = "ietf-restconf"
- val static RESTCONF_MODULE_DRAFT02_NAMESPACE = "urn:ietf:params:xml:ns:yang:ietf-restconf"
- val static RESTCONF_MODULE_DRAFT02_RESTCONF_GROUPING_SCHEMA_NODE = "restconf"
- val static RESTCONF_MODULE_DRAFT02_RESTCONF_CONTAINER_SCHEMA_NODE = "restconf"
- val static RESTCONF_MODULE_DRAFT02_MODULES_CONTAINER_SCHEMA_NODE = "modules"
- val static RESTCONF_MODULE_DRAFT02_MODULE_LIST_SCHEMA_NODE = "module"
- val static RESTCONF_MODULE_DRAFT02_STREAMS_CONTAINER_SCHEMA_NODE = "streams"
- val static RESTCONF_MODULE_DRAFT02_STREAM_LIST_SCHEMA_NODE = "stream"
- val static RESTCONF_MODULE_DRAFT02_OPERATIONS_CONTAINER_SCHEMA_NODE = "operations"
- val static SAL_REMOTE_NAMESPACE = "urn:opendaylight:params:xml:ns:yang:controller:md:sal:remote"
- val static SAL_REMOTE_RPC_SUBSRCIBE = "create-data-change-event-subscription"
-
- @Property
- BrokerFacade broker
-
- @Property
- extension ControllerContext controllerContext
-
- private new() {
- if (INSTANCE !== null) {
- throw new IllegalStateException("Already instantiated");
- }
- }
-
- static def getInstance() {
- return INSTANCE
- }
-
- override getModules() {
- val restconfModule = getRestconfModule()
- val List<Node<?>> modulesAsData = new ArrayList
- val moduleSchemaNode = restconfModule.getSchemaNode(RESTCONF_MODULE_DRAFT02_MODULE_LIST_SCHEMA_NODE)
- for (module : allModules) {
- modulesAsData.add(module.toModuleCompositeNode(moduleSchemaNode))
- }
- val modulesSchemaNode = restconfModule.getSchemaNode(RESTCONF_MODULE_DRAFT02_MODULES_CONTAINER_SCHEMA_NODE)
- val modulesNode = NodeFactory.createImmutableCompositeNode(modulesSchemaNode.QName, null, modulesAsData)
- return new StructuredData(modulesNode, modulesSchemaNode, null)
- }
-
- override getAvailableStreams(){
- var Set<String> availableStreams = Notificator.getStreamNames();
- val List<Node<?>> streamsAsData = new ArrayList
- val streamSchemaNode = restconfModule.getSchemaNode(RESTCONF_MODULE_DRAFT02_STREAM_LIST_SCHEMA_NODE)
- for (String streamName:availableStreams){
- streamsAsData.add(streamName.toStreamCompositeNode(streamSchemaNode))
- }
- val streamsSchemaNode = restconfModule.getSchemaNode(RESTCONF_MODULE_DRAFT02_STREAMS_CONTAINER_SCHEMA_NODE)
- val streamsNode = NodeFactory.createImmutableCompositeNode(streamsSchemaNode.QName, null, streamsAsData)
- return new StructuredData(streamsNode, streamsSchemaNode, null)
- }
- override getModules(String identifier) {
- var Set<Module> modules = null
- var MountInstance mountPoint = null
- if (identifier.contains(ControllerContext.MOUNT)) {
- mountPoint = identifier.toMountPointIdentifier.mountPoint
- modules = mountPoint.allModules
- } else {
- throw new ResponseException(BAD_REQUEST, "URI has bad format. If modules behind mount point should be showed, URI has to end with " + ControllerContext.MOUNT)
- }
- val List<Node<?>> modulesAsData = new ArrayList
- val moduleSchemaNode = restconfModule.getSchemaNode(RESTCONF_MODULE_DRAFT02_MODULE_LIST_SCHEMA_NODE)
- for (module : modules) {
- modulesAsData.add(module.toModuleCompositeNode(moduleSchemaNode))
- }
- val modulesSchemaNode = restconfModule.getSchemaNode(RESTCONF_MODULE_DRAFT02_MODULES_CONTAINER_SCHEMA_NODE)
- val modulesNode = NodeFactory.createImmutableCompositeNode(modulesSchemaNode.QName, null, modulesAsData)
- return new StructuredData(modulesNode, modulesSchemaNode, mountPoint)
- }
-
- override getModule(String identifier) {
- val moduleNameAndRevision = identifier.moduleNameAndRevision
- var Module module = null
- var MountInstance mountPoint = null
- if (identifier.contains(ControllerContext.MOUNT)) {
- mountPoint = identifier.toMountPointIdentifier.mountPoint
- module = mountPoint.findModuleByNameAndRevision(moduleNameAndRevision)
- } else {
- module = findModuleByNameAndRevision(moduleNameAndRevision)
- }
- if (module === null) {
- throw new ResponseException(BAD_REQUEST,
- "Module with name '" + moduleNameAndRevision.localName + "' and revision '" +
- moduleNameAndRevision.revision + "' was not found.")
- }
- val moduleSchemaNode = restconfModule.getSchemaNode(RESTCONF_MODULE_DRAFT02_MODULE_LIST_SCHEMA_NODE)
- val moduleNode = module.toModuleCompositeNode(moduleSchemaNode)
- return new StructuredData(moduleNode, moduleSchemaNode, mountPoint)
- }
-
- override getOperations() {
- return operationsFromModulesToStructuredData(allModules,null)
- }
-
- override getOperations(String identifier) {
- var Set<Module> modules = null
- var MountInstance mountPoint = null
- if (identifier.contains(ControllerContext.MOUNT)) {
- mountPoint = identifier.toMountPointIdentifier.mountPoint
- modules = mountPoint.allModules
- } else {
- throw new ResponseException(BAD_REQUEST, "URI has bad format. If operations behind mount point should be showed, URI has to end with " + ControllerContext.MOUNT)
- }
- return operationsFromModulesToStructuredData(modules,mountPoint)
- }
-
- private def StructuredData operationsFromModulesToStructuredData(Set<Module> modules,MountInstance mountPoint) {
- val List<Node<?>> operationsAsData = new ArrayList
- val operationsSchemaNode = restconfModule.getSchemaNode(RESTCONF_MODULE_DRAFT02_OPERATIONS_CONTAINER_SCHEMA_NODE)
- val fakeOperationsSchemaNode = new ContainerSchemaNodeBuilder(RESTCONF_MODULE_DRAFT02_NAME, 0, operationsSchemaNode.QName, operationsSchemaNode.path)
- for (module : modules) {
- for (rpc : module.rpcs) {
- operationsAsData.add(NodeFactory.createImmutableSimpleNode(rpc.QName, null, null))
- val fakeRpcSchemaNode = new LeafSchemaNodeBuilder(module.name, 0, rpc.QName, null)
- fakeRpcSchemaNode.setAugmenting(true)
- fakeRpcSchemaNode.setType(EmptyType.instance)
- fakeOperationsSchemaNode.addChildNode(fakeRpcSchemaNode.build)
- }
- }
- val operationsNode = NodeFactory.createImmutableCompositeNode(operationsSchemaNode.QName, null, operationsAsData)
- return new StructuredData(operationsNode, fakeOperationsSchemaNode.build, mountPoint)
- }
-
- private def Module getRestconfModule() {
- val restconfModule = findModuleByNameAndRevision(
- QName.create(RESTCONF_MODULE_DRAFT02_NAMESPACE, RESTCONF_MODULE_DRAFT02_REVISION,
- RESTCONF_MODULE_DRAFT02_NAME))
- if (restconfModule === null) {
- throw new ResponseException(INTERNAL_SERVER_ERROR, "Restconf module was not found.")
- }
- return restconfModule
- }
-
- private def QName getModuleNameAndRevision(String identifier) {
- val indexOfMountPointFirstLetter = identifier.indexOf(ControllerContext.MOUNT)
- var moduleNameAndRevision = "";
- if (indexOfMountPointFirstLetter !== -1) { // module and revision is behind mount point string
- moduleNameAndRevision = identifier.substring(indexOfMountPointFirstLetter + ControllerContext.MOUNT.length)
- } else (
- moduleNameAndRevision = identifier
- )
- val pathArgs = Lists.newArrayList(Splitter.on("/").omitEmptyStrings.split(moduleNameAndRevision))
- if (pathArgs.length < 2) {
- throw new ResponseException(BAD_REQUEST,
- "URI has bad format. End of URI should be in format 'moduleName/yyyy-MM-dd'")
- }
- try {
- val moduleName = pathArgs.head
- val moduleRevision = REVISION_FORMAT.parse(pathArgs.get(1))
- return QName.create(null, moduleRevision, moduleName)
- } catch(ParseException e) {
- throw new ResponseException(BAD_REQUEST, "URI has bad format. It should be 'moduleName/yyyy-MM-dd'")
- }
- }
-
- private def CompositeNode toStreamCompositeNode(String streamName, DataSchemaNode streamSchemaNode) {
- val List<Node<?>> streamNodeValues = new ArrayList
- val nameSchemaNode = (streamSchemaNode as DataNodeContainer).findInstanceDataChildrenByName("name").head
- streamNodeValues.add(NodeFactory.createImmutableSimpleNode(nameSchemaNode.QName, null, streamName))
-
- val descriptionSchemaNode = (streamSchemaNode as DataNodeContainer).findInstanceDataChildrenByName("description").head
- streamNodeValues.add(NodeFactory.createImmutableSimpleNode(descriptionSchemaNode.QName, null, "DESCRIPTION_PLACEHOLDER"))
-
- val replaySupportSchemaNode = (streamSchemaNode as DataNodeContainer).findInstanceDataChildrenByName("replay-support").head
- streamNodeValues.add(NodeFactory.createImmutableSimpleNode(replaySupportSchemaNode.QName, null, true))
-
- val replayLogCreationTimeSchemaNode = (streamSchemaNode as DataNodeContainer).findInstanceDataChildrenByName("replay-log-creation-time").head
- streamNodeValues.add(NodeFactory.createImmutableSimpleNode(replayLogCreationTimeSchemaNode.QName, null, ""))
-
- val eventsSchemaNode = (streamSchemaNode as DataNodeContainer).findInstanceDataChildrenByName("events").head
- streamNodeValues.add(NodeFactory.createImmutableSimpleNode(eventsSchemaNode.QName, null, ""))
-
- return NodeFactory.createImmutableCompositeNode(streamSchemaNode.QName, null, streamNodeValues)
- }
- private def CompositeNode toModuleCompositeNode(Module module, DataSchemaNode moduleSchemaNode) {
- val List<Node<?>> moduleNodeValues = new ArrayList
- val nameSchemaNode = (moduleSchemaNode as DataNodeContainer).findInstanceDataChildrenByName("name").head
- moduleNodeValues.add(NodeFactory.createImmutableSimpleNode(nameSchemaNode.QName, null, module.name))
- val revisionSchemaNode = (moduleSchemaNode as DataNodeContainer).findInstanceDataChildrenByName("revision").head
- moduleNodeValues.add(NodeFactory.createImmutableSimpleNode(revisionSchemaNode.QName, null, REVISION_FORMAT.format(module.revision)))
- val namespaceSchemaNode = (moduleSchemaNode as DataNodeContainer).findInstanceDataChildrenByName("namespace").head
- moduleNodeValues.add(NodeFactory.createImmutableSimpleNode(namespaceSchemaNode.QName, null, module.namespace.toString))
- val featureSchemaNode = (moduleSchemaNode as DataNodeContainer).findInstanceDataChildrenByName("feature").head
- for (feature : module.features) {
- moduleNodeValues.add(NodeFactory.createImmutableSimpleNode(featureSchemaNode.QName, null, feature.QName.localName))
- }
- return NodeFactory.createImmutableCompositeNode(moduleSchemaNode.QName, null, moduleNodeValues)
- }
-
- private def DataSchemaNode getSchemaNode(Module restconfModule, String schemaNodeName) {
- val restconfGrouping = restconfModule.groupings.filter[g|g.QName.localName == RESTCONF_MODULE_DRAFT02_RESTCONF_GROUPING_SCHEMA_NODE].head
- val restconfContainer = restconfGrouping.findInstanceDataChildrenByName(RESTCONF_MODULE_DRAFT02_RESTCONF_CONTAINER_SCHEMA_NODE).head
- if (schemaNodeName == RESTCONF_MODULE_DRAFT02_OPERATIONS_CONTAINER_SCHEMA_NODE) {
- return (restconfContainer as DataNodeContainer).findInstanceDataChildrenByName(RESTCONF_MODULE_DRAFT02_OPERATIONS_CONTAINER_SCHEMA_NODE).head
- } else if (schemaNodeName == RESTCONF_MODULE_DRAFT02_STREAMS_CONTAINER_SCHEMA_NODE) {
- return (restconfContainer as DataNodeContainer).findInstanceDataChildrenByName(RESTCONF_MODULE_DRAFT02_STREAMS_CONTAINER_SCHEMA_NODE).head
- } else if (schemaNodeName == RESTCONF_MODULE_DRAFT02_STREAM_LIST_SCHEMA_NODE) {
- val modules = (restconfContainer as DataNodeContainer).findInstanceDataChildrenByName(RESTCONF_MODULE_DRAFT02_STREAMS_CONTAINER_SCHEMA_NODE).head
- return (modules as DataNodeContainer).findInstanceDataChildrenByName(RESTCONF_MODULE_DRAFT02_STREAM_LIST_SCHEMA_NODE).head
- }else if (schemaNodeName == RESTCONF_MODULE_DRAFT02_MODULES_CONTAINER_SCHEMA_NODE) {
- return (restconfContainer as DataNodeContainer).findInstanceDataChildrenByName(RESTCONF_MODULE_DRAFT02_MODULES_CONTAINER_SCHEMA_NODE).head
- } else if (schemaNodeName == RESTCONF_MODULE_DRAFT02_MODULE_LIST_SCHEMA_NODE) {
- val modules = (restconfContainer as DataNodeContainer).findInstanceDataChildrenByName(RESTCONF_MODULE_DRAFT02_MODULES_CONTAINER_SCHEMA_NODE).head
- return (modules as DataNodeContainer).findInstanceDataChildrenByName(RESTCONF_MODULE_DRAFT02_MODULE_LIST_SCHEMA_NODE).head
- }
- return null
- }
-
- override getRoot() {
- return null;
- }
-
- override invokeRpc(String identifier, CompositeNode payload) {
- val rpc = resolveIdentifierInInvokeRpc(identifier)
- if (rpc.QName.namespace.toString == SAL_REMOTE_NAMESPACE && rpc.QName.localName == SAL_REMOTE_RPC_SUBSRCIBE) {
- val value = normalizeNode(payload, rpc.input, null)
- val pathNode = value?.getFirstSimpleByName(QName.create(rpc.QName, "path"))
- val pathValue = pathNode?.value
- if (pathValue === null && !(pathValue instanceof InstanceIdentifier)) {
- throw new ResponseException(INTERNAL_SERVER_ERROR, "Instance identifier was not normalized correctly.");
- }
- val pathIdentifier = (pathValue as InstanceIdentifier)
- var String streamName = null
- if (!pathIdentifier.path.nullOrEmpty) {
- streamName = Notificator.createStreamNameFromUri(pathIdentifier.toFullRestconfIdentifier)
- }
- if (streamName.nullOrEmpty) {
- throw new ResponseException(BAD_REQUEST, "Path is empty or contains data node which is not Container or List build-in type.");
- }
- val streamNameNode = NodeFactory.createImmutableSimpleNode(QName.create(rpc.output.QName, "stream-name"), null, streamName)
- val List<Node<?>> output = new ArrayList
- output.add(streamNameNode)
- val responseData = NodeFactory.createMutableCompositeNode(rpc.output.QName, null, output, null, null)
-
- if (!Notificator.existListenerFor(pathIdentifier)) {
- Notificator.createListener(pathIdentifier, streamName)
- }
-
- return new StructuredData(responseData, rpc.output, null)
- }
- return callRpc(identifier.rpcDefinition, payload)
- }
-
- override invokeRpc(String identifier, String noPayload) {
- if (!noPayload.nullOrEmpty) {
- throw new ResponseException(UNSUPPORTED_MEDIA_TYPE, "Content-Type contains unsupported Media Type.");
- }
- val rpc = resolveIdentifierInInvokeRpc(identifier)
- return callRpc(rpc, null)
- }
-
- private def resolveIdentifierInInvokeRpc(String identifier) {
- if (identifier.indexOf("/") === -1) {
- val identifierDecoded = identifier.urlPathArgDecode
- val rpc = identifierDecoded.rpcDefinition
- if (rpc !== null) {
- return rpc
- }
- throw new ResponseException(NOT_FOUND, "RPC does not exist.");
- }
- val slashErrorMsg = String.format(
- "Identifier %n%s%ncan't contain slash character (/).%nIf slash is part of identifier name then use %%2F placeholder.", identifier)
- throw new ResponseException(NOT_FOUND, slashErrorMsg);
- }
-
- private def StructuredData callRpc(RpcDefinition rpc, CompositeNode payload) {
- if (rpc === null) {
- throw new ResponseException(NOT_FOUND, "RPC does not exist.");
- }
- var CompositeNode rpcRequest;
- if (payload === null) {
- rpcRequest = NodeFactory.createMutableCompositeNode(rpc.QName, null, null, null, null)
- } else {
- val value = normalizeNode(payload, rpc.input, null)
- val List<Node<?>> input = new ArrayList
- input.add(value)
- rpcRequest = NodeFactory.createMutableCompositeNode(rpc.QName, null, input, null, null)
- }
- val rpcResult = broker.invokeRpc(rpc.QName, rpcRequest);
- if (!rpcResult.successful) {
- throw new ResponseException(INTERNAL_SERVER_ERROR, "Operation failed")
- }
- if (rpcResult.result === null) {
- return null
- }
- return new StructuredData(rpcResult.result, rpc.output, null)
- }
-
- override readConfigurationData(String identifier) {
- val iiWithData = identifier.toInstanceIdentifier
- var CompositeNode data = null;
- if (iiWithData.mountPoint !== null) {
- data = broker.readConfigurationDataBehindMountPoint(iiWithData.mountPoint, iiWithData.getInstanceIdentifier)
- } else {
- data = broker.readConfigurationData(iiWithData.getInstanceIdentifier);
- }
- return new StructuredData(data, iiWithData.schemaNode, iiWithData.mountPoint)
- }
-
- override readOperationalData(String identifier) {
- val iiWithData = identifier.toInstanceIdentifier
- var CompositeNode data = null;
- if (iiWithData.mountPoint !== null) {
- data = broker.readOperationalDataBehindMountPoint(iiWithData.mountPoint, iiWithData.getInstanceIdentifier)
- } else {
- data = broker.readOperationalData(iiWithData.getInstanceIdentifier);
- }
- return new StructuredData(data, iiWithData.schemaNode, iiWithData.mountPoint)
- }
-
- override updateConfigurationData(String identifier, CompositeNode payload) {
- val iiWithData = identifier.toInstanceIdentifier
- val value = normalizeNode(payload, iiWithData.schemaNode, iiWithData.mountPoint)
- var RpcResult<TransactionStatus> status = null
- if (iiWithData.mountPoint !== null) {
- status = broker.commitConfigurationDataPutBehindMountPoint(iiWithData.mountPoint,
- iiWithData.instanceIdentifier, value).get()
- } else {
- status = broker.commitConfigurationDataPut(iiWithData.instanceIdentifier, value).get();
- }
- switch status.result {
- case TransactionStatus.COMMITED: Response.status(OK).build
- default: Response.status(INTERNAL_SERVER_ERROR).build
- }
- }
-
- override createConfigurationData(String identifier, CompositeNode payload) {
- if (payload.namespace === null) {
- throw new ResponseException(BAD_REQUEST,
- "Data has bad format. Root element node must have namespace (XML format) or module name(JSON format)");
- }
- var InstanceIdWithSchemaNode iiWithData;
- var CompositeNode value;
- if (payload.representsMountPointRootData) { // payload represents mount point data and URI represents path to the mount point
- if (identifier.endsWithMountPoint) {
- throw new ResponseException(BAD_REQUEST,
- "URI has bad format. URI should be without \"" + ControllerContext.MOUNT + "\" for POST operation.");
- }
- val completIdentifier = identifier.addMountPointIdentifier
- iiWithData = completIdentifier.toInstanceIdentifier
- value = normalizeNode(payload, iiWithData.schemaNode, iiWithData.mountPoint)
- } else {
- val uncompleteInstIdWithData = identifier.toInstanceIdentifier
- val parentSchema = uncompleteInstIdWithData.schemaNode as DataNodeContainer
- val module = uncompleteInstIdWithData.mountPoint.findModule(payload)
- if (module === null) {
- throw new ResponseException(BAD_REQUEST, "Module was not found for \"" + payload.namespace + "\"")
- }
- val schemaNode = parentSchema.findInstanceDataChildByNameAndNamespace(payload.name, module.namespace)
- value = normalizeNode(payload, schemaNode, uncompleteInstIdWithData.mountPoint)
- iiWithData = uncompleteInstIdWithData.addLastIdentifierFromData(value, schemaNode)
- }
- var RpcResult<TransactionStatus> status = null
- if (iiWithData.mountPoint !== null) {
- status = broker.commitConfigurationDataPostBehindMountPoint(iiWithData.mountPoint,
- iiWithData.instanceIdentifier, value)?.get();
- } else {
- status = broker.commitConfigurationDataPost(iiWithData.instanceIdentifier, value)?.get();
- }
- if (status === null) {
- return Response.status(ACCEPTED).build
- }
- switch status.result {
- case TransactionStatus.COMMITED: Response.status(NO_CONTENT).build
- default: Response.status(INTERNAL_SERVER_ERROR).build
- }
- }
-
- override createConfigurationData(CompositeNode payload) {
- if (payload.namespace === null) {
- throw new ResponseException(BAD_REQUEST,
- "Data has bad format. Root element node must have namespace (XML format) or module name(JSON format)");
- }
- val module = findModule(null, payload)
- if (module === null) {
- throw new ResponseException(BAD_REQUEST,
- "Data has bad format. Root element node has incorrect namespace (XML format) or module name(JSON format)");
- }
- val schemaNode = module.findInstanceDataChildByNameAndNamespace(payload.name, module.namespace)
- val value = normalizeNode(payload, schemaNode, null)
- val iiWithData = addLastIdentifierFromData(null, value, schemaNode)
- var RpcResult<TransactionStatus> status = null
- if (iiWithData.mountPoint !== null) {
- status = broker.commitConfigurationDataPostBehindMountPoint(iiWithData.mountPoint,
- iiWithData.instanceIdentifier, value)?.get();
- } else {
- status = broker.commitConfigurationDataPost(iiWithData.instanceIdentifier, value)?.get();
- }
- if (status === null) {
- return Response.status(ACCEPTED).build
- }
- switch status.result {
- case TransactionStatus.COMMITED: Response.status(NO_CONTENT).build
- default: Response.status(INTERNAL_SERVER_ERROR).build
- }
- }
-
- override deleteConfigurationData(String identifier) {
- val iiWithData = identifier.toInstanceIdentifier
- var RpcResult<TransactionStatus> status = null
- if (iiWithData.mountPoint !== null) {
- status = broker.commitConfigurationDataDeleteBehindMountPoint(iiWithData.mountPoint,
- iiWithData.getInstanceIdentifier).get;
- } else {
- status = broker.commitConfigurationDataDelete(iiWithData.getInstanceIdentifier).get;
- }
- switch status.result {
- case TransactionStatus.COMMITED: Response.status(OK).build
- default: Response.status(INTERNAL_SERVER_ERROR).build
- }
- }
-
- override subscribeToStream(String identifier, UriInfo uriInfo) {
- val streamName = Notificator.createStreamNameFromUri(identifier)
- if (streamName.nullOrEmpty) {
- throw new ResponseException(BAD_REQUEST, "Stream name is empty.")
- }
- val listener = Notificator.getListenerFor(streamName);
- if (listener === null) {
- throw new ResponseException(BAD_REQUEST, "Stream was not found.")
- }
- broker.registerToListenDataChanges(listener)
- val uriBuilder = uriInfo.getAbsolutePathBuilder()
- val uriToWebsocketServer = uriBuilder.port(WebSocketServer.PORT).replacePath(streamName).build()
- return Response.status(OK).location(uriToWebsocketServer).build
- }
-
- private def dispatch URI namespace(CompositeNode data) {
- return data.nodeType.namespace
- }
-
- private def dispatch URI namespace(CompositeNodeWrapper data) {
- return data.namespace
- }
-
- private def dispatch String localName(CompositeNode data) {
- return data.nodeType.localName
- }
-
- private def dispatch String localName(CompositeNodeWrapper data) {
- return data.localName
- }
-
- private def dispatch Module findModule(MountInstance mountPoint, CompositeNode data) {
- if (mountPoint !== null) {
- return mountPoint.findModuleByNamespace(data.nodeType.namespace)
- } else {
- return findModuleByNamespace(data.nodeType.namespace)
- }
- }
-
- private def dispatch Module findModule(MountInstance mountPoint, CompositeNodeWrapper data) {
- Preconditions.checkNotNull(data.namespace)
- var Module module = null;
- if (mountPoint !== null) {
- module = mountPoint.findModuleByNamespace(data.namespace) // namespace from XML
- if (module === null) {
- module = mountPoint.findModuleByName(data.namespace.toString) // namespace (module name) from JSON
- }
- } else {
- module = data.namespace.findModuleByNamespace // namespace from XML
- if (module === null) {
- module = data.namespace.toString.findModuleByName // namespace (module name) from JSON
- }
- }
- return module
- }
-
- private def dispatch getName(CompositeNode data) {
- return data.nodeType.localName
- }
-
- private def dispatch getName(CompositeNodeWrapper data) {
- return data.localName
- }
-
- private def InstanceIdWithSchemaNode addLastIdentifierFromData(InstanceIdWithSchemaNode identifierWithSchemaNode,
- CompositeNode data, DataSchemaNode schemaOfData) {
- val iiOriginal = identifierWithSchemaNode?.instanceIdentifier
- var InstanceIdentifierBuilder iiBuilder = null
- if (iiOriginal === null) {
- iiBuilder = InstanceIdentifier.builder
- } else {
- iiBuilder = InstanceIdentifier.builder(iiOriginal)
- }
-
- if (schemaOfData instanceof ListSchemaNode) {
- iiBuilder.nodeWithKey(schemaOfData.QName, (schemaOfData as ListSchemaNode).resolveKeysFromData(data))
- } else {
- iiBuilder.node(schemaOfData.QName)
- }
- return new InstanceIdWithSchemaNode(iiBuilder.toInstance, schemaOfData, identifierWithSchemaNode?.mountPoint)
- }
-
- private def resolveKeysFromData(ListSchemaNode listNode, CompositeNode dataNode) {
- val keyValues = new HashMap<QName, Object>();
- for (key : listNode.keyDefinition) {
- val dataNodeKeyValueObject = dataNode.getSimpleNodesByName(key.localName)?.head?.value
- if (dataNodeKeyValueObject === null) {
- throw new ResponseException(BAD_REQUEST,
- "Data contains list \"" + dataNode.nodeType.localName + "\" which does not contain key: \"" +
- key.localName + "\"")
- }
- keyValues.put(key, dataNodeKeyValueObject);
- }
- return keyValues
- }
-
- private def endsWithMountPoint(String identifier) {
- return (identifier.endsWith(ControllerContext.MOUNT) || identifier.endsWith(ControllerContext.MOUNT + "/"))
- }
-
- private def representsMountPointRootData(CompositeNode data) {
- return ((data.namespace == SchemaContext.NAME.namespace || data.namespace == MOUNT_POINT_MODULE_NAME) &&
- data.localName == SchemaContext.NAME.localName)
- }
-
- private def addMountPointIdentifier(String identifier) {
- if (identifier.endsWith("/")) {
- return identifier + ControllerContext.MOUNT
- }
- return identifier + "/" + ControllerContext.MOUNT
- }
-
- private def CompositeNode normalizeNode(CompositeNode node, DataSchemaNode schema, MountInstance mountPoint) {
- if (schema === null) {
- throw new ResponseException(INTERNAL_SERVER_ERROR,
- "Data schema node was not found for " + node?.nodeType?.localName)
- }
- if (!(schema instanceof DataNodeContainer)) {
- throw new ResponseException(BAD_REQUEST, "Root element has to be container or list yang datatype.");
- }
- if (node instanceof CompositeNodeWrapper) {
- if ((node as CompositeNodeWrapper).changeAllowed) {
- try {
- normalizeNode(node as CompositeNodeWrapper, schema, null, mountPoint)
- } catch (NumberFormatException e) {
- throw new ResponseException(BAD_REQUEST,e.message)
- }
- }
- return (node as CompositeNodeWrapper).unwrap()
- }
- return node
- }
-
- private def void normalizeNode(NodeWrapper<?> nodeBuilder, DataSchemaNode schema, QName previousAugment,
- MountInstance mountPoint) {
- if (schema === null) {
- throw new ResponseException(BAD_REQUEST,
- "Data has bad format.\n\"" + nodeBuilder.localName + "\" does not exist in yang schema.");
- }
-
- var QName currentAugment;
- if (nodeBuilder.qname !== null) {
- currentAugment = previousAugment
- } else {
- currentAugment = normalizeNodeName(nodeBuilder, schema, previousAugment, mountPoint)
- if (nodeBuilder.qname === null) {
- throw new ResponseException(BAD_REQUEST,
- "Data has bad format.\nIf data is in XML format then namespace for \"" + nodeBuilder.localName +
- "\" should be \"" + schema.QName.namespace + "\".\n" +
- "If data is in JSON format then module name for \"" + nodeBuilder.localName +
- "\" should be corresponding to namespace \"" + schema.QName.namespace + "\".");
- }
- }
-
- if (nodeBuilder instanceof CompositeNodeWrapper) {
- val List<NodeWrapper<?>> children = (nodeBuilder as CompositeNodeWrapper).getValues
- for (child : children) {
- val potentialSchemaNodes = (schema as DataNodeContainer).findInstanceDataChildrenByName(child.localName)
- if (potentialSchemaNodes.size > 1 && child.namespace === null) {
- val StringBuilder namespacesOfPotentialModules = new StringBuilder;
- for (potentialSchemaNode : potentialSchemaNodes) {
- namespacesOfPotentialModules.append(" ").append(potentialSchemaNode.QName.namespace.toString).append("\n")
- }
- throw new ResponseException(BAD_REQUEST,
- "Node \"" + child.localName + "\" is added as augment from more than one module. "
- + "Therefore node must have namespace (XML format) or module name (JSON format)."
- + "\nThe node is added as augment from modules with namespaces:\n" + namespacesOfPotentialModules)
- }
- var rightNodeSchemaFound = false
- for (potentialSchemaNode : potentialSchemaNodes) {
- if (!rightNodeSchemaFound) {
- val potentialCurrentAugment = normalizeNodeName(child, potentialSchemaNode, currentAugment,
- mountPoint)
- if (child.qname !== null) {
- normalizeNode(child, potentialSchemaNode, potentialCurrentAugment, mountPoint)
- rightNodeSchemaFound = true
- }
- }
- }
- if (!rightNodeSchemaFound) {
- throw new ResponseException(BAD_REQUEST,
- "Schema node \"" + child.localName + "\" was not found in module.")
- }
- }
- if (schema instanceof ListSchemaNode) {
- val listKeys = (schema as ListSchemaNode).keyDefinition
- for (listKey : listKeys) {
- var foundKey = false
- for (child : children) {
- if (child.unwrap.nodeType.localName == listKey.localName) {
- foundKey = true;
- }
- }
- if (!foundKey) {
- throw new ResponseException(BAD_REQUEST,
- "Missing key in URI \"" + listKey.localName + "\" of list \"" + schema.QName.localName +
- "\"")
- }
- }
- }
- } else if (nodeBuilder instanceof SimpleNodeWrapper) {
- val simpleNode = (nodeBuilder as SimpleNodeWrapper)
- val value = simpleNode.value
- var inputValue = value;
-
- if (schema.typeDefinition instanceof IdentityrefTypeDefinition) {
- if (value instanceof String) {
- inputValue = new IdentityValuesDTO(nodeBuilder.namespace.toString, value as String, null,value as String);
- } // else value is already instance of IdentityValuesDTO
- }
-
- val outputValue = RestCodec.from(schema.typeDefinition, mountPoint)?.deserialize(inputValue);
- simpleNode.setValue(outputValue)
- } else if (nodeBuilder instanceof EmptyNodeWrapper) {
- val emptyNodeBuilder = nodeBuilder as EmptyNodeWrapper
- if (schema instanceof LeafSchemaNode) {
- emptyNodeBuilder.setComposite(false);
- } else if (schema instanceof ContainerSchemaNode) {
-
- // FIXME: Add presence check
- emptyNodeBuilder.setComposite(true);
- }
- }
- }
-
- private def dispatch TypeDefinition<?> typeDefinition(LeafSchemaNode node) {
- var baseType = node.type
- while (baseType.baseType !== null) {
- baseType = baseType.baseType;
- }
- baseType
- }
-
- private def dispatch TypeDefinition<?> typeDefinition(LeafListSchemaNode node) {
- var TypeDefinition<?> baseType = node.type
- while (baseType.baseType !== null) {
- baseType = baseType.baseType;
- }
- baseType
- }
-
- private def QName normalizeNodeName(NodeWrapper<?> nodeBuilder, DataSchemaNode schema, QName previousAugment,
- MountInstance mountPoint) {
- var validQName = schema.QName
- var currentAugment = previousAugment;
- if (schema.augmenting) {
- currentAugment = schema.QName
- } else if (previousAugment !== null && schema.QName.namespace !== previousAugment.namespace) {
- validQName = QName.create(currentAugment, schema.QName.localName);
- }
- var String moduleName = null;
- if (mountPoint === null) {
- moduleName = controllerContext.findModuleNameByNamespace(validQName.namespace);
- } else {
- moduleName = controllerContext.findModuleNameByNamespace(mountPoint, validQName.namespace)
- }
- if (nodeBuilder.namespace === null || nodeBuilder.namespace == validQName.namespace ||
- nodeBuilder.namespace.toString == moduleName || nodeBuilder.namespace == MOUNT_POINT_MODULE_NAME) {
- nodeBuilder.qname = validQName
- }
- return currentAugment
- }
-
-}
--- /dev/null
+/*
+ * Copyright (c) ${year} 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.sal.restconf.impl.test;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertSame;
+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 java.util.Map;
+import java.util.concurrent.Future;
+
+import javax.ws.rs.core.Response.Status;
+
+import org.junit.Before;
+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.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.ResponseException;
+import org.opendaylight.controller.sal.streams.listeners.ListenerAdapter;
+import org.opendaylight.controller.sal.streams.listeners.Notificator;
+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.data.api.CompositeNode;
+import org.opendaylight.yangtools.yang.data.api.InstanceIdentifier;
+
+import com.google.common.collect.ImmutableMap;
+import com.google.common.util.concurrent.Futures;
+
+/**
+ * Unit tests for BrokerFacade.
+ *
+ * @author Thomas Pantelis
+ */
+public class BrokerFacadeTest {
+
+ @Mock
+ DataBrokerService dataBroker;
+
+ @Mock
+ DataModificationTransaction mockTransaction;
+
+ @Mock
+ ConsumerSession mockConsumerSession;
+
+ @Mock
+ MountInstance mockMountInstance;
+
+ BrokerFacade brokerFacade = BrokerFacade.getInstance();
+
+ CompositeNode dataNode = TestUtils.readInputToCnSn( "/parts/ietf-interfaces_interfaces.xml",
+ XmlToCompositeNodeProvider.INSTANCE );
+
+ QName qname = QName.create( "node" );
+
+ InstanceIdentifier instanceID = InstanceIdentifier.builder().node( qname ).toInstance();
+
+ @Before
+ public void setUp() throws Exception {
+ MockitoAnnotations.initMocks( this );
+
+ brokerFacade.setDataService( dataBroker );
+ brokerFacade.setContext( mockConsumerSession );
+ }
+
+ @Test
+ public void testReadConfigurationData() {
+ when( dataBroker.readConfigurationData( instanceID ) ).thenReturn( dataNode );
+
+ CompositeNode actualNode = brokerFacade.readConfigurationData( instanceID );
+
+ assertSame( "readConfigurationData", dataNode, actualNode );
+ }
+
+ @Test
+ public void testReadConfigurationDataBehindMountPoint() {
+ when( mockMountInstance.readConfigurationData( instanceID ) ).thenReturn( dataNode );
+
+ CompositeNode actualNode = brokerFacade.readConfigurationDataBehindMountPoint(
+ mockMountInstance, instanceID );
+
+ assertSame( "readConfigurationDataBehindMountPoint", dataNode, actualNode );
+ }
+
+ @Test
+ public void testReadOperationalData() {
+ when( dataBroker.readOperationalData( instanceID ) ).thenReturn( dataNode );
+
+ CompositeNode actualNode = brokerFacade.readOperationalData( instanceID );
+
+ assertSame( "readOperationalData", dataNode, actualNode );
+ }
+
+ @Test
+ public void testReadOperationalDataBehindMountPoint() {
+ when( mockMountInstance.readOperationalData( instanceID ) ).thenReturn( dataNode );
+
+ CompositeNode actualNode = brokerFacade.readOperationalDataBehindMountPoint(
+ mockMountInstance, instanceID );
+
+ assertSame( "readOperationalDataBehindMountPoint", dataNode, actualNode );
+ }
+
+ @Test(expected=ResponseException.class)
+ public void testReadOperationalDataWithNoDataBroker() {
+ brokerFacade.setDataService( null );
+
+ brokerFacade.readOperationalData( instanceID );
+ }
+
+ @SuppressWarnings("unchecked")
+ @Test
+ public void testInvokeRpc() {
+ RpcResult<CompositeNode> expResult = mock( RpcResult.class );
+ Future<RpcResult<CompositeNode>> future = Futures.immediateFuture( expResult );
+ when( mockConsumerSession.rpc( qname, dataNode ) ).thenReturn( future );
+
+ RpcResult<CompositeNode> actualResult = brokerFacade.invokeRpc( qname, dataNode );
+
+ assertSame( "invokeRpc", expResult, actualResult );
+ }
+
+ @Test(expected=ResponseException.class)
+ public void testInvokeRpcWithException() {
+ Exception mockEx = new Exception( "mock" );
+ Future<RpcResult<CompositeNode>> future = Futures.immediateFailedFuture( mockEx );
+ when( mockConsumerSession.rpc( qname, dataNode ) ).thenReturn( future );
+
+ brokerFacade.invokeRpc( qname, dataNode );
+ }
+
+ @Test(expected=ResponseException.class)
+ public void testInvokeRpcWithNoConsumerSession() {
+ brokerFacade.setContext( null );
+
+ brokerFacade.invokeRpc( qname, dataNode );
+ }
+
+ @Test
+ public void testCommitConfigurationDataPut() {
+ Future<RpcResult<TransactionStatus>> expFuture = Futures.immediateFuture( null );
+
+ when( dataBroker.beginTransaction() ).thenReturn( mockTransaction );
+ mockTransaction.putConfigurationData( instanceID, dataNode );
+ when( mockTransaction.commit() ).thenReturn( expFuture );
+
+ Future<RpcResult<TransactionStatus>> actualFuture =
+ brokerFacade.commitConfigurationDataPut( instanceID, dataNode );
+
+ assertSame( "invokeRpc", expFuture, actualFuture );
+
+ InOrder inOrder = inOrder( dataBroker, mockTransaction );
+ inOrder.verify( dataBroker ).beginTransaction();
+ inOrder.verify( mockTransaction ).putConfigurationData( instanceID, dataNode );
+ inOrder.verify( mockTransaction ).commit();
+ }
+
+ @Test
+ public void testCommitConfigurationDataPutBehindMountPoint() {
+ Future<RpcResult<TransactionStatus>> expFuture = Futures.immediateFuture( null );
+
+ when( mockMountInstance.beginTransaction() ).thenReturn( mockTransaction );
+ mockTransaction.putConfigurationData( instanceID, dataNode );
+ when( mockTransaction.commit() ).thenReturn( expFuture );
+
+ Future<RpcResult<TransactionStatus>> actualFuture =
+ brokerFacade.commitConfigurationDataPutBehindMountPoint(
+ mockMountInstance, instanceID, dataNode );
+
+ assertSame( "invokeRpc", expFuture, actualFuture );
+
+ InOrder inOrder = inOrder( mockMountInstance, mockTransaction );
+ inOrder.verify( mockMountInstance ).beginTransaction();
+ inOrder.verify( mockTransaction ).putConfigurationData( instanceID, dataNode );
+ inOrder.verify( mockTransaction ).commit();
+ }
+
+ @Test
+ public void testCommitConfigurationDataPost() {
+ Future<RpcResult<TransactionStatus>> expFuture = Futures.immediateFuture( null );
+
+ Map<InstanceIdentifier, CompositeNode> nodeMap =
+ new ImmutableMap.Builder<InstanceIdentifier,CompositeNode>()
+ .put( instanceID, dataNode ).build();
+
+ when( dataBroker.beginTransaction() ).thenReturn( mockTransaction );
+ mockTransaction.putConfigurationData( instanceID, dataNode );
+ when( mockTransaction.getCreatedConfigurationData() ).thenReturn( nodeMap );
+ when( mockTransaction.commit() ).thenReturn( expFuture );
+
+ Future<RpcResult<TransactionStatus>> actualFuture =
+ brokerFacade.commitConfigurationDataPost( instanceID, dataNode );
+
+ assertSame( "commitConfigurationDataPut", expFuture, actualFuture );
+
+ InOrder inOrder = inOrder( dataBroker, mockTransaction );
+ inOrder.verify( dataBroker ).beginTransaction();
+ inOrder.verify( mockTransaction ).putConfigurationData( instanceID, dataNode );
+ inOrder.verify( mockTransaction ).commit();
+ }
+
+ @Test(expected=ResponseException.class)
+ public void testCommitConfigurationDataPostAlreadyExists() {
+ when( dataBroker.beginTransaction() ).thenReturn( mockTransaction );
+ mockTransaction.putConfigurationData( instanceID, dataNode );
+ when ( mockTransaction.readConfigurationData( instanceID ) )
+ .thenReturn( dataNode );
+ try {
+ brokerFacade.commitConfigurationDataPost( instanceID, dataNode );
+ } catch (ResponseException e) {
+ assertEquals("Unexpect Exception Status -> "
+ + "http://tools.ietf.org/html/draft-bierman-netconf-restconf-03#page-48",
+ (e.getResponse().getStatus()), Status.CONFLICT.getStatusCode());
+ throw e;
+ }
+ }
+
+ @Test
+ public void testCommitConfigurationDataPostBehindMountPoint() {
+ Future<RpcResult<TransactionStatus>> expFuture = Futures.immediateFuture( null );
+
+ Map<InstanceIdentifier, CompositeNode> nodeMap =
+ new ImmutableMap.Builder<InstanceIdentifier,CompositeNode>()
+ .put( instanceID, dataNode ).build();
+
+ when( mockMountInstance.beginTransaction() ).thenReturn( mockTransaction );
+ mockTransaction.putConfigurationData( instanceID, dataNode );
+ when( mockTransaction.getCreatedConfigurationData() ).thenReturn( nodeMap );
+ when( mockTransaction.commit() ).thenReturn( expFuture );
+
+ Future<RpcResult<TransactionStatus>> 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=ResponseException.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 );
+ } catch (ResponseException e) {
+ assertEquals("Unexpect Exception Status -> "
+ + "http://tools.ietf.org/html/draft-bierman-netconf-restconf-03#page-48",
+ e.getResponse().getStatus(), Status.CONFLICT.getStatusCode());
+ throw e;
+ }
+ }
+
+ @Test
+ public void testCommitConfigurationDataDelete() {
+ Future<RpcResult<TransactionStatus>> expFuture = Futures.immediateFuture( null );
+
+ when( dataBroker.beginTransaction() ).thenReturn( mockTransaction );
+ mockTransaction.removeConfigurationData( instanceID );
+ when( mockTransaction.commit() ).thenReturn( expFuture );
+
+ Future<RpcResult<TransactionStatus>> 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<RpcResult<TransactionStatus>> expFuture = Futures.immediateFuture( null );
+
+ when( mockMountInstance.beginTransaction() ).thenReturn( mockTransaction );
+ mockTransaction.removeConfigurationData( instanceID );
+ when( mockTransaction.commit() ).thenReturn( expFuture );
+
+ Future<RpcResult<TransactionStatus>> 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();
+ }
+
+ @SuppressWarnings("unchecked")
+ @Test
+ public void testRegisterToListenDataChanges() {
+ ListenerAdapter listener = Notificator.createListener( instanceID, "stream" );
+
+ ListenerRegistration<DataChangeListener> mockRegistration = mock( ListenerRegistration.class );
+ when( dataBroker.registerDataChangeListener( instanceID, listener ) )
+ .thenReturn( mockRegistration );
+
+ brokerFacade.registerToListenDataChanges( listener );
+
+ verify( dataBroker ).registerDataChangeListener( instanceID, listener );
+
+ assertEquals( "isListening", true, listener.isListening() );
+
+ brokerFacade.registerToListenDataChanges( listener );
+ verifyNoMoreInteractions( dataBroker );
+ }
+}
response = target(uri).request("application/yang.api+xml").get();
responseBody = response.readEntity(String.class);
assertNotNull(responseBody);
- assertTrue(responseBody.contains("<streams xmlns=\"urn:ietf:params:xml:ns:yang:ietf-restconf\"/>"));
+ assertTrue(responseBody.contains("<streams xmlns=\"urn:ietf:params:xml:ns:yang:ietf-restconf\""));
}
// /modules/module
import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.topology.Link;
import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
-import java.util.*;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Set;
/**
* InventoryService provides functions related to Nodes & NodeConnectors.
import org.opendaylight.controller.sal.utils.HexEncode;
import org.opendaylight.controller.sal.utils.NetUtils;
import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.yang.types.rev100924.MacAddress;
-import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.*;
+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.Node;
import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.nodes.NodeKey;
import org.opendaylight.yang.gen.v1.urn.opendaylight.l2.address.tracker.rev140402.l2.addresses.L2Address;
<plugin>
<groupId>org.apache.felix</groupId>
<artifactId>maven-bundle-plugin</artifactId>
- <configuration>
- <instructions>
- <Export-Package>org.opendaylight.controller.sample.toaster.provider.api,
- org.opendaylight.controller.config.yang.toaster-consumer,</Export-Package>
- <Import-Package>*</Import-Package>
- </instructions>
- </configuration>
</plugin>
<plugin>
<groupId>org.opendaylight.yangtools</groupId>
--- /dev/null
+/**
+* Generated file
+
+* Generated from: yang module name: toaster-consumer-impl yang module local name: toaster-consumer-impl
+* Generated by: org.opendaylight.controller.config.yangjmxgenerator.plugin.JMXGenerator
+* Generated at: Wed Feb 05 11:31:30 CET 2014
+*
+* Do not modify this file unless it is present under src/main directory
+*/
+package org.opendaylight.controller.config.yang.config.kitchen_service.impl;
+
+import org.opendaylight.controller.config.yang.config.kitchen_service.impl.AbstractKitchenServiceModule;
+import org.opendaylight.controller.sample.kitchen.api.EggsType;
+import org.opendaylight.controller.sample.kitchen.api.KitchenService;
+import org.opendaylight.controller.sample.kitchen.impl.KitchenServiceImpl;
+import org.opendaylight.yang.gen.v1.http.netconfcentral.org.ns.toaster.rev091120.ToastType;
+import org.opendaylight.yang.gen.v1.http.netconfcentral.org.ns.toaster.rev091120.ToasterService;
+import org.opendaylight.yangtools.concepts.Registration;
+import org.opendaylight.yangtools.yang.binding.NotificationListener;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+*
+*/
+public final class KitchenServiceModule extends AbstractKitchenServiceModule {
+ private static final Logger log = LoggerFactory.getLogger(KitchenServiceModule.class);
+
+ public KitchenServiceModule(org.opendaylight.controller.config.api.ModuleIdentifier identifier, org.opendaylight.controller.config.api.DependencyResolver dependencyResolver) {
+ super(identifier, dependencyResolver);
+ }
+
+ public KitchenServiceModule(org.opendaylight.controller.config.api.ModuleIdentifier identifier, org.opendaylight.controller.config.api.DependencyResolver dependencyResolver,
+ KitchenServiceModule oldModule, java.lang.AutoCloseable oldInstance) {
+
+ super(identifier, dependencyResolver, oldModule, oldInstance);
+ }
+
+ @Override
+ protected void customValidation(){
+ // No need to validate dependencies, since all dependencies have mandatory true flag in yang
+ // config-subsystem will perform the validation
+ }
+
+ @Override
+ public java.lang.AutoCloseable createInstance() {
+ ToasterService toasterService = getRpcRegistryDependency().getRpcService(ToasterService.class);
+
+ final KitchenServiceImpl kitchenService = new KitchenServiceImpl(toasterService);
+
+ final Registration<NotificationListener> toasterListenerReg =
+ getNotificationServiceDependency().registerNotificationListener( kitchenService );
+
+ final KitchenServiceRuntimeRegistration runtimeReg =
+ getRootRuntimeBeanRegistratorWrapper().register( kitchenService );
+
+ final class AutoCloseableKitchenService implements KitchenService, AutoCloseable {
+
+ @Override
+ public void close() throws Exception {
+ toasterListenerReg.close();
+ runtimeReg.close();
+ log.info("Toaster consumer (instance {}) torn down.", this);
+ }
+
+ @Override
+ public boolean makeBreakfast( EggsType eggs, Class<? extends ToastType> toast, int toastDoneness ) {
+ return kitchenService.makeBreakfast( eggs, toast, toastDoneness );
+ }
+ }
+
+ AutoCloseable ret = new AutoCloseableKitchenService();
+ log.info("KitchenService (instance {}) initialized.", ret );
+ return ret;
+ }
+}
*
* Do not modify this file unless it is present under src/main directory
*/
-package org.opendaylight.controller.config.yang.config.toaster_consumer.impl;
+package org.opendaylight.controller.config.yang.config.kitchen_service.impl;
+
+import org.opendaylight.controller.config.yang.config.kitchen_service.impl.AbstractKitchenServiceModuleFactory;
/**
*
*/
-public class ToasterConsumerModuleFactory extends org.opendaylight.controller.config.yang.config.toaster_consumer.impl.AbstractToasterConsumerModuleFactory
+public class KitchenServiceModuleFactory extends AbstractKitchenServiceModuleFactory
{
+++ /dev/null
-/**
-* Generated file
-
-* Generated from: yang module name: toaster-consumer-impl yang module local name: toaster-consumer-impl
-* Generated by: org.opendaylight.controller.config.yangjmxgenerator.plugin.JMXGenerator
-* Generated at: Wed Feb 05 11:31:30 CET 2014
-*
-* Do not modify this file unless it is present under src/main directory
-*/
-package org.opendaylight.controller.config.yang.config.toaster_consumer.impl;
-
-import org.opendaylight.controller.sal.binding.api.NotificationListener;
-import org.opendaylight.controller.sample.toaster.provider.api.ToastConsumer;
-import org.opendaylight.controller.sample.toaster.provider.impl.ToastConsumerImpl;
-import org.opendaylight.yang.gen.v1.http.netconfcentral.org.ns.toaster.rev091120.ToastDone;
-import org.opendaylight.yang.gen.v1.http.netconfcentral.org.ns.toaster.rev091120.ToastType;
-import org.opendaylight.yang.gen.v1.http.netconfcentral.org.ns.toaster.rev091120.ToasterService;
-import org.opendaylight.yangtools.concepts.Registration;
-
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-
-/**
-*
-*/
-public final class ToasterConsumerModule extends org.opendaylight.controller.config.yang.config.toaster_consumer.impl.AbstractToasterConsumerModule
- {
- private static final Logger log = LoggerFactory.getLogger(ToasterConsumerModule.class);
-
- public ToasterConsumerModule(org.opendaylight.controller.config.api.ModuleIdentifier identifier, org.opendaylight.controller.config.api.DependencyResolver dependencyResolver) {
- super(identifier, dependencyResolver);
- }
-
- public ToasterConsumerModule(org.opendaylight.controller.config.api.ModuleIdentifier identifier, org.opendaylight.controller.config.api.DependencyResolver dependencyResolver,
- ToasterConsumerModule oldModule, java.lang.AutoCloseable oldInstance) {
-
- super(identifier, dependencyResolver, oldModule, oldInstance);
- }
-
- @Override
- protected void customValidation(){
- // No need to validate dependencies, since all dependencies have mandatory true flag in yang
- // config-subsystem will perform the validation
- }
-
- @Override
- public java.lang.AutoCloseable createInstance() {
- ToasterService toasterService = getRpcRegistryDependency().getRpcService(ToasterService.class);
-
- final ToastConsumerImpl consumer = new ToastConsumerImpl(toasterService);
- final Registration<NotificationListener<ToastDone>> notificationRegistration = getNotificationServiceDependency()
- .registerNotificationListener(ToastDone.class, consumer);
-
- final ToasterConsumerRuntimeRegistration runtimeRegistration = getRootRuntimeBeanRegistratorWrapper().register(consumer);
-
- final class AutoCloseableToastConsumer implements AutoCloseable, ToastConsumer {
-
- @Override
- public void close() throws Exception {
- runtimeRegistration.close();
- notificationRegistration.close();
- log.info("Toaster consumer (instance {}) torn down.", this);
- }
-
- @Override
- public boolean createToast(Class<? extends ToastType> type, int doneness) {
- return consumer.createToast(type, doneness);
- }
- }
-
- AutoCloseable ret = new AutoCloseableToastConsumer();
- log.info("Toaster consumer (instance {}) initialized.", ret);
- return ret;
- }
-}
--- /dev/null
+package org.opendaylight.controller.sample.kitchen.api;
+
+public enum EggsType {
+ SCRAMBLED,
+ OVER_EASY,
+ POACHED
+}
--- /dev/null
+package org.opendaylight.controller.sample.kitchen.api;
+
+import org.opendaylight.yang.gen.v1.http.netconfcentral.org.ns.toaster.rev091120.ToastType;
+
+public interface KitchenService {
+ boolean makeBreakfast( EggsType eggs, Class<? extends ToastType> toast, int toastDoneness );
+}
--- /dev/null
+package org.opendaylight.controller.sample.kitchen.impl;
+
+import java.util.concurrent.ExecutionException;
+
+import org.opendaylight.controller.config.yang.config.kitchen_service.impl.KitchenServiceRuntimeMXBean;
+import org.opendaylight.controller.sample.kitchen.api.EggsType;
+import org.opendaylight.controller.sample.kitchen.api.KitchenService;
+import org.opendaylight.yang.gen.v1.http.netconfcentral.org.ns.toaster.rev091120.MakeToastInputBuilder;
+import org.opendaylight.yang.gen.v1.http.netconfcentral.org.ns.toaster.rev091120.ToastType;
+import org.opendaylight.yang.gen.v1.http.netconfcentral.org.ns.toaster.rev091120.ToasterListener;
+import org.opendaylight.yang.gen.v1.http.netconfcentral.org.ns.toaster.rev091120.ToasterOutOfBread;
+import org.opendaylight.yang.gen.v1.http.netconfcentral.org.ns.toaster.rev091120.ToasterRestocked;
+import org.opendaylight.yang.gen.v1.http.netconfcentral.org.ns.toaster.rev091120.ToasterService;
+import org.opendaylight.yang.gen.v1.http.netconfcentral.org.ns.toaster.rev091120.WheatBread;
+import org.opendaylight.yangtools.yang.common.RpcResult;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+public class KitchenServiceImpl implements KitchenService, KitchenServiceRuntimeMXBean, ToasterListener {
+
+ private static final Logger log = LoggerFactory.getLogger( KitchenServiceImpl.class );
+
+ private final ToasterService toaster;
+
+ private volatile boolean toasterOutOfBread;
+
+ public KitchenServiceImpl(ToasterService toaster) {
+ this.toaster = toaster;
+ }
+
+ @Override
+ public boolean makeBreakfast( EggsType eggs, Class<? extends ToastType> toast, int toastDoneness ) {
+
+ if( toasterOutOfBread )
+ {
+ log.info( "We're out of toast but we can make eggs" );
+ return true;
+ }
+
+ // Access the ToasterService to make the toast.
+ // We don't actually make the eggs for this example - sorry.
+ MakeToastInputBuilder toastInput = new MakeToastInputBuilder();
+ toastInput.setToasterDoneness( (long) toastDoneness);
+ toastInput.setToasterToastType( toast );
+
+ try {
+ RpcResult<Void> result = toaster.makeToast( toastInput.build() ).get();
+
+ if( result.isSuccessful() ) {
+ log.info( "makeToast succeeded" );
+ } else {
+ log.warn( "makeToast failed: " + result.getErrors() );
+ }
+
+ return result.isSuccessful();
+ } catch( InterruptedException | ExecutionException e ) {
+ log.warn( "Error occurred during toast creation" );
+ }
+ return false;
+ }
+
+ @Override
+ public Boolean makeScrambledWithWheat() {
+ return makeBreakfast( EggsType.SCRAMBLED, WheatBread.class, 2 );
+ }
+
+ /**
+ * Implemented from the ToasterListener interface.
+ */
+ @Override
+ public void onToasterOutOfBread( ToasterOutOfBread notification ) {
+ log.info( "ToasterOutOfBread notification" );
+ toasterOutOfBread = true;
+ }
+
+ /**
+ * Implemented from the ToasterListener interface.
+ */
+ @Override
+ public void onToasterRestocked( ToasterRestocked notification ) {
+ log.info( "ToasterRestocked notification - amountOfBread: " + notification.getAmountOfBread() );
+ toasterOutOfBread = false;
+ }
+}
+++ /dev/null
-/*
- * 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.sample.toaster.provider.api;
-
-import org.opendaylight.yang.gen.v1.http.netconfcentral.org.ns.toaster.rev091120.ToastType;
-
-public interface ToastConsumer {
-
- boolean createToast(Class<? extends ToastType> type,int doneness);
-
-}
+++ /dev/null
-/*
- * 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.sample.toaster.provider.impl;
-
-import java.util.concurrent.ExecutionException;
-
-import org.opendaylight.controller.config.yang.config.toaster_consumer.impl.ToasterConsumerRuntimeMXBean;
-import org.opendaylight.controller.sal.binding.api.NotificationListener;
-import org.opendaylight.controller.sample.toaster.provider.api.ToastConsumer;
-import org.opendaylight.yang.gen.v1.http.netconfcentral.org.ns.toaster.rev091120.*;
-import org.opendaylight.yangtools.yang.common.RpcResult;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-
-public class ToastConsumerImpl implements
- ToastConsumer,
- NotificationListener<ToastDone>,ToasterConsumerRuntimeMXBean {
-
- private static final Logger log = LoggerFactory.getLogger(ToastConsumerImpl.class);
-
- private ToasterService toaster;
-
- public ToastConsumerImpl(ToasterService toaster) {
- this.toaster = toaster;
- }
-
- @Override
- public boolean createToast(Class<? extends ToastType> type, int doneness) {
- MakeToastInputBuilder toastInput = new MakeToastInputBuilder();
- toastInput.setToasterDoneness((long) doneness);
- toastInput.setToasterToastType(type);
-
- try {
- RpcResult<Void> result = toaster.makeToast(toastInput.build()).get();
-
- if (result.isSuccessful()) {
- log.trace("Toast was successfully finished");
- } else {
- log.warn("Toast was not successfully finished");
- }
- return result.isSuccessful();
- } catch (InterruptedException | ExecutionException e) {
- log.warn("Error occurred during toast creation");
- }
- return false;
-
- }
-
- @Override
- public void onNotification(ToastDone notification) {
- log.trace("ToastDone Notification Received: {} ",notification.getToastStatus());
- }
-
- @Override
- public Boolean makeHashBrownToast(Integer doneness) {
- return createToast(HashBrown.class, doneness);
- }
-}
// vi: set smarttab et sw=4 tabstop=4:
-module toaster-consumer-impl {
+module kitchen-service-impl {
yang-version 1;
- namespace "urn:opendaylight:params:xml:ns:yang:controller:config:toaster-consumer:impl";
- prefix "toaster-consumer-impl";
+ namespace "urn:opendaylight:params:xml:ns:yang:controller:config:kitchen-service:impl";
+ prefix "kitchen-service-impl";
import config { prefix config; revision-date 2013-04-05; }
import rpc-context { prefix rpcx; revision-date 2013-06-17; }
- import toaster-consumer { prefix toaster-consumer; revision-date 2014-01-31; }
import opendaylight-md-sal-binding { prefix mdsal; revision-date 2013-10-28; }
description
"This module contains the base YANG definitions for
- toaster-consumer impl implementation.";
+ kitchen-service impl implementation.";
revision "2014-01-31" {
description
"Initial revision.";
}
- // This is the definition of a service implementation
- identity toaster-consumer-impl {
+ // This is the definition of kitchen service interface identity.
+ identity kitchen-service {
+ base "config:service-type";
+ config:java-class "org.opendaylight.controller.sample.kitchen.api.KitchenService";
+ }
+
+ // This is the definition of kitchen service implementation module identity.
+ identity kitchen-service-impl {
base config:module-type;
- config:provided-service toaster-consumer:toaster-consumer;
- config:java-name-prefix ToasterConsumer;
+ config:provided-service kitchen-service;
+ config:java-name-prefix KitchenService;
}
augment "/config:modules/config:module/config:configuration" {
- case toaster-consumer-impl {
- when "/config:modules/config:module/config:type = 'toaster-consumer-impl'";
+ case kitchen-service-impl {
+ when "/config:modules/config:module/config:type = 'kitchen-service-impl'";
container rpc-registry {
uses config:service-ref {
}
}
}
-
}
}
-
+
augment "/config:modules/config:module/config:state" {
- case toaster-consumer-impl {
- when "/config:modules/config:module/config:type = 'toaster-consumer-impl'";
- rpcx:rpc-context-instance "make-hash-brown-toast-rpc";
+ case kitchen-service-impl {
+ when "/config:modules/config:module/config:type = 'kitchen-service-impl'";
+
+ rpcx:rpc-context-instance "make-scrambled-with-wheat-rpc";
}
}
- identity make-hash-brown-toast-rpc;
+ identity make-scrambled-with-wheat-rpc;
- rpc make-hash-brown-toast {
+ rpc make-scrambled-with-wheat {
+ description
+ "Shortcut JMX call to make breakfast with scrambled eggs and wheat toast for testing.";
+
input {
uses rpcx:rpc-context-ref {
refine context-instance {
- rpcx:rpc-context-instance make-hash-brown-toast-rpc;
+ rpcx:rpc-context-instance make-scrambled-with-wheat-rpc;
}
}
- leaf doneness {
- type uint16;
- }
}
+
output {
leaf result {
type boolean;
+++ /dev/null
-// vi: set smarttab et sw=4 tabstop=4:
-module toaster-consumer {
-
- yang-version 1;
- namespace "urn:opendaylight:params:xml:ns:yang:controller:config:toaster-consumer";
- prefix "toaster-consumer";
-
- import config { prefix config; revision-date 2013-04-05; }
-
- description
- "This module contains the base YANG definitions for
- toaster-consumer services.";
-
- revision "2014-01-31" {
- description
- "Initial revision.";
- }
-
- // This is the definition of a service
- identity toaster-consumer {
-
- base "config:service-type";
-
- config:java-class "org.opendaylight.controller.sample.toaster.provider.api.ToastConsumer";
- }
-}
\ No newline at end of file
import org.junit.Assert;
import org.junit.Test;
import org.junit.runner.RunWith;
-import org.opendaylight.controller.sample.toaster.provider.api.ToastConsumer;
+import org.opendaylight.controller.sample.kitchen.api.EggsType;
+import org.opendaylight.controller.sample.kitchen.api.KitchenService;
import org.opendaylight.yang.gen.v1.http.netconfcentral.org.ns.toaster.rev091120.HashBrown;
import org.opendaylight.yang.gen.v1.http.netconfcentral.org.ns.toaster.rev091120.WhiteBread;
import org.ops4j.pax.exam.Configuration;
import javax.inject.Inject;
import javax.management.MBeanServer;
import javax.management.ObjectName;
+
import java.lang.management.ManagementFactory;
import static org.junit.Assert.assertEquals;
@Inject
@Filter(timeout=60*1000)
- ToastConsumer toastConsumer;
+ KitchenService kitchenService;
@Configuration
public Option[] config() {
public void testToaster() throws Exception {
MBeanServer platformMBeanServer = ManagementFactory.getPlatformMBeanServer();
- ObjectName consumerOn = new ObjectName("org.opendaylight.controller:instanceName=toaster-consumer-impl,type=RuntimeBean,moduleFactoryName=toaster-consumer-impl");
ObjectName providerOn = new ObjectName("org.opendaylight.controller:instanceName=toaster-provider-impl,type=RuntimeBean,moduleFactoryName=toaster-provider-impl");
long toastsMade = (long) platformMBeanServer.getAttribute(providerOn, "ToastsMade");
boolean toasts = true;
// Make toasts using OSGi service
- toasts &= toastConsumer.createToast(HashBrown.class, 4);
- toasts &= toastConsumer.createToast(WhiteBread.class, 8);
-
- // Make toast using JMX/config-subsystem
- toasts &= (Boolean)platformMBeanServer.invoke(consumerOn, "makeHashBrownToast", new Object[]{4}, new String[]{Integer.class.getName()});
+ toasts &= kitchenService.makeBreakfast( EggsType.SCRAMBLED, HashBrown.class, 4);
+ toasts &= kitchenService.makeBreakfast( EggsType.POACHED, WhiteBread.class, 8 );
- Assert.assertTrue("Not all toasts done by " + toastConsumer, toasts);
+ Assert.assertTrue("Not all toasts done by " + kitchenService, toasts);
// Verify toasts made count on provider via JMX/config-subsystem
toastsMade = (long) platformMBeanServer.getAttribute(providerOn, "ToastsMade");
- assertEquals(3, toastsMade);
+ assertEquals(2, toastsMade);
}
}
<snapshots>
<snapshot>
<required-capabilities>
- <capability>urn:opendaylight:l2:types?module=opendaylight-l2-types&revision=2013-08-27</capability>
+ <!-- <capability>urn:opendaylight:l2:types?module=opendaylight-l2-types&revision=2013-08-27</capability>-->
<capability>
urn:opendaylight:params:xml:ns:yang:controller:md:sal:binding?module=opendaylight-md-sal-binding&revision=2013-10-28
</capability>
urn:opendaylight:params:xml:ns:yang:controller:md:sal:dom:impl?module=opendaylight-sal-dom-broker-impl&revision=2013-10-28
</capability>
<capability>urn:opendaylight:params:xml:ns:yang:controller:logback:config?module=config-logging&revision=2013-07-16</capability>
- <capability>urn:opendaylight:yang:extension:yang-ext?module=yang-ext&revision=2013-07-09
- </capability>
+ <!-- <capability>urn:opendaylight:yang:extension:yang-ext?module=yang-ext&revision=2013-07-09</capability>-->
<capability>
urn:opendaylight:params:xml:ns:yang:controller:md:sal:common?module=opendaylight-md-sal-common&revision=2013-10-28
</capability>
<capability>http://netconfcentral.org/ns/toaster?module=toaster&revision=2009-11-20</capability>
- <capability>urn:opendaylight:params:xml:ns:yang:controller:config:toaster-consumer?module=toaster-consumer&revision=2014-01-31</capability>
- <capability>urn:opendaylight:params:xml:ns:yang:controller:config:toaster-consumer:impl?module=toaster-consumer-impl&revision=2014-01-31</capability>
- <capability>urn:opendaylight:params:xml:ns:yang:controller:config:toaster-provider?module=toaster-provider&revision=2014-01-31</capability>
+ <capability>urn:opendaylight:params:xml:ns:yang:controller:config:kitchen-service:impl?module=kitchen-service-impl&revision=2014-01-31</capability>
<capability>urn:opendaylight:params:xml:ns:yang:controller:config:toaster-provider:impl?module=toaster-provider-impl&revision=2014-01-31</capability>
</required-capabilities>
<name>binding-rpc-broker</name>
</rpc-registry>
+ <data-broker>
+ <type xmlns:binding="urn:opendaylight:params:xml:ns:yang:controller:md:sal:binding">binding:binding-data-broker</type>
+ <name>ref_binding-data-broker</name>
+ </data-broker>
+
<notification-service>
<type xmlns:binding="urn:opendaylight:params:xml:ns:yang:controller:md:sal:binding">
binding:binding-notification-service
</module>
<module>
- <type xmlns:prefix="urn:opendaylight:params:xml:ns:yang:controller:config:toaster-consumer:impl">
- prefix:toaster-consumer-impl
+ <type xmlns:prefix="urn:opendaylight:params:xml:ns:yang:controller:config:kitchen-service:impl">
+ prefix:kitchen-service-impl
</type>
- <name>toaster-consumer-impl</name>
+ <name>kitchen-service-impl</name>
<rpc-registry>
<type xmlns:binding="urn:opendaylight:params:xml:ns:yang:controller:md:sal:binding">binding:binding-rpc-registry</type>
</modules>
<services xmlns="urn:opendaylight:params:xml:ns:yang:controller:config">
+ <service>
+ <type xmlns:kitchen="urn:opendaylight:params:xml:ns:yang:controller:config:kitchen-service:impl">
+ kitchen:kitchen-service
+ </type>
+ <instance>
+ <name>kitchen-service</name>
+ <provider>/modules/module[type='kitchen-service-impl'][name='kitchen-service-impl']</provider>
+ </instance>
+ </service>
<service>
<type xmlns:dom="urn:opendaylight:params:xml:ns:yang:controller:md:sal:dom">
dom:schema-service
package org.opendaylight.controller.config.yang.config.toaster_provider.impl;
import org.opendaylight.controller.sal.binding.api.BindingAwareBroker;
+import org.opendaylight.controller.sal.binding.api.data.DataChangeListener;
+import org.opendaylight.controller.sal.binding.api.data.DataProviderService;
import org.opendaylight.controller.sample.toaster.provider.OpendaylightToaster;
-import org.opendaylight.yang.gen.v1.http.netconfcentral.org.ns.toaster.rev091120.Toaster;
-import org.opendaylight.yang.gen.v1.http.netconfcentral.org.ns.toaster.rev091120.ToasterData;
import org.opendaylight.yang.gen.v1.http.netconfcentral.org.ns.toaster.rev091120.ToasterService;
+import org.opendaylight.yangtools.concepts.ListenerRegistration;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
// Register to md-sal
opendaylightToaster.setNotificationProvider(getNotificationServiceDependency());
- opendaylightToaster.setDataProvider(getDataBrokerDependency());
+
+ DataProviderService dataBrokerService = getDataBrokerDependency();
+ opendaylightToaster.setDataProvider(dataBrokerService);
+
+ final ListenerRegistration<DataChangeListener> dataChangeListenerRegistration =
+ dataBrokerService.registerDataChangeListener( OpendaylightToaster.TOASTER_IID, opendaylightToaster );
+
final BindingAwareBroker.RpcRegistration<ToasterService> rpcRegistration = getRpcRegistryDependency()
.addRpcImplementation(ToasterService.class, opendaylightToaster);
// Wrap toaster as AutoCloseable and close registrations to md-sal at
// close()
- final class AutoCloseableToaster implements AutoCloseable, ToasterData {
+ final class AutoCloseableToaster implements AutoCloseable {
@Override
public void close() throws Exception {
+ dataChangeListenerRegistration.close();
rpcRegistration.close();
runtimeReg.close();
opendaylightToaster.close();
log.info("Toaster provider (instance {}) torn down.", this);
}
-
- @Override
- public Toaster getToaster() {
- return opendaylightToaster.getToaster();
- }
}
AutoCloseable ret = new AutoCloseableToaster();
*/
package org.opendaylight.controller.sample.toaster.provider;
+import java.util.Arrays;
import java.util.Collections;
import java.util.concurrent.Callable;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.atomic.AtomicLong;
import org.opendaylight.controller.config.yang.config.toaster_provider.impl.ToasterProviderRuntimeMXBean;
+import org.opendaylight.controller.md.sal.common.api.data.DataChangeEvent;
import org.opendaylight.controller.sal.binding.api.NotificationProviderService;
import org.opendaylight.controller.sal.binding.api.data.DataBrokerService;
import org.opendaylight.controller.sal.binding.api.data.DataModificationTransaction;
+import org.opendaylight.controller.sal.common.util.RpcErrors;
import org.opendaylight.controller.sal.common.util.Rpcs;
import org.opendaylight.yang.gen.v1.http.netconfcentral.org.ns.toaster.rev091120.DisplayString;
import org.opendaylight.yang.gen.v1.http.netconfcentral.org.ns.toaster.rev091120.MakeToastInput;
-import org.opendaylight.yang.gen.v1.http.netconfcentral.org.ns.toaster.rev091120.ToastDone.ToastStatus;
-import org.opendaylight.yang.gen.v1.http.netconfcentral.org.ns.toaster.rev091120.ToastDoneBuilder;
import org.opendaylight.yang.gen.v1.http.netconfcentral.org.ns.toaster.rev091120.Toaster;
import org.opendaylight.yang.gen.v1.http.netconfcentral.org.ns.toaster.rev091120.Toaster.ToasterStatus;
+import org.opendaylight.yang.gen.v1.http.netconfcentral.org.ns.toaster.rev091120.RestockToasterInput;
import org.opendaylight.yang.gen.v1.http.netconfcentral.org.ns.toaster.rev091120.ToasterBuilder;
-import org.opendaylight.yang.gen.v1.http.netconfcentral.org.ns.toaster.rev091120.ToasterData;
+import org.opendaylight.yang.gen.v1.http.netconfcentral.org.ns.toaster.rev091120.ToasterOutOfBreadBuilder;
+import org.opendaylight.yang.gen.v1.http.netconfcentral.org.ns.toaster.rev091120.ToasterRestocked;
+import org.opendaylight.yang.gen.v1.http.netconfcentral.org.ns.toaster.rev091120.ToasterRestockedBuilder;
import org.opendaylight.yang.gen.v1.http.netconfcentral.org.ns.toaster.rev091120.ToasterService;
+import org.opendaylight.controller.sal.binding.api.data.DataChangeListener;
+import org.opendaylight.yangtools.yang.binding.DataObject;
import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
import org.opendaylight.yangtools.yang.common.RpcError;
import org.opendaylight.yangtools.yang.common.RpcResult;
import com.google.common.util.concurrent.Futures;
-public class OpendaylightToaster implements ToasterData, ToasterService, ToasterProviderRuntimeMXBean, AutoCloseable {
+public class OpendaylightToaster implements ToasterService, ToasterProviderRuntimeMXBean,
+ DataChangeListener, AutoCloseable {
- private static final Logger log = LoggerFactory.getLogger(OpendaylightToaster.class);
- private static final InstanceIdentifier<Toaster> toasterIID = InstanceIdentifier.builder(Toaster.class).build();
+ private static final Logger LOG = LoggerFactory.getLogger(OpendaylightToaster.class);
- private static final DisplayString toasterManufacturer = new DisplayString("Opendaylight");
- private static final DisplayString toasterModelNumber = new DisplayString("Model 1 - Binding Aware");
+ public static final InstanceIdentifier<Toaster> TOASTER_IID = InstanceIdentifier.builder(Toaster.class).build();
+
+ private static final DisplayString TOASTER_MANUFACTURER = new DisplayString("Opendaylight");
+ private static final DisplayString TOASTER_MODEL_NUMBER = new DisplayString("Model 1 - Binding Aware");
private NotificationProviderService notificationProvider;
private DataBrokerService dataProvider;
+
private final ExecutorService executor;
- private Future<RpcResult<Void>> currentTask;
+ // As you will see we are using multiple threads here. Therefore we need to be careful about concurrency.
+ // In this case we use the taskLock to provide synchronization for the current task.
+ private volatile Future<RpcResult<Void>> currentTask;
+ private final Object taskLock = new Object();
+
+ private final AtomicLong amountOfBreadInStock = new AtomicLong( 100 );
+
+ private final AtomicLong toastsMade = new AtomicLong(0);
+
+ // Thread safe holder for our darkness multiplier.
+ private final AtomicLong darknessFactor = new AtomicLong( 1000 );
public OpendaylightToaster() {
executor = Executors.newFixedThreadPool(1);
}
+ public void setNotificationProvider(NotificationProviderService salService) {
+ this.notificationProvider = salService;
+ }
+
+ public void setDataProvider(DataBrokerService salDataProvider) {
+ this.dataProvider = salDataProvider;
+ updateStatus();
+ }
+
+ /**
+ * Implemented from the AutoCloseable interface.
+ */
@Override
- public synchronized Toaster getToaster() {
- ToasterBuilder tb = new ToasterBuilder();
- tb //
- .setToasterManufacturer(toasterManufacturer) //
- .setToasterModelNumber(toasterModelNumber) //
- .setToasterStatus(currentTask == null ? ToasterStatus.Up : ToasterStatus.Down);
+ public void close() throws ExecutionException, InterruptedException {
+ // When we close this service we need to shutdown our executor!
+ executor.shutdown();
+ if (dataProvider != null) {
+ final DataModificationTransaction t = dataProvider.beginTransaction();
+ t.removeOperationalData(TOASTER_IID);
+ t.commit().get();
+ }
+ }
+
+ private Toaster buildToaster() {
+ // We don't need to synchronize on currentTask here b/c it's declared volatile and
+ // we're just doing a read.
+ boolean isUp = currentTask == null;
+
+ // note - we are simulating a device whose manufacture and model are
+ // fixed (embedded) into the hardware.
+ // This is why the manufacture and model number are hardcoded.
+ ToasterBuilder tb = new ToasterBuilder();
+ tb.setToasterManufacturer(TOASTER_MANUFACTURER).setToasterModelNumber(TOASTER_MODEL_NUMBER)
+ .setToasterStatus(isUp ? ToasterStatus.Up : ToasterStatus.Down);
return tb.build();
}
+ /**
+ * Implemented from the DataChangeListener interface.
+ */
@Override
- public synchronized Future<RpcResult<Void>> cancelToast() {
- if (currentTask != null) {
- cancelToastImpl();
+ public void onDataChanged( DataChangeEvent<InstanceIdentifier<?>, DataObject> change ) {
+ DataObject dataObject = change.getUpdatedConfigurationData().get( TOASTER_IID );
+ if( dataObject instanceof Toaster )
+ {
+ Toaster toaster = (Toaster) dataObject;
+ Long darkness = toaster.getDarknessFactor();
+ if( darkness != null )
+ {
+ darknessFactor.set( darkness );
+ }
}
- return null;
}
+ /**
+ * RestConf RPC call implemented from the ToasterService interface.
+ */
@Override
- public synchronized Future<RpcResult<Void>> makeToast(MakeToastInput input) {
- log.debug("makeToast - Received input for toast");
- logToastInput(input);
- if (currentTask != null) {
- return inProgressError();
+ public Future<RpcResult<Void>> cancelToast() {
+ synchronized (taskLock) {
+ if (currentTask != null) {
+ currentTask.cancel(true);
+ currentTask = null;
+ }
}
- currentTask = executor.submit(new MakeToastTask(input));
- updateStatus();
- return currentTask;
+ // Always return success from the cancel toast call.
+ return Futures.immediateFuture(Rpcs.<Void> getRpcResult(true, Collections.<RpcError> emptySet()));
}
- private Future<RpcResult<Void>> inProgressError() {
- RpcResult<Void> result = Rpcs.<Void> getRpcResult(false, null, Collections.<RpcError> emptySet());
- return Futures.immediateFuture(result);
- }
+ /**
+ * RestConf RPC call implemented from the ToasterService interface.
+ */
+ @Override
+ public Future<RpcResult<Void>> makeToast(MakeToastInput input) {
+ LOG.info("makeToast: " + input);
- private void cancelToastImpl() {
- currentTask.cancel(true);
- ToastDoneBuilder toastDone = new ToastDoneBuilder();
- toastDone.setToastStatus(ToastStatus.Cancelled);
- notificationProvider.publish(toastDone.build());
- }
+ synchronized (taskLock) {
+ if (currentTask != null) {
+ // return an error since we are already toasting some toast.
+ LOG.info( "Toaster is already making toast" );
- public void setNotificationProvider(NotificationProviderService salService) {
- this.notificationProvider = salService;
- }
+ RpcResult<Void> result = Rpcs.<Void> getRpcResult(false, null, Arrays.asList(
+ RpcErrors.getRpcError( null, null, null, null,
+ "Toaster is busy", null, null ) ) );
+ return Futures.immediateFuture(result);
+ }
+ else if( outOfBread() ) {
+ RpcResult<Void> result = Rpcs.<Void> getRpcResult(false, null, Arrays.asList(
+ RpcErrors.getRpcError( null, null, null, null,
+ "Toaster is out of bread", null, null ) ) );
+ return Futures.immediateFuture(result);
+ }
+ else {
+ // Notice that we are moving the actual call to another thread,
+ // allowing this thread to return immediately.
+ // The MD-SAL design encourages asynchronus programming. If the
+ // caller needs to block until the call is
+ // complete then they can leverage the blocking methods on the
+ // Future interface.
+ currentTask = executor.submit(new MakeToastTask(input));
+ }
+ }
- public void setDataProvider(DataBrokerService salDataProvider) {
- this.dataProvider = salDataProvider;
updateStatus();
+ return currentTask;
}
- private void logToastInput(MakeToastInput input) {
- String toastType = input.getToasterToastType().getName();
- String toastDoneness = input.getToasterDoneness().toString();
- log.trace("Toast: {} doneness: {}", toastType, toastDoneness);
+ /**
+ * RestConf RPC call implemented from the ToasterService interface.
+ * Restocks the bread for the toaster, resets the toastsMade counter to 0, and sends a
+ * ToasterRestocked notification.
+ */
+ @Override
+ public Future<RpcResult<java.lang.Void>> restockToaster(RestockToasterInput input) {
+ LOG.info( "restockToaster: " + input );
+
+ synchronized( taskLock ) {
+ amountOfBreadInStock.set( input.getAmountOfBreadToStock() );
+
+ if( amountOfBreadInStock.get() > 0 ) {
+ ToasterRestocked reStockedNotification =
+ new ToasterRestockedBuilder().setAmountOfBread( input.getAmountOfBreadToStock() ).build();
+ notificationProvider.publish( reStockedNotification );
+ }
+ }
+
+ return Futures.immediateFuture(Rpcs.<Void> getRpcResult(true, Collections.<RpcError> emptySet()));
}
- private final AtomicLong toastsMade = new AtomicLong(0);
+ /**
+ * JMX RPC call implemented from the ToasterProviderRuntimeMXBean interface.
+ */
+ @Override
+ public void clearToastsMade() {
+ LOG.info( "clearToastsMade" );
+ toastsMade.set( 0 );
+ }
+ /**
+ * Accesssor method implemented from the ToasterProviderRuntimeMXBean interface.
+ */
@Override
public Long getToastsMade() {
return toastsMade.get();
private void updateStatus() {
if (dataProvider != null) {
final DataModificationTransaction t = dataProvider.beginTransaction();
- t.removeOperationalData(toasterIID);
- t.putOperationalData(toasterIID, getToaster());
+ t.removeOperationalData(TOASTER_IID);
+ t.putOperationalData(TOASTER_IID, buildToaster());
try {
t.commit().get();
} catch (InterruptedException | ExecutionException e) {
- log.warn("Failed to update toaster status, operational otherwise", e);
+ LOG.warn("Failed to update toaster status, operational otherwise", e);
}
} else {
- log.trace("No data provider configured, not updating status");
+ LOG.trace("No data provider configured, not updating status");
}
}
- @Override
- public void close() throws ExecutionException, InterruptedException {
- if (dataProvider != null) {
- final DataModificationTransaction t = dataProvider.beginTransaction();
- t.removeOperationalData(toasterIID);
- t.commit().get();
- }
+ private boolean outOfBread()
+ {
+ return amountOfBreadInStock.get() == 0;
}
private class MakeToastTask implements Callable<RpcResult<Void>> {
}
@Override
- public RpcResult<Void> call() throws InterruptedException {
- Thread.sleep(1000 * toastRequest.getToasterDoneness());
+ public RpcResult<Void> call() {
+ try
+ {
+ // make toast just sleeps for n secondn per doneness level.
+ long darknessFactor = OpendaylightToaster.this.darknessFactor.get();
+ Thread.sleep(darknessFactor * toastRequest.getToasterDoneness());
- ToastDoneBuilder notifyBuilder = new ToastDoneBuilder();
- notifyBuilder.setToastStatus(ToastStatus.Done);
- notificationProvider.publish(notifyBuilder.build());
- log.debug("Toast Done");
- logToastInput(toastRequest);
+ }
+ catch( InterruptedException e ) {
+ LOG.info( "Interrupted while making the toast" );
+ }
- currentTask = null;
toastsMade.incrementAndGet();
+
+ amountOfBreadInStock.getAndDecrement();
+ if( outOfBread() ) {
+ LOG.info( "Toaster is out of bread!" );
+
+ notificationProvider.publish( new ToasterOutOfBreadBuilder().build() );
+ }
+
+ synchronized (taskLock) {
+ currentTask = null;
+ }
+
updateStatus();
+ LOG.debug("Toast done");
+
return Rpcs.<Void> getRpcResult(true, null, Collections.<RpcError> emptySet());
}
}
prefix "toaster-provider-impl";
import config { prefix config; revision-date 2013-04-05; }
- import toaster-provider { prefix toaster-provider; revision-date 2014-01-31; }
+ import rpc-context { prefix rpcx; revision-date 2013-06-17; }
import opendaylight-md-sal-binding { prefix mdsal; revision-date 2013-10-28; }
description
"Initial revision.";
}
- // This is the definition of a service implementation
+ // This is the definition of the service implementation as a module identity.
identity toaster-provider-impl {
base config:module-type;
- config:provided-service toaster-provider:toaster-provider;
+
+ // Specifies the prefix for generated java classes.
config:java-name-prefix ToasterProvider;
}
+ // Augments the 'configuration' choice node under modules/module.
augment "/config:modules/config:module/config:configuration" {
case toaster-provider-impl {
when "/config:modules/config:module/config:type = 'toaster-provider-impl'";
augment "/config:modules/config:module/config:state" {
case toaster-provider-impl {
when "/config:modules/config:module/config:type = 'toaster-provider-impl'";
-
+
leaf toasts-made {
type uint32;
}
+
+ rpcx:rpc-context-instance "clear-toasts-made-rpc";
+ }
+ }
+
+ identity clear-toasts-made-rpc;
+ rpc clear-toasts-made {
+ description
+ "JMX call to clear the toasts-made counter.";
+
+ input {
+ uses rpcx:rpc-context-ref {
+ refine context-instance {
+ rpcx:rpc-context-instance clear-toasts-made-rpc;
+ }
+ }
}
}
}
+++ /dev/null
-// vi: set smarttab et sw=4 tabstop=4:
-module toaster-provider {
-
- yang-version 1;
- namespace "urn:opendaylight:params:xml:ns:yang:controller:config:toaster-provider";
- prefix "toaster-provider";
-
- import config { prefix config; revision-date 2013-04-05; }
-
- description
- "This module contains the base YANG definitions for
- toaster-provider services.";
-
- revision "2014-01-31" {
- description
- "Initial revision.";
- }
-
- // This is the definition of a service
- identity toaster-provider {
-
- base "config:service-type";
-
- config:java-class "org.opendaylight.yang.gen.v1.http.netconfcentral.org.ns.toaster.rev091120.ToasterData";
- }
-}
\ No newline at end of file
"This variable indicates the current state of
the toaster.";
}
+
+ leaf darknessFactor {
+ type uint32;
+ config true;
+ default 1000;
+ description
+ "The darkness factor. Basically, the number of ms to multiple the doneness value by.";
+ }
} // container toaster
rpc make-toast {
if the toaster service is disabled.";
} // rpc cancel-toast
- notification toastDone {
- description
- "Indicates that the toast in progress has completed.";
- leaf toastStatus {
- type enumeration {
- enum "done" {
- value 0;
- description "The toast is done.";
- }
- enum "cancelled" {
- value 1;
- description
- "The toast was cancelled.";
- }
- enum "error" {
- value 2;
- description
- "The toaster service was disabled or
- the toaster is broken.";
- }
+ rpc restock-toaster {
+ description
+ "Restocks the toaster with the amount of bread specified.";
+
+ input {
+ leaf amountOfBreadToStock {
+ type uint32;
+ description
+ "Indicates the amount of bread to re-stock";
+ }
}
+ }
+
+ notification toasterOutOfBread {
+ description
+ "Indicates that the toaster has run of out bread.";
+ } // notification toasterOutOfStock
+
+ notification toasterRestocked {
+ description
+ "Indicates that the toaster has run of out bread.";
+ leaf amountOfBread {
+ type uint32;
description
- "Indicates the final toast status";
+ "Indicates the amount of bread that was re-stocked";
}
- } // notification toastDone
+ } // notification toasterOutOfStock
+
} // module toaster
+++ /dev/null
-<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
- xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
- <modelVersion>4.0.0</modelVersion>
- <parent>
- <artifactId>sal-test-parent</artifactId>
- <groupId>org.opendaylight.controller.tests</groupId>
- <version>1.0-SNAPSHOT</version>
- </parent>
- <artifactId>sal-rest-connector-it</artifactId>
- <scm>
- <connection>scm:git:ssh://git.opendaylight.org:29418/controller.git</connection>
- <developerConnection>scm:git:ssh://git.opendaylight.org:29418/controller.git</developerConnection>
- <url>https://wiki.opendaylight.org/view/OpenDaylight_Controller:MD-SAL</url>
- </scm>
-
- <build>
- <plugins>
- <plugin>
- <groupId>org.ops4j.pax.exam</groupId>
- <artifactId>maven-paxexam-plugin</artifactId>
- <version>1.2.4</version>
- <executions>
- <execution>
- <id>generate-config</id>
- <goals>
- <goal>generate-depends-file</goal>
- </goals>
- </execution>
- </executions>
- </plugin>
- </plugins>
- <pluginManagement>
- <plugins>
- <!--This plugin's configuration is used to store Eclipse
- m2e settings only. It has no influence on the Maven build itself. -->
- <plugin>
- <groupId>org.eclipse.m2e</groupId>
- <artifactId>lifecycle-mapping</artifactId>
- <version>1.0.0</version>
- <configuration>
- <lifecycleMappingMetadata>
- <pluginExecutions>
- <pluginExecution>
- <pluginExecutionFilter>
- <groupId>
- org.ops4j.pax.exam
- </groupId>
- <artifactId>
- maven-paxexam-plugin
- </artifactId>
- <versionRange>
- [1.2.4,)
- </versionRange>
- <goals>
- <goal>
- generate-depends-file
- </goal>
- </goals>
- </pluginExecutionFilter>
- <action>
- <ignore></ignore>
- </action>
- </pluginExecution>
- </pluginExecutions>
- </lifecycleMappingMetadata>
- </configuration>
- </plugin>
- </plugins>
- </pluginManagement>
- </build>
-
- <dependencies>
- <dependency>
- <groupId>org.opendaylight.controller</groupId>
- <artifactId>logging.bridge</artifactId>
- <version>0.4.1-SNAPSHOT</version>
- </dependency>
- <dependency>
- <groupId>org.opendaylight.yangtools.thirdparty</groupId>
- <artifactId>xtend-lib-osgi</artifactId>
- <version>2.4.3</version>
- </dependency>
- <dependency>
- <groupId>org.opendaylight.controller</groupId>
- <artifactId>bundlescanner.implementation</artifactId>
- <version>0.4.1-SNAPSHOT</version>
- </dependency>
- <dependency>
- <groupId>org.opendaylight.controller</groupId>
- <artifactId>sal-broker-impl</artifactId>
- <version>1.0-SNAPSHOT</version>
- <scope>test</scope>
- </dependency>
- <dependency>
- <groupId>org.opendaylight.controller</groupId>
- <artifactId>sal-rest-connector</artifactId>
- <version>1.0-SNAPSHOT</version>
- <scope>test</scope>
- </dependency>
- <dependency>
- <groupId>org.opendaylight.controller</groupId>
- <artifactId>sal-netconf-connector</artifactId>
- <version>1.0-SNAPSHOT</version>
- <scope>test</scope>
- </dependency>
- <dependency>
- <groupId>org.opendaylight.controller</groupId>
- <artifactId>sal-binding-it</artifactId>
- <version>1.0-SNAPSHOT</version>
- <scope>test</scope>
- </dependency>
- <dependency>
- <groupId>org.ops4j.pax.exam</groupId>
- <artifactId>pax-exam-container-native</artifactId>
- <version>${exam.version}</version>
- <scope>test</scope>
- </dependency>
- <dependency>
- <groupId>org.ops4j.pax.exam</groupId>
- <artifactId>pax-exam-junit4</artifactId>
- <version>${exam.version}</version>
- <scope>test</scope>
- </dependency>
- <dependency>
- <groupId>io.netty</groupId>
- <artifactId>netty-all</artifactId>
- <version>${netty.version}</version>
- <scope>test</scope>
- </dependency>
- <dependency>
- <groupId>org.ops4j.pax.exam</groupId>
- <artifactId>pax-exam-link-mvn</artifactId>
- <version>${exam.version}</version>
- <scope>test</scope>
- </dependency>
- <dependency>
- <groupId>equinoxSDK381</groupId>
- <artifactId>org.eclipse.osgi</artifactId>
- <version>3.8.1.v20120830-144521</version>
- <scope>test</scope>
- </dependency>
- <dependency>
- <groupId>org.slf4j</groupId>
- <artifactId>log4j-over-slf4j</artifactId>
- <version>1.7.2</version>
- </dependency>
- <dependency>
- <groupId>ch.qos.logback</groupId>
- <artifactId>logback-core</artifactId>
- <version>1.0.9</version>
- </dependency>
- <dependency>
- <groupId>ch.qos.logback</groupId>
- <artifactId>logback-classic</artifactId>
- <version>1.0.9</version>
- </dependency>
- <dependency>
- <groupId>org.opendaylight.controller</groupId>
- <artifactId>sal-binding-api</artifactId>
- <version>1.0-SNAPSHOT</version>
- </dependency>
- <dependency>
- <groupId>org.opendaylight.controller</groupId>
- <artifactId>sal-common-util</artifactId>
- <version>1.0-SNAPSHOT</version>
- </dependency>
- <dependency>
- <groupId>org.opendaylight.controller</groupId>
- <artifactId>sal-core-api</artifactId>
- <version>1.0-SNAPSHOT</version>
- </dependency>
- <dependency>
- <groupId>org.opendaylight.controller.model</groupId>
- <artifactId>model-flow-service</artifactId>
- <version>1.0-SNAPSHOT</version>
- <scope>provided</scope>
- </dependency>
- <dependency>
- <groupId>org.opendaylight.controller</groupId>
- <artifactId>config-manager</artifactId>
- <version>0.2.2-SNAPSHOT</version>
- </dependency>
- <dependency>
- <groupId>org.opendaylight.controller.model</groupId>
- <artifactId>model-flow-management</artifactId>
- <version>1.0-SNAPSHOT</version>
- <scope>provided</scope>
- </dependency>
- <dependency>
- <groupId>org.opendaylight.yangtools.thirdparty</groupId>
- <artifactId>antlr4-runtime-osgi-nohead</artifactId>
- <version>4.0</version>
- </dependency>
- <dependency>
- <groupId>org.opendaylight.yangtools</groupId>
- <artifactId>yang-binding</artifactId>
- </dependency>
- <dependency>
- <groupId>org.opendaylight.yangtools</groupId>
- <artifactId>yang-common</artifactId>
- </dependency>
- <dependency>
- <groupId>org.opendaylight.yangtools</groupId>
- <artifactId>yang-data-api</artifactId>
- </dependency>
- <dependency>
- <groupId>org.opendaylight.controller</groupId>
- <artifactId>commons.northbound</artifactId>
- <version>0.4.1-SNAPSHOT</version>
- <scope>runtime</scope>
- </dependency>
- <dependency>
- <groupId>org.opendaylight.controller</groupId>
- <artifactId>sal-common-util</artifactId>
- <version>1.0-SNAPSHOT</version>
- </dependency>
- <dependency>
- <groupId>org.slf4j</groupId>
- <artifactId>jcl-over-slf4j</artifactId>
- <version>1.7.2</version>
- </dependency>
- <dependency>
- <groupId>org.slf4j</groupId>
- <artifactId>slf4j-api</artifactId>
-
- </dependency>
- <dependency>
- <groupId>org.slf4j</groupId>
- <artifactId>log4j-over-slf4j</artifactId>
- <version>1.7.2</version>
- </dependency>
- <dependency>
- <groupId>ch.qos.logback</groupId>
- <artifactId>logback-core</artifactId>
- <version>1.0.9</version>
- </dependency>
- <dependency>
- <groupId>ch.qos.logback</groupId>
- <artifactId>logback-classic</artifactId>
- <version>1.0.9</version>
- </dependency>
- <dependency>
- <groupId>commons-codec</groupId>
- <artifactId>commons-codec</artifactId>
- <version>1.7</version>
- </dependency>
- <dependency>
- <groupId>equinoxSDK381</groupId>
- <artifactId>javax.servlet</artifactId>
- <version>3.0.0.v201112011016</version>
- </dependency>
- <dependency>
- <groupId>equinoxSDK381</groupId>
- <artifactId>javax.servlet.jsp</artifactId>
- <version>2.2.0.v201112011158</version>
- </dependency>
- <dependency>
- <groupId>equinoxSDK381</groupId>
- <artifactId>org.eclipse.equinox.ds</artifactId>
- <version>1.4.0.v20120522-1841</version>
- </dependency>
- <dependency>
- <groupId>equinoxSDK381</groupId>
- <artifactId>org.eclipse.equinox.util</artifactId>
- <version>1.0.400.v20120522-2049</version>
- </dependency>
- <dependency>
- <groupId>equinoxSDK381</groupId>
- <artifactId>org.eclipse.osgi.services</artifactId>
- <version>3.3.100.v20120522-1822</version>
- </dependency>
- <dependency>
- <groupId>equinoxSDK381</groupId>
- <artifactId>org.eclipse.osgi</artifactId>
- <version>3.8.1.v20120830-144521</version>
- </dependency>
- <dependency>
- <groupId>equinoxSDK381</groupId>
- <artifactId>org.apache.felix.gogo.command</artifactId>
- <version>0.8.0.v201108120515</version>
- </dependency>
- <dependency>
- <groupId>equinoxSDK381</groupId>
- <artifactId>org.apache.felix.gogo.runtime</artifactId>
- <version>0.8.0.v201108120515</version>
- </dependency>
- <dependency>
- <groupId>equinoxSDK381</groupId>
- <artifactId>org.apache.felix.gogo.shell</artifactId>
- <version>0.8.0.v201110170705</version>
- </dependency>
- <dependency>
- <groupId>equinoxSDK381</groupId>
- <artifactId>org.eclipse.equinox.cm</artifactId>
- <version>1.0.400.v20120522-1841</version>
- </dependency>
- <dependency>
- <groupId>equinoxSDK381</groupId>
- <artifactId>org.eclipse.equinox.console</artifactId>
- <version>1.0.0.v20120522-1841</version>
- </dependency>
- <dependency>
- <groupId>equinoxSDK381</groupId>
- <artifactId>org.eclipse.equinox.launcher</artifactId>
- <version>1.3.0.v20120522-1813</version>
- </dependency>
- <!-- Gemini Web -->
- <dependency>
- <groupId>geminiweb</groupId>
- <artifactId>org.eclipse.gemini.web.core</artifactId>
- <version>${geminiweb.version}</version>
- </dependency>
- <dependency>
- <groupId>geminiweb</groupId>
- <artifactId>org.eclipse.gemini.web.extender</artifactId>
- <version>${geminiweb.version}</version>
- </dependency>
- <dependency>
- <groupId>geminiweb</groupId>
- <artifactId>org.eclipse.gemini.web.tomcat</artifactId>
- <version>${geminiweb.version}</version>
- </dependency>
- <dependency>
- <groupId>geminiweb</groupId>
- <artifactId>org.eclipse.virgo.kernel.equinox.extensions</artifactId>
- <version>${virgo.version}</version>
- </dependency>
- <dependency>
- <groupId>geminiweb</groupId>
- <artifactId>org.eclipse.virgo.util.common</artifactId>
- <version>${virgo.version}</version>
- </dependency>
- <dependency>
- <groupId>geminiweb</groupId>
- <artifactId>org.eclipse.virgo.util.io</artifactId>
- <version>${virgo.version}</version>
- </dependency>
- <dependency>
- <groupId>geminiweb</groupId>
- <artifactId>org.eclipse.virgo.util.math</artifactId>
- <version>${virgo.version}</version>
- </dependency>
- <dependency>
- <groupId>geminiweb</groupId>
- <artifactId>org.eclipse.virgo.util.osgi</artifactId>
- <version>${virgo.version}</version>
- </dependency>
- <dependency>
- <groupId>geminiweb</groupId>
- <artifactId>org.eclipse.virgo.util.osgi.manifest</artifactId>
- <version>${virgo.version}</version>
- </dependency>
- <dependency>
- <groupId>geminiweb</groupId>
- <artifactId>org.eclipse.virgo.util.parser.manifest</artifactId>
- <version>${virgo.version}</version>
- </dependency>
- <dependency>
- <groupId>org.apache.felix</groupId>
- <artifactId>org.apache.felix.dependencymanager</artifactId>
- <version>3.1.0</version>
- </dependency>
- <dependency>
- <groupId>org.apache.felix</groupId>
- <artifactId>org.apache.felix.dependencymanager.shell</artifactId>
- <version>3.0.1</version>
- </dependency>
- <dependency>
- <groupId>org.jboss.spec.javax.transaction</groupId>
- <artifactId>jboss-transaction-api_1.1_spec</artifactId>
- <version>1.0.1.Final</version>
- </dependency>
- <dependency>
- <groupId>org.apache.felix</groupId>
- <artifactId>org.apache.felix.fileinstall</artifactId>
- <version>3.1.6</version>
- </dependency>
- <dependency>
- <groupId>org.apache.commons</groupId>
- <artifactId>commons-lang3</artifactId>
- <version>3.1</version>
- </dependency>
- <dependency>
- <groupId>virgomirror</groupId>
- <artifactId>org.eclipse.jdt.core.compiler.batch</artifactId>
- <version>3.8.0.I20120518-2145</version>
- </dependency>
- <dependency>
- <groupId>eclipselink</groupId>
- <artifactId>javax.persistence</artifactId>
- <version>2.0.4.v201112161009</version>
- </dependency>
- <dependency>
- <groupId>orbit</groupId>
- <artifactId>javax.activation</artifactId>
- <version>1.1.0.v201211130549</version>
- </dependency>
- <dependency>
- <groupId>orbit</groupId>
- <artifactId>javax.annotation</artifactId>
- <version>1.1.0.v201209060031</version>
- </dependency>
- <dependency>
- <groupId>orbit</groupId>
- <artifactId>javax.ejb</artifactId>
- <version>3.1.1.v201204261316</version>
- </dependency>
- <dependency>
- <groupId>orbit</groupId>
- <artifactId>javax.el</artifactId>
- <version>2.2.0.v201108011116</version>
- </dependency>
- <dependency>
- <groupId>orbit</groupId>
- <artifactId>javax.mail.glassfish</artifactId>
- <version>1.4.1.v201108011116</version>
- </dependency>
- <dependency>
- <groupId>orbit</groupId>
- <artifactId>javax.xml.rpc</artifactId>
- <version>1.1.0.v201005080400</version>
- </dependency>
- <dependency>
- <groupId>orbit</groupId>
- <artifactId>org.apache.catalina</artifactId>
- <version>7.0.32.v201211201336</version>
- </dependency>
- <dependency>
- <groupId>orbit</groupId>
- <artifactId>org.apache.catalina.ha</artifactId>
- <version>7.0.32.v201211201952</version>
- </dependency>
- <dependency>
- <groupId>orbit</groupId>
- <artifactId>org.apache.catalina.tribes</artifactId>
- <version>7.0.32.v201211201952</version>
- </dependency>
- <dependency>
- <groupId>orbit</groupId>
- <artifactId>org.apache.coyote</artifactId>
- <version>7.0.32.v201211201952</version>
- </dependency>
- <dependency>
- <groupId>orbit</groupId>
- <artifactId>org.apache.el</artifactId>
- <version>7.0.32.v201211081135</version>
- </dependency>
- <dependency>
- <groupId>orbit</groupId>
- <artifactId>org.apache.jasper</artifactId>
- <version>7.0.32.v201211201952</version>
- </dependency>
- <dependency>
- <groupId>orbit</groupId>
- <artifactId>org.apache.juli.extras</artifactId>
- <version>7.0.32.v201211081135</version>
- </dependency>
- <dependency>
- <groupId>orbit</groupId>
- <artifactId>org.apache.tomcat.api</artifactId>
- <version>7.0.32.v201211081135</version>
- </dependency>
- <dependency>
- <groupId>orbit</groupId>
- <artifactId>org.apache.tomcat.util</artifactId>
- <version>7.0.32.v201211201952</version>
- </dependency>
- <dependency>
- <groupId>orbit</groupId>
- <artifactId>javax.servlet.jsp.jstl</artifactId>
- <version>1.2.0.v201105211821</version>
- </dependency>
- <dependency>
- <groupId>orbit</groupId>
- <artifactId>javax.servlet.jsp.jstl.impl</artifactId>
- <version>1.2.0.v201210211230</version>
- </dependency>
- <!-- Add Pax Exam -->
- <dependency>
- <groupId>org.ops4j.pax.exam</groupId>
- <artifactId>pax-exam-container-native</artifactId>
- <version>${exam.version}</version>
- <scope>test</scope>
- </dependency>
- <dependency>
- <groupId>org.ops4j.pax.exam</groupId>
- <artifactId>pax-exam-junit4</artifactId>
- <version>${exam.version}</version>
- <scope>test</scope>
- </dependency>
- <dependency>
- <groupId>org.ops4j.pax.exam</groupId>
- <artifactId>pax-exam-link-mvn</artifactId>
- <version>${exam.version}</version>
- <scope>test</scope>
- </dependency>
- <dependency>
- <groupId>org.ops4j.pax.url</groupId>
- <artifactId>pax-url-aether</artifactId>
- <version>${url.version}</version>
- <scope>test</scope>
- </dependency>
- <dependency>
- <groupId>org.ow2.asm</groupId>
- <artifactId>asm-all</artifactId>
- <version>4.1</version>
- </dependency>
- <dependency>
- <groupId>org.springframework</groupId>
- <artifactId>org.springframework.asm</artifactId>
- <version>${spring.version}</version>
- </dependency>
- <dependency>
- <groupId>org.springframework</groupId>
- <artifactId>org.springframework.aop</artifactId>
- <version>${spring.version}</version>
- </dependency>
- <dependency>
- <groupId>org.springframework</groupId>
- <artifactId>org.springframework.context</artifactId>
- <version>${spring.version}</version>
- </dependency>
- <dependency>
- <groupId>org.springframework</groupId>
- <artifactId>org.springframework.context.support</artifactId>
- <version>${spring.version}</version>
- </dependency>
- <dependency>
- <groupId>org.springframework</groupId>
- <artifactId>org.springframework.core</artifactId>
- <version>${spring.version}</version>
- </dependency>
- <dependency>
- <groupId>org.springframework</groupId>
- <artifactId>org.springframework.beans</artifactId>
- <version>${spring.version}</version>
- </dependency>
- <dependency>
- <groupId>org.springframework</groupId>
- <artifactId>org.springframework.expression</artifactId>
- <version>${spring.version}</version>
- </dependency>
- <dependency>
- <groupId>org.springframework</groupId>
- <artifactId>org.springframework.web</artifactId>
- <version>${spring.version}</version>
- </dependency>
- <dependency>
- <groupId>org.aopalliance</groupId>
- <artifactId>com.springsource.org.aopalliance</artifactId>
- <version>1.0.0</version>
- </dependency>
- <dependency>
- <groupId>org.springframework</groupId>
- <artifactId>org.springframework.web.servlet</artifactId>
- <version>${spring.version}</version>
- </dependency>
- <!-- Spring security -->
- <dependency>
- <groupId>org.springframework.security</groupId>
- <artifactId>spring-security-config</artifactId>
- <version>${spring-security.version}</version>
- </dependency>
- <dependency>
- <groupId>org.springframework.security</groupId>
- <artifactId>spring-security-core</artifactId>
- <version>${spring-security.version}</version>
- </dependency>
- <dependency>
- <groupId>org.springframework.security</groupId>
- <artifactId>spring-security-web</artifactId>
- <version>${spring-security.version}</version>
- </dependency>
- <dependency>
- <groupId>org.springframework.security</groupId>
- <artifactId>spring-security-taglibs</artifactId>
- <version>${spring-security.version}</version>
- </dependency>
- <dependency>
- <groupId>org.springframework</groupId>
- <artifactId>org.springframework.transaction</artifactId>
- <version>${spring-security.version}</version>
- </dependency>
- <!-- Visual VM hook -->
- <dependency>
- <groupId>org.ow2.chameleon.management</groupId>
- <artifactId>chameleon-mbeans</artifactId>
- <version>1.0.0</version>
- </dependency>
- <!-- Jersey for JAXRS -->
- <dependency>
- <groupId>com.sun.jersey</groupId>
- <artifactId>jersey-core</artifactId>
- <version>${jersey.version}</version>
- </dependency>
- <!-- <dependency> <groupId>com.sun.jersey</groupId> <artifactId>jersey-servlet</artifactId>
- <version>${jersey.version}</version> </dependency> -->
- <dependency>
- <groupId>com.sun.jersey</groupId>
- <artifactId>jersey-server</artifactId>
- <version>${jersey.version}</version>
- </dependency>
- <dependency>
- <groupId>com.sun.jersey</groupId>
- <artifactId>jersey-client</artifactId>
- <version>${jersey.version}</version>
- </dependency>
-
- <dependency>
- <groupId>eclipselink</groupId>
- <artifactId>javax.resource</artifactId>
- <version>1.5.0.v200906010428</version>
- </dependency>
- <dependency>
- <groupId>org.opendaylight.controller.thirdparty</groupId>
- <artifactId>com.sun.jersey.jersey-servlet</artifactId>
- <version>1.17</version>
- </dependency>
- <dependency>
- <groupId>org.opendaylight.controller.thirdparty</groupId>
- <artifactId>org.apache.catalina.filters.CorsFilter</artifactId>
- <version>7.0.42</version>
- </dependency>
-
-
- <dependency>
- <groupId>org.opendaylight.controller</groupId>
- <artifactId>config-api</artifactId>
- </dependency>
- <dependency>
- <groupId>org.opendaylight.controller</groupId>
- <artifactId>config-manager</artifactId>
- </dependency>
- <dependency>
- <groupId>org.opendaylight.controller</groupId>
- <artifactId>config-util</artifactId>
- </dependency>
- <dependency>
- <groupId>org.opendaylight.controller</groupId>
- <artifactId>yang-jmx-generator</artifactId>
- </dependency>
- <dependency>
- <groupId>org.opendaylight.controller</groupId>
- <artifactId>logback-config</artifactId>
- </dependency>
- <dependency>
- <groupId>org.opendaylight.controller</groupId>
- <artifactId>config-persister-api</artifactId>
- </dependency>
- <dependency>
- <groupId>org.opendaylight.controller</groupId>
- <artifactId>config-persister-file-xml-adapter</artifactId>
- </dependency>
- <dependency>
- <groupId>org.opendaylight.controller</groupId>
- <artifactId>netconf-api</artifactId>
- </dependency>
- <dependency>
- <groupId>org.opendaylight.controller</groupId>
- <artifactId>netconf-impl</artifactId>
- </dependency>
- <dependency>
- <groupId>org.opendaylight.controller</groupId>
- <artifactId>netconf-util</artifactId>
- </dependency>
- <dependency>
- <groupId>org.opendaylight.controller</groupId>
- <artifactId>netconf-client</artifactId>
- </dependency>
- <dependency>
- <groupId>org.opendaylight.controller</groupId>
- <artifactId>netconf-mapping-api</artifactId>
- </dependency>
- <dependency>
- <groupId>org.opendaylight.controller</groupId>
- <artifactId>config-netconf-connector</artifactId>
- </dependency>
- <dependency>
- <groupId>org.opendaylight.controller</groupId>
- <artifactId>config-persister-impl</artifactId>
- </dependency>
- </dependencies>
-</project>
+++ /dev/null
-/*
- * Copyright (c) 2014 Cisco Systems, Inc. and others. All rights reserved.
- *
- * This program and the accompanying materials are made available under the
- * terms of the Eclipse Public License v1.0 which accompanies this distribution,
- * and is available at http://www.eclipse.org/legal/epl-v10.html
- */
-package org.opendaylight.controller.test.restconf.it;
-
-import static junit.framework.Assert.assertEquals;
-import static org.junit.Assert.*;
-import static org.ops4j.pax.exam.CoreOptions.junitBundles;
-import static org.ops4j.pax.exam.CoreOptions.mavenBundle;
-import static org.ops4j.pax.exam.CoreOptions.options;
-import static org.ops4j.pax.exam.CoreOptions.systemPackages;
-import static org.ops4j.pax.exam.CoreOptions.systemProperty;
-import static org.ops4j.pax.exam.CoreOptions.maven;
-
-import java.net.InetSocketAddress;
-import java.net.URI;
-import java.util.Collection;
-import java.util.Collections;
-import java.util.Map;
-
-import javax.inject.Inject;
-
-import org.junit.Test;
-import org.junit.runner.RunWith;
-import org.opendaylight.controller.sal.binding.api.BindingAwareBroker;
-import org.opendaylight.controller.sal.connect.netconf.InventoryUtils;
-import org.opendaylight.controller.sal.connect.netconf.NetconfInventoryUtils;
-import org.opendaylight.controller.sal.core.api.data.DataBrokerService;
-import org.opendaylight.controller.sal.core.api.mount.MountProvisionInstance;
-import org.opendaylight.controller.sal.core.api.mount.MountProvisionService;
-import org.opendaylight.controller.test.sal.binding.it.TestHelper;
-import org.opendaylight.yangtools.yang.common.QName;
-import org.opendaylight.yangtools.yang.data.api.CompositeNode;
-import org.opendaylight.yangtools.yang.data.api.InstanceIdentifier;
-import org.ops4j.pax.exam.Configuration;
-import org.ops4j.pax.exam.CoreOptions;
-import org.ops4j.pax.exam.Option;
-import org.ops4j.pax.exam.junit.PaxExam;
-import org.ops4j.pax.exam.util.PathUtils;
-import org.osgi.framework.BundleContext;
-import org.osgi.framework.InvalidSyntaxException;
-import org.osgi.framework.ServiceReference;
-
-import static org.opendaylight.controller.test.sal.binding.it.TestHelper.*;
-
-@RunWith(PaxExam.class)
-public class ServiceProviderController {
-
- public static final String ODL = "org.opendaylight.controller";
- public static final String YANG = "org.opendaylight.yangtools";
- public static final String SAMPLE = "org.opendaylight.controller.samples";
-
- private static QName CONFIG_MODULES = new QName(
- URI.create("urn:opendaylight:params:xml:ns:yang:controller:config"), null, "modules");
- private static QName CONFIG_SERVICES = new QName(
- URI.create("urn:opendaylight:params:xml:ns:yang:controller:config"), null, "modules");
- @Inject
- BundleContext context;
-
- @Inject
- MountProvisionService mountService;
-
- @Inject
- DataBrokerService dataBroker;
-
- @Test
- public void properInitialized() throws Exception {
-
- Map<QName, String> arg = Collections.singletonMap(InventoryUtils.INVENTORY_ID, "foo");
-
- InstanceIdentifier path = InstanceIdentifier.builder(InventoryUtils.INVENTORY_PATH)
- .nodeWithKey(InventoryUtils.INVENTORY_NODE, InventoryUtils.INVENTORY_ID, "foo").toInstance();
-
-
- InstanceIdentifier mountPointPath = path;
-
- /** We retrive a mountpoint **/
- MountProvisionInstance mountPoint = mountService.getMountPoint(mountPointPath);
- CompositeNode data = mountPoint.readOperationalData(InstanceIdentifier.builder().node(CONFIG_MODULES)
- .toInstance());
- assertNotNull(data);
- assertEquals(CONFIG_MODULES, data.getNodeType());
-
- CompositeNode data2 = mountPoint.readOperationalData(InstanceIdentifier.builder().toInstance());
- assertNotNull(data2);
-
- InstanceIdentifier fullPath = InstanceIdentifier.builder(mountPointPath).node(CONFIG_MODULES).toInstance();
-
- CompositeNode data3 = dataBroker.readOperationalData(fullPath);
- assertNotNull(data3);
- assertEquals(CONFIG_MODULES, data.getNodeType());
-
- //Thread.sleep(30 * 60 * 1000); // Waiting for services to get wired.
- //assertTrue(true);
- // assertTrue(consumer.createToast(WhiteBread.class, 5));
- }
-
- @Configuration
- public Option[] config() {
- return options(
- mavenBundle("org.slf4j", "slf4j-api").versionAsInProject(), //
- mavenBundle("org.slf4j", "log4j-over-slf4j").versionAsInProject(), //
- mavenBundle("ch.qos.logback", "logback-core").versionAsInProject(), //
- mavenBundle("ch.qos.logback", "logback-classic").versionAsInProject(), //
-
- mdSalCoreBundles(),
- baseModelBundles(),
- flowCapableModelBundles(),
- configMinumumBundles(),
-
- // mavenBundle(ODL,
- // "sal-binding-broker-impl").versionAsInProject().update(), //
- mavenBundle(ODL, "sal-common").versionAsInProject(), //
- mavenBundle(ODL, "sal-common-api").versionAsInProject(),//
- mavenBundle(ODL, "sal-common-impl").versionAsInProject(), //
- mavenBundle(ODL, "sal-common-util").versionAsInProject(), //
-
- mavenBundle(ODL, "sal-core-api").versionAsInProject().update(), //
- mavenBundle(ODL, "sal-broker-impl").versionAsInProject(), //
- mavenBundle(ODL, "sal-core-spi").versionAsInProject().update(), //
-
- mavenBundle(ODL, "sal-connector-api").versionAsInProject(), //
- // mavenBundle(SAMPLE,
- // "zeromq-test-provider").versionAsInProject(), //
- mavenBundle(ODL, "sal-rest-connector").versionAsInProject(), //
- mavenBundle(ODL, "sal-netconf-connector").versionAsInProject(), //
-
- mavenBundle(YANG, "concepts").versionAsInProject(),
- mavenBundle(YANG, "yang-binding").versionAsInProject(), //
- mavenBundle(YANG, "yang-common").versionAsInProject(), //
- mavenBundle(YANG, "yang-data-api").versionAsInProject(), //
- mavenBundle(YANG, "yang-data-impl").versionAsInProject(), //
- mavenBundle(YANG, "yang-model-api").versionAsInProject(), //
- mavenBundle(YANG, "yang-model-util").versionAsInProject(), //
- mavenBundle(YANG, "yang-parser-api").versionAsInProject(),
- mavenBundle(YANG, "yang-parser-impl").versionAsInProject(),
-
- mavenBundle(YANG + ".thirdparty", "xtend-lib-osgi").versionAsInProject(), //
- mavenBundle(YANG + ".thirdparty", "antlr4-runtime-osgi-nohead").versionAsInProject(), //
- mavenBundle("com.google.guava", "guava").versionAsInProject(), //
-
- // systemProperty("logback.configurationFile").value(
- // "file:" + PathUtils.getBaseDir() +
- // "/src/test/resources/logback.xml"),
- // To start OSGi console for inspection remotely
- systemProperty("osgi.console").value("2401"),
- systemProperty("org.eclipse.gemini.web.tomcat.config.path").value(
- PathUtils.getBaseDir() + "/src/test/resources/tomcat-server.xml"),
-
- // setting default level. Jersey bundles will need to be started
- // earlier.
- systemProperty("osgi.bundles.defaultStartLevel").value("4"),
-
- systemProperty("netconf.tcp.address").value("127.0.0.1"),
- systemProperty("netconf.tcp.port").value("8383"),
-
- systemProperty("netconf.tcp.client.address").value("127.0.0.1"),
- systemProperty("netconf.tcp.client.port").value("8383"),
-
- // Set the systemPackages (used by clustering)
- systemPackages("sun.reflect", "sun.reflect.misc", "sun.misc"),
-
- mavenBundle("org.apache.servicemix.bundles", "org.apache.servicemix.bundles.xerces", "2.11.0_1"),
- mavenBundle("org.eclipse.birt.runtime.3_7_1", "org.apache.xml.resolver", "1.2.0"),
-
- mavenBundle("org.slf4j", "jcl-over-slf4j").versionAsInProject(),
- mavenBundle("org.slf4j", "slf4j-api").versionAsInProject(),
- mavenBundle("org.slf4j", "log4j-over-slf4j").versionAsInProject(),
- mavenBundle("ch.qos.logback", "logback-core").versionAsInProject(),
- mavenBundle("ch.qos.logback", "logback-classic").versionAsInProject(),
- mavenBundle("org.apache.commons", "commons-lang3").versionAsInProject(),
- mavenBundle("org.apache.felix", "org.apache.felix.dependencymanager").versionAsInProject(),
- mavenBundle("org.opendaylight.controller", "clustering.services").versionAsInProject(),
- mavenBundle("org.opendaylight.controller", "containermanager").versionAsInProject(),
- // List all the opendaylight modules
- mavenBundle("org.opendaylight.controller", "configuration").versionAsInProject(),
- mavenBundle("org.opendaylight.controller", "sal").versionAsInProject(),
- mavenBundle("org.opendaylight.controller", "switchmanager").versionAsInProject(),
- mavenBundle("org.opendaylight.controller", "usermanager").versionAsInProject(),
- mavenBundle("org.opendaylight.controller", "logging.bridge").versionAsInProject(),
- // mavenBundle("org.opendaylight.controller",
- // "clustering.test").versionAsInProject(),
- mavenBundle("org.opendaylight.controller", "bundlescanner").versionAsInProject(),
- mavenBundle("org.opendaylight.controller", "bundlescanner.implementation").versionAsInProject(),
-
- // Northbound bundles
- mavenBundle("org.opendaylight.controller", "commons.northbound").versionAsInProject(),
-
- mavenBundle("com.fasterxml.jackson.core", "jackson-annotations").versionAsInProject(),
- mavenBundle("com.fasterxml.jackson.core", "jackson-core").versionAsInProject(),
- mavenBundle("com.fasterxml.jackson.core", "jackson-databind").versionAsInProject(),
- mavenBundle("com.fasterxml.jackson.jaxrs", "jackson-jaxrs-json-provider").versionAsInProject(),
- mavenBundle("com.fasterxml.jackson.module", "jackson-module-jaxb-annotations").versionAsInProject(),
-
- mavenBundle("org.codehaus.jettison", "jettison").versionAsInProject(),
-
- mavenBundle("commons-io", "commons-io").versionAsInProject(),
-
- // mavenBundle("commons-fileupload",
- // "commons-fileupload").versionAsInProject(),
-
- mavenBundle("io.netty", "netty-handler").versionAsInProject(),
- mavenBundle("io.netty", "netty-codec").versionAsInProject(),
- mavenBundle("io.netty", "netty-buffer").versionAsInProject(),
- mavenBundle("io.netty", "netty-transport").versionAsInProject(),
- mavenBundle("io.netty", "netty-common").versionAsInProject(),
-
- mavenBundle(ODL, "config-api").versionAsInProject(),
- mavenBundle(ODL, "config-manager").versionAsInProject(),
- mavenBundle(ODL, "config-util").versionAsInProject(),
- mavenBundle(ODL, "yang-jmx-generator").versionAsInProject(),
- mavenBundle(ODL, "logback-config").versionAsInProject(),
- mavenBundle(ODL, "config-persister-api").versionAsInProject(),
- // mavenBundle(ODL,"config-persister-file-xml-adapter").versionAsInProject(),
- mavenBundle(ODL, "protocol-framework").versionAsInProject(),
- mavenBundle(ODL, "netconf-api").versionAsInProject(),
- mavenBundle(ODL, "netconf-impl").versionAsInProject(),
- mavenBundle(ODL, "netconf-client").versionAsInProject(),
- mavenBundle(ODL, "netconf-util").versionAsInProject(),
- mavenBundle(ODL + ".thirdparty", "ganymed").versionAsInProject(),
- mavenBundle(ODL, "netconf-mapping-api").versionAsInProject(),
- mavenBundle(ODL, "config-netconf-connector").versionAsInProject(),
- mavenBundle(ODL, "config-persister-impl").versionAsInProject(),
-
- mavenBundle(YANG, "binding-generator-spi").versionAsInProject(), //
- mavenBundle(YANG, "binding-model-api").versionAsInProject(), //
- mavenBundle(YANG, "binding-generator-util").versionAsInProject(),
- mavenBundle(YANG, "yang-parser-impl").versionAsInProject(),
- mavenBundle(YANG, "binding-type-provider").versionAsInProject(),
-
- mavenBundle("equinoxSDK381", "javax.servlet").versionAsInProject(),
- mavenBundle("equinoxSDK381", "javax.servlet.jsp").versionAsInProject(),
- mavenBundle("equinoxSDK381", "org.eclipse.equinox.ds").versionAsInProject(),
- mavenBundle("orbit", "javax.xml.rpc").versionAsInProject(),
- mavenBundle("equinoxSDK381", "org.eclipse.equinox.util").versionAsInProject(),
- mavenBundle("equinoxSDK381", "org.eclipse.osgi.services").versionAsInProject(),
- mavenBundle("equinoxSDK381", "org.apache.felix.gogo.command").versionAsInProject(),
- mavenBundle("equinoxSDK381", "org.apache.felix.gogo.runtime").versionAsInProject(),
- mavenBundle("equinoxSDK381", "org.apache.felix.gogo.shell").versionAsInProject(),
- mavenBundle("equinoxSDK381", "org.eclipse.equinox.cm").versionAsInProject(),
- mavenBundle("equinoxSDK381", "org.eclipse.equinox.console").versionAsInProject(),
- mavenBundle("equinoxSDK381", "org.eclipse.equinox.launcher").versionAsInProject(),
-
- mavenBundle("geminiweb", "org.eclipse.gemini.web.core").versionAsInProject(),
- mavenBundle("geminiweb", "org.eclipse.gemini.web.extender").versionAsInProject(),
- mavenBundle("geminiweb", "org.eclipse.gemini.web.tomcat").versionAsInProject(),
- mavenBundle("geminiweb", "org.eclipse.virgo.kernel.equinox.extensions").versionAsInProject().noStart(),
- mavenBundle("geminiweb", "org.eclipse.virgo.util.common").versionAsInProject(),
- mavenBundle("geminiweb", "org.eclipse.virgo.util.io").versionAsInProject(),
- mavenBundle("geminiweb", "org.eclipse.virgo.util.math").versionAsInProject(),
- mavenBundle("geminiweb", "org.eclipse.virgo.util.osgi").versionAsInProject(),
- mavenBundle("geminiweb", "org.eclipse.virgo.util.osgi.manifest").versionAsInProject(),
- mavenBundle("geminiweb", "org.eclipse.virgo.util.parser.manifest").versionAsInProject(),
-
- mavenBundle("org.apache.felix", "org.apache.felix.dependencymanager").versionAsInProject(),
- mavenBundle("org.apache.felix", "org.apache.felix.dependencymanager.shell").versionAsInProject(),
-
- mavenBundle("com.google.code.gson", "gson").versionAsInProject(),
- mavenBundle("org.jboss.spec.javax.transaction", "jboss-transaction-api_1.1_spec").versionAsInProject(),
- mavenBundle("org.apache.felix", "org.apache.felix.fileinstall").versionAsInProject(),
- mavenBundle("org.apache.commons", "commons-lang3").versionAsInProject(),
- mavenBundle("commons-codec", "commons-codec").versionAsInProject(),
- mavenBundle("virgomirror", "org.eclipse.jdt.core.compiler.batch").versionAsInProject(),
- mavenBundle("eclipselink", "javax.persistence").versionAsInProject(),
- mavenBundle("eclipselink", "javax.resource").versionAsInProject(),
-
- mavenBundle("orbit", "javax.activation").versionAsInProject(),
- mavenBundle("orbit", "javax.annotation").versionAsInProject(),
- mavenBundle("orbit", "javax.ejb").versionAsInProject(),
- mavenBundle("orbit", "javax.el").versionAsInProject(),
- mavenBundle("orbit", "javax.mail.glassfish").versionAsInProject(),
- mavenBundle("orbit", "javax.xml.rpc").versionAsInProject(),
- mavenBundle("orbit", "org.apache.catalina").versionAsInProject(),
- // these are bundle fragments that can't be started on its own
- mavenBundle("orbit", "org.apache.catalina.ha").versionAsInProject().noStart(),
- mavenBundle("orbit", "org.apache.catalina.tribes").versionAsInProject().noStart(),
- mavenBundle("orbit", "org.apache.coyote").versionAsInProject().noStart(),
- mavenBundle("orbit", "org.apache.jasper").versionAsInProject().noStart(),
-
- mavenBundle("orbit", "org.apache.el").versionAsInProject(),
- mavenBundle("orbit", "org.apache.juli.extras").versionAsInProject(),
- mavenBundle("orbit", "org.apache.tomcat.api").versionAsInProject(),
- mavenBundle("orbit", "org.apache.tomcat.util").versionAsInProject().noStart(),
- mavenBundle("orbit", "javax.servlet.jsp.jstl").versionAsInProject(),
- mavenBundle("orbit", "javax.servlet.jsp.jstl.impl").versionAsInProject(),
-
- mavenBundle("org.ops4j.pax.exam", "pax-exam-container-native").versionAsInProject(),
- mavenBundle("org.ops4j.pax.exam", "pax-exam-junit4").versionAsInProject(),
- mavenBundle("org.ops4j.pax.exam", "pax-exam-link-mvn").versionAsInProject(),
- mavenBundle("org.ops4j.pax.url", "pax-url-aether").versionAsInProject(),
-
- mavenBundle("org.ow2.asm", "asm-all").versionAsInProject(),
-
- mavenBundle("org.springframework", "org.springframework.asm").versionAsInProject(),
- mavenBundle("org.springframework", "org.springframework.aop").versionAsInProject(),
- mavenBundle("org.springframework", "org.springframework.context").versionAsInProject(),
- mavenBundle("org.springframework", "org.springframework.context.support").versionAsInProject(),
- mavenBundle("org.springframework", "org.springframework.core").versionAsInProject(),
- mavenBundle("org.springframework", "org.springframework.beans").versionAsInProject(),
- mavenBundle("org.springframework", "org.springframework.expression").versionAsInProject(),
- mavenBundle("org.springframework", "org.springframework.web").versionAsInProject(),
-
- mavenBundle("org.aopalliance", "com.springsource.org.aopalliance").versionAsInProject(),
- mavenBundle("org.springframework", "org.springframework.web.servlet").versionAsInProject(),
- mavenBundle("org.springframework.security", "spring-security-config").versionAsInProject(),
- mavenBundle("org.springframework.security", "spring-security-core").versionAsInProject(),
- mavenBundle("org.springframework.security", "spring-security-web").versionAsInProject(),
- mavenBundle("org.springframework.security", "spring-security-taglibs").versionAsInProject(),
- mavenBundle("org.springframework", "org.springframework.transaction").versionAsInProject(),
-
- mavenBundle("org.ow2.chameleon.management", "chameleon-mbeans").versionAsInProject(),
- mavenBundle("org.opendaylight.controller.thirdparty", "com.sun.jersey.jersey-servlet")
- .versionAsInProject().startLevel(2),
- mavenBundle("org.opendaylight.controller.thirdparty", "org.apache.catalina.filters.CorsFilter")
- .versionAsInProject().noStart(),
-
- // Jersey needs to be started before the northbound application
- // bundles, using a lower start level
- mavenBundle("com.sun.jersey", "jersey-client").versionAsInProject(),
- mavenBundle("com.sun.jersey", "jersey-server").versionAsInProject().startLevel(2),
- mavenBundle("com.sun.jersey", "jersey-core").versionAsInProject().startLevel(2),
- junitBundles());
- }
-
-}
+++ /dev/null
-#pax.exam.system = default
-pax.exam.logging = none
-pax.exam.service.timeout = 5000
-
+++ /dev/null
-<configuration scan="true">
-
- <appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender">
- <encoder>
- <pattern>%d{HH:mm:ss.SSS} [%thread] %-5level %logger{36} - %msg%n
- </pattern>
- </encoder>
- </appender>
-
- <root level="error">
- <appender-ref ref="STDOUT" />
- </root>
-</configuration>
+++ /dev/null
-<?xml version='1.0' encoding='utf-8'?>
-<!-- Licensed to the Apache Software Foundation (ASF) under one or more contributor
- license agreements. See the NOTICE file distributed with this work for additional
- information regarding copyright ownership. The ASF licenses this file to
- You under the Apache License, Version 2.0 (the "License"); you may not use
- this file except in compliance with the License. You may obtain a copy of
- the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required
- by applicable law or agreed to in writing, software distributed under the
- License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS
- OF ANY KIND, either express or implied. See the License for the specific
- language governing permissions and limitations under the License. -->
-<Server>
- <!--APR library loader. Documentation at /docs/apr.html -->
- <Listener className="org.apache.catalina.core.AprLifecycleListener"
- SSLEngine="on" />
- <!--Initialize Jasper prior to webapps are loaded. Documentation at /docs/jasper-howto.html -->
- <Listener className="org.apache.catalina.core.JasperListener" />
- <!-- Prevent memory leaks due to use of particular java/javax APIs -->
- <Listener className="org.apache.catalina.core.JreMemoryLeakPreventionListener" />
- <Listener
- className="org.apache.catalina.mbeans.GlobalResourcesLifecycleListener" />
- <Listener
- className="org.apache.catalina.core.ThreadLocalLeakPreventionListener" />
-
- <Service name="Catalina">
- <Connector port="8080" protocol="HTTP/1.1"
- connectionTimeout="20000" redirectPort="8443" />
-
- <!-- Please remove the comments around the following Connector tag
- to enable HTTPS Authentication support. Remember to add a valid keystore
- in the configuration folder. More info : http://tomcat.apache.org/tomcat-7.0-doc/ssl-howto.html#Configuration -->
-
- <!-- <Connector port="8443" protocol="HTTP/1.1" SSLEnabled="true"
- maxThreads="150" scheme="https" secure="true" clientAuth="false" sslProtocol="TLS"
- keystoreFile="configuration/keystore" keystorePass="changeit"/> -->
-
- <Engine name="Catalina" defaultHost="localhost">
- <Host name="localhost" appBase="" unpackWARs="false"
- autoDeploy="false" deployOnStartup="false" createDirs="false">
- <!-- Realm
- className="org.opendaylight.controller.security.ControllerCustomRealm" /> -->
- <Valve className="org.apache.catalina.authenticator.SingleSignOn" />
-
- <Valve className="org.apache.catalina.valves.AccessLogValve"
- directory="logs" prefix="web_access_log_" suffix=".txt"
- resolveHosts="false" rotatable="true"
- fileDateFormat="yyyy-MM"
- pattern="%{yyyy-MM-dd HH:mm:ss.SSS z}t - [%a] - %r" />
-
- </Host>
- </Engine>
- </Service>
-</Server>
throw new IllegalStateException(e);
}
logger.info("Configuration Persister initialization completed.");
+
+ /*
+ * We have completed initial configuration. At this point
+ * it is good idea to perform garbage collection to prune
+ * any garbage we have accumulated during startup.
+ */
+ logger.debug("Running post-initialization garbage collection...");
+ System.gc();
+ logger.debug("Post-initialization garbage collection completed.");
+
ConfigPersisterNotificationHandler jmxNotificationHandler = new ConfigPersisterNotificationHandler(platformMBeanServer, persisterAggregator);
synchronized (ConfigPersisterActivator.this) {
autoCloseables.add(jmxNotificationHandler);
synchronized (ConfigPersisterActivator.this) {
autoCloseables.add(new AutoCloseable() {
@Override
- public void close() throws Exception {
+ public void close() {
pushingThread.interrupt();
}
});
</properties>
<dependencies>
- <dependency>
- <groupId>${project.groupId}</groupId>
- <artifactId>sal-binding-it</artifactId>
- <exclusions>
- <!-- FIXME see IdentityRefNetconfTest -->
- <!-- Pax-url-aether contains guava classes e.g. ImmutableSet that clashes with guava and causes tests to fail-->
- <exclusion>
- <groupId>org.ops4j.pax.url</groupId>
- <artifactId>pax-url-aether</artifactId>
- </exclusion>
- </exclusions>
- </dependency>
<dependency>
<groupId>org.opendaylight.controller</groupId>
<artifactId>commons.logback_settings</artifactId>
<artifactId>yang-test</artifactId>
<scope>test</scope>
</dependency>
- <dependency>
- <groupId>org.ops4j.pax.tinybundles</groupId>
- <artifactId>tinybundles</artifactId>
- <version>${tinybundles.version}</version>
- <scope>test</scope>
- </dependency>
</dependencies>
<build>
<forkCount>1</forkCount>
<reuseForks>false</reuseForks>
<perCoreThreadCount>false</perCoreThreadCount>
- <classpathDependencyExcludes>
- <classpathDependencyExcludes>com.google.collections:google-collections</classpathDependencyExcludes>
- <classpathDependencyExcludes>org.ops4j.pax.url:pax-url-aether</classpathDependencyExcludes>
- </classpathDependencyExcludes>
</configuration>
<executions>
<execution>
import static java.util.Collections.emptyList;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNotNull;
-import static org.junit.Assert.assertTrue;
+import static org.junit.Assert.assertThat;
+import static org.junit.Assert.fail;
import static org.mockito.Matchers.anyString;
import static org.mockito.Mockito.doReturn;
import static org.mockito.Mockito.mock;
import javax.management.ObjectName;
import javax.xml.parsers.ParserConfigurationException;
-import junit.framework.Assert;
-
-import org.apache.commons.io.IOUtils;
import org.junit.After;
import org.junit.Before;
import org.junit.Ignore;
import org.junit.Test;
+import org.junit.matchers.JUnitMatchers;
import org.opendaylight.controller.config.manager.impl.factoriesresolver.HardcodedModuleFactoriesResolver;
import org.opendaylight.controller.config.spi.ModuleFactory;
import org.opendaylight.controller.config.util.ConfigTransactionJMXClient;
import org.opendaylight.controller.config.yang.test.impl.DepTestImplModuleFactory;
+import org.opendaylight.controller.config.yang.test.impl.IdentityTestModuleFactory;
import org.opendaylight.controller.config.yang.test.impl.NetconfTestImplModuleFactory;
import org.opendaylight.controller.config.yang.test.impl.NetconfTestImplModuleMXBean;
import org.opendaylight.controller.config.yang.test.impl.TestImplModuleFactory;
-import org.opendaylight.controller.netconf.StubUserManager;
import org.opendaylight.controller.netconf.api.NetconfDocumentedException;
import org.opendaylight.controller.netconf.api.NetconfMessage;
import org.opendaylight.controller.netconf.client.NetconfClientDispatcherImpl;
import org.opendaylight.controller.netconf.impl.osgi.NetconfOperationServiceSnapshotImpl;
import org.opendaylight.controller.netconf.mapping.api.NetconfOperationProvider;
import org.opendaylight.controller.netconf.mapping.api.NetconfOperationService;
-import org.opendaylight.controller.netconf.ssh.NetconfSSHServer;
-import org.opendaylight.controller.netconf.ssh.authentication.AuthProvider;
import org.opendaylight.controller.netconf.util.test.XmlFileLoader;
import org.opendaylight.controller.netconf.util.xml.XmlElement;
import org.opendaylight.controller.netconf.util.xml.XmlUtil;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.controller.config.test.types.rev131127.TestIdentity1;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.controller.config.test.types.rev131127.TestIdentity2;
+import org.opendaylight.yangtools.yang.data.impl.codec.CodecRegistry;
+import org.opendaylight.yangtools.yang.data.impl.codec.IdentityCodec;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.w3c.dom.Document;
import org.w3c.dom.Node;
import org.xml.sax.SAXException;
-import ch.ethz.ssh2.Connection;
-import ch.ethz.ssh2.Session;
-
+import com.google.common.base.Throwables;
import com.google.common.collect.Lists;
import com.google.common.collect.Sets;
import io.netty.channel.ChannelFuture;
static List<ModuleFactory> getModuleFactoriesS() {
return Lists.newArrayList(new TestImplModuleFactory(), new DepTestImplModuleFactory(),
- new NetconfTestImplModuleFactory());
+ new NetconfTestImplModuleFactory(), new IdentityTestModuleFactory());
}
@Test
return netconfClient;
}
- private void startSSHServer() throws Exception {
- logger.info("Creating SSH server");
- StubUserManager um = new StubUserManager(USERNAME, PASSWORD);
- String pem;
- try (InputStream is = getClass().getResourceAsStream("/RSA.pk")) {
- pem = IOUtils.toString(is);
+ @Test
+ public void testIdRef() throws Exception {
+ NetconfMessage editId = XmlFileLoader.xmlFileToNetconfMessage("netconfMessages/editConfig_identities.xml");
+ NetconfMessage commit = XmlFileLoader.xmlFileToNetconfMessage("netconfMessages/commit.xml");
+
+ try (TestingNetconfClient netconfClient = createSession(tcpAddress, "1")) {
+ assertIsOK(netconfClient.sendMessage(editId).getDocument());
+ assertIsOK(netconfClient.sendMessage(commit).getDocument());
+
+ NetconfMessage response = netconfClient.sendMessage(getConfig);
+
+ assertThat(XmlUtil.toString(response.getDocument()), JUnitMatchers.containsString("<prefix:afi xmlns:prefix=\"urn:opendaylight:params:xml:ns:yang:controller:config:test:types\">prefix:test-identity1</prefix:afi>"));
+ assertThat(XmlUtil.toString(response.getDocument()), JUnitMatchers.containsString("<prefix:afi xmlns:prefix=\"urn:opendaylight:params:xml:ns:yang:controller:config:test:types\">prefix:test-identity2</prefix:afi>"));
+ assertThat(XmlUtil.toString(response.getDocument()), JUnitMatchers.containsString("<prefix:safi xmlns:prefix=\"urn:opendaylight:params:xml:ns:yang:controller:config:test:types\">prefix:test-identity2</prefix:safi>"));
+ assertThat(XmlUtil.toString(response.getDocument()), JUnitMatchers.containsString("<prefix:safi xmlns:prefix=\"urn:opendaylight:params:xml:ns:yang:controller:config:test:types\">prefix:test-identity1</prefix:safi>"));
+
+ } catch (Exception e) {
+ fail(Throwables.getStackTraceAsString(e));
}
- AuthProvider ap = new AuthProvider(um, pem);
- Thread sshServerThread = new Thread(NetconfSSHServer.start(10830, tcpAddress, ap));
- sshServerThread.setDaemon(true);
- sshServerThread.start();
- logger.info("SSH server on");
}
- @Test
- public void sshTest() throws Exception {
- startSSHServer();
- logger.info("creating connection");
- Connection conn = new Connection(sshAddress.getHostName(), sshAddress.getPort());
- Assert.assertNotNull(conn);
- logger.info("connection created");
- conn.connect();
- boolean isAuthenticated = conn.authenticateWithPassword(USERNAME, PASSWORD);
- assertTrue(isAuthenticated);
- logger.info("user authenticated");
- final Session sess = conn.openSession();
- sess.startSubSystem("netconf");
- logger.info("user authenticated");
- sess.getStdin().write(XmlUtil.toString(this.getConfig.getDocument()).getBytes());
-
- new Thread() {
- @Override
- public void run() {
- while (true) {
- byte[] bytes = new byte[1024];
- int c = 0;
- try {
- c = sess.getStdout().read(bytes);
- } catch (IOException e) {
- throw new IllegalStateException("IO exception while reading data on ssh bridge.");
- }
- logger.info("got data:" + bytes);
- if (c == 0) {
- break;
- }
- }
- }
- }.join();
- }
+ @Override
+ protected CodecRegistry getCodecRegistry() {
+ final IdentityCodec<?> codec = mock(IdentityCodec.class);
+ doReturn(TestIdentity1.class).when(codec).deserialize(TestIdentity1.QNAME);
+ doReturn(TestIdentity2.class).when(codec).deserialize(TestIdentity2.QNAME);
+ final CodecRegistry ret = super.getCodecRegistry();
+ doReturn(codec).when(ret).getIdentityCodec();
+ return ret;
+ }
}
+++ /dev/null
-/*
-* 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.netconf.it.pax;
-
-import static org.junit.Assert.fail;
-import static org.opendaylight.controller.test.sal.binding.it.TestHelper.baseModelBundles;
-import static org.opendaylight.controller.test.sal.binding.it.TestHelper.bindingAwareSalBundles;
-import static org.opendaylight.controller.test.sal.binding.it.TestHelper.configMinumumBundles;
-import static org.opendaylight.controller.test.sal.binding.it.TestHelper.flowCapableModelBundles;
-import static org.opendaylight.controller.test.sal.binding.it.TestHelper.junitAndMockitoBundles;
-import static org.opendaylight.controller.test.sal.binding.it.TestHelper.mdSalCoreBundles;
-import static org.ops4j.pax.exam.CoreOptions.mavenBundle;
-import static org.ops4j.pax.exam.CoreOptions.options;
-import static org.ops4j.pax.exam.CoreOptions.streamBundle;
-import static org.ops4j.pax.exam.CoreOptions.systemPackages;
-import static org.ops4j.pax.exam.CoreOptions.systemProperty;
-
-import io.netty.util.HashedWheelTimer;
-import io.netty.util.Timer;
-import java.io.IOException;
-import java.net.InetSocketAddress;
-import java.util.concurrent.ExecutionException;
-import java.util.concurrent.TimeoutException;
-
-import javax.xml.parsers.ParserConfigurationException;
-
-import org.junit.Assert;
-import org.junit.Ignore;
-import org.junit.Test;
-import org.junit.matchers.JUnitMatchers;
-import org.junit.runner.RunWith;
-import org.opendaylight.controller.netconf.api.NetconfMessage;
-import org.opendaylight.controller.netconf.client.NetconfClientDispatcherImpl;
-import org.opendaylight.controller.netconf.client.SimpleNetconfClientSessionListener;
-import org.opendaylight.controller.netconf.client.conf.NetconfClientConfiguration;
-import org.opendaylight.controller.netconf.client.conf.NetconfClientConfigurationBuilder;
-import org.opendaylight.controller.netconf.client.test.TestingNetconfClient;
-import org.opendaylight.controller.netconf.util.test.XmlFileLoader;
-import org.opendaylight.controller.netconf.util.xml.XmlUtil;
-import org.opendaylight.controller.sal.binding.api.BindingAwareBroker;
-import org.opendaylight.protocol.framework.NeverReconnectStrategy;
-import org.ops4j.pax.exam.Configuration;
-import org.ops4j.pax.exam.Option;
-import org.ops4j.pax.exam.junit.PaxExam;
-import org.ops4j.pax.exam.options.DefaultCompositeOption;
-import org.ops4j.pax.exam.util.Filter;
-import org.ops4j.pax.tinybundles.core.TinyBundles;
-import org.osgi.framework.Constants;
-import org.xml.sax.SAXException;
-
-import com.google.common.base.Preconditions;
-import com.google.common.base.Throwables;
-
-import io.netty.channel.nio.NioEventLoopGroup;
-import io.netty.util.concurrent.GlobalEventExecutor;
-
-@Ignore
-@RunWith(PaxExam.class)
-public class IdentityRefNetconfTest {
-
- public static final int CLIENT_CONNECTION_TIMEOUT_MILLIS = 15000;
-
- // Wait for controller to start
-
- // FIXME move this (pax) test to different module
- // pax jars contain guava classes that clash with real guava dependencies in non-pax tests
- //
- //@Inject
- @Filter(timeout = 60 * 1000)
- BindingAwareBroker broker;
-
- @Configuration
- public Option[] config() {
- return options(
- systemProperty("osgi.console").value("2401"),
- systemProperty("osgi.bundles.defaultStartLevel").value("4"),
- systemProperty("pax.exam.osgi.unresolved.fail").value("true"),
- systemPackages("sun.nio.ch"),
-
- testingModules(),
- loggingModules(),
- mdSalCoreBundles(),
- bindingAwareSalBundles(), configMinumumBundles(), baseModelBundles(), flowCapableModelBundles(),
- junitAndMockitoBundles(),
-
- // Classes from test-jars bundled for pax-exam test
- streamBundle(TinyBundles.bundle()
- .add(TestingNetconfClient.class)
- .add(XmlFileLoader.class)
-
- .add("/netconfMessages/editConfig_identities.xml",
- XmlFileLoader.class.getResource("/netconfMessages/editConfig_identities.xml"))
- .add("/netconfMessages/commit.xml",
- XmlFileLoader.class.getResource("/netconfMessages/commit.xml"))
- .add("/netconfMessages/getConfig.xml",
- XmlFileLoader.class.getResource("/netconfMessages/getConfig.xml"))
-
- .set(Constants.BUNDLE_SYMBOLICNAME, "TestingClient_bundle")
- .set(Constants.EXPORT_PACKAGE, "org.opendaylight.controller.netconf.client.test, " +
- "org.opendaylight.controller.netconf.util.test")
- .build(TinyBundles.withBnd())));
- }
-
- private Option loggingModules() {
- return new DefaultCompositeOption(
- mavenBundle("org.slf4j", "slf4j-api").versionAsInProject(),
- mavenBundle("org.slf4j", "log4j-over-slf4j").versionAsInProject(),
- mavenBundle("ch.qos.logback", "logback-core").versionAsInProject(),
- mavenBundle("ch.qos.logback", "logback-classic").versionAsInProject(),
- mavenBundle("org.openexi", "nagasena").versionAsInProject(),
- mavenBundle("org.openexi", "nagasena-rta").versionAsInProject());
-
-
- }
-
- private Option testingModules() {
- return new DefaultCompositeOption(
- mavenBundle("org.opendaylight.controller", "yang-test").versionAsInProject());
- }
-
- private static final InetSocketAddress tcpAddress = new InetSocketAddress("127.0.0.1", 18383);
-
- @Test
- public void testIdRef() throws Exception {
- Preconditions.checkNotNull(broker, "Controller not initialized");
-
-
- NetconfMessage edit = xmlFileToNetconfMessage("netconfMessages/editConfig_identities.xml");
- NetconfMessage commit = xmlFileToNetconfMessage("netconfMessages/commit.xml");
- NetconfMessage getConfig = xmlFileToNetconfMessage("netconfMessages/getConfig.xml");
-
- NioEventLoopGroup nettyThreadgroup = new NioEventLoopGroup();
- Timer timer = new HashedWheelTimer();
- NetconfClientDispatcherImpl clientDispatcher = new NetconfClientDispatcherImpl(nettyThreadgroup, nettyThreadgroup, timer);
- try (TestingNetconfClient netconfClient = new TestingNetconfClient("client", clientDispatcher, getClientConfiguration(tcpAddress))) {
- sendMessage(edit, netconfClient);
- sendMessage(commit, netconfClient);
- sendMessage(getConfig, netconfClient, "id-test",
- "<prefix:afi xmlns:prefix=\"urn:opendaylight:params:xml:ns:yang:controller:config:test:types\">prefix:test-identity1</prefix:afi>",
- "<prefix:afi xmlns:prefix=\"urn:opendaylight:params:xml:ns:yang:controller:config:test:types\">prefix:test-identity2</prefix:afi>",
- "<prefix:safi xmlns:prefix=\"urn:opendaylight:params:xml:ns:yang:controller:config:test:types\">prefix:test-identity2</prefix:safi>",
- "<prefix:safi xmlns:prefix=\"urn:opendaylight:params:xml:ns:yang:controller:config:test:types\">prefix:test-identity1</prefix:safi>");
-
- clientDispatcher.close();
- } catch (Exception e) {
- fail(Throwables.getStackTraceAsString(e));
- } finally {
- nettyThreadgroup.shutdownGracefully().get();
- timer.stop();
- }
- }
-
- private void sendMessage(NetconfMessage edit, TestingNetconfClient netconfClient, String... containingResponse)
- throws ExecutionException, InterruptedException, TimeoutException {
- NetconfMessage response = netconfClient.sendRequest(edit).get();
- if (containingResponse == null) {
- Assert.assertThat(XmlUtil.toString(response.getDocument()), JUnitMatchers.containsString("<ok/>"));
- } else {
- for (String resp : containingResponse) {
- Assert.assertThat(XmlUtil.toString(response.getDocument()), JUnitMatchers.containsString(resp));
- }
- }
- }
-
- public static NetconfMessage xmlFileToNetconfMessage(final String fileName) throws IOException, SAXException,
- ParserConfigurationException {
- return XmlFileLoader.xmlFileToNetconfMessage(fileName);
- }
-
- public NetconfClientConfiguration getClientConfiguration(final InetSocketAddress tcpAddress) {
- final NetconfClientConfigurationBuilder b = NetconfClientConfigurationBuilder.create();
- b.withAddress(tcpAddress);
- b.withSessionListener(new SimpleNetconfClientSessionListener());
- b.withReconnectStrategy(new NeverReconnectStrategy(GlobalEventExecutor.INSTANCE,
- CLIENT_CONNECTION_TIMEOUT_MILLIS));
- b.withConnectionTimeoutMillis(CLIENT_CONNECTION_TIMEOUT_MILLIS);
- return b.build();
- }
-}
+++ /dev/null
------BEGIN RSA PRIVATE KEY-----
-MIIEogIBAAKCAQEAuC9hbEacpewvylI0mwFwjy3Wou2hpr/ncN9BBiFDSaG5yW2k
-3Oy+SCAcFCL+ZKWb6cc6Ch4gUeCwyEHRojZguuhliKtak9YQf6qbvpPLe00842Lx
-iqNAGurMpzizCDsGFq8ChaAkBZQI3TvcHuPoSUWSMJ+K8xHpRyUdVr6g2yEjezKJ
-sTXBtWaeCCh6YUafFujuDJk7fvYcPW7Je5KRBBStIKvxcMW0zB+7eq04deTHwGbJ
-gGjKWilQ72hsDDP3Hbp5CJMAYg1r4GlCmFx3KyHRGztgWgNgaD7nNpKCkTLjtmA6
-b4x7TA+jrzZ6Af2z5TMrI4dv5w1SrxHaZ+ziLQIDAQABAoIBAHTndeGgq/rQf8De
-Do+4CTaHtK0zQSAyu/azbXUzlZ7drKuCEVs8VMY4wzmwwGEnkF+A2YDkgEUX5X0l
-8aYQ97KKoS9u+43MGCrAIhyDeGrpqlT1TzRcy+qJz53v6gq2U/X/3QztiQ+VV078
-mIluxNgE9XYxPaNsYfGLSCTv1+9c8y/hjGVX2kwFK+u4ut0ZZETggNa8UxfaHVDS
-fIJQX9Gm3J3GSUV30fDGMBIUW6ESLc2L8b7u8Mp9TRP39ZeQSuEUjBe8MYKv0Rel
-oEpjZvcnniMTpFbLpndBYn7/AoIiEBvtCN8faVTuRRcvvLcsRm09IctzKQYnMh6M
-6PLKV+ECgYEA8HFRYaKHUzxpzE/fyon82GQbzqFFY0/bbWrfWICMfNbIgshJUie6
-FmH5iUFMfeqaT7v557HFM0GB9FeIeSbvd88YmiBAcRopZ3DfMkDH+DT73yJ+/TKG
-2nrQtdhyuTIs4bwHqeS2BBJYs7PK9R2rratF3l34Tf7mjlvyOgygHdUCgYEAxBo2
-8hEBlAVNcNb1hTYUxe1w1B6675/mFlmw98Xmj9dRYfICXNhahs8tX3/lsBEd+vBu
-fI0oyHaff8m5bPgGzD1ZMybfeROujNrgxaKVk7Ef0FDRRCop4bm18OroFlFAt9l8
-wMp++ToACbdvQvL/mjWMPYlIxhB/YxHswICZZvkCgYAexxKYwdo6sGAGlC7cWT9x
-X5cjowcjyEQZRHXkeUgCbufpvcOM7aLnXJE5nY8yCwbHsBM0MlBA2GDPKylAANjk
-aDEJAZneIHAuWodngl1Wi0m2bU7+ECqs6s2uiU9eH2sZVh1RBQK7kLGkBx6ys6KX
-L3ZZGYRAT6GplWFzRsx0JQKBgCeVlxPD5QqpC1nEumi6YvUVGdpnnZpzL3HBhxxs
-wT612wKnZFyze4qM1X7ahVXGDsQxtkvD/sCAWW/lG13orw6ZL6FIroF1PJ3ILOkY
-CZN3hJF7TtKwpCWhZB2OfWzL2AGEkE8mUP0j/Q/5DCd6f6f0OSvOw3bfq6cm3iB5
-lP2ZAoGAXsRN5TZTX4AQ2xTlrDQ8A5XgcvyWQpJOmEXMTyHV7VaJVzmNWFVAvndK
-5UIq8ALDwB2t7vjmMUW6euvIwqtXiop7G79UOb3e3NhzeyWFGQyBLqCRznGaXQTT
-dlFy73xhukZMhFnj006bjKCYvOPnwuGl3+0fuWil5Rq3jOuY5c8=
------END RSA PRIVATE KEY-----
+++ /dev/null
-<?xml version="1.0" encoding="UTF-8"?>
-<persisted-snapshots>
- <snapshots>
- <snapshot>
- <required-capabilities>
- <capability>urn:opendaylight:params:xml:ns:yang:controller:config:test:types?module=test-types&revision=2013-11-27</capability>
- <capability>urn:opendaylight:params:xml:ns:yang:controller:config?module=config&revision=2013-04-05</capability>
- <capability>urn:opendaylight:params:xml:ns:yang:controller:logback:config?module=config-logging&revision=2013-07-16</capability>
- <capability>urn:opendaylight:params:xml:ns:yang:controller:md:sal:binding:impl?module=opendaylight-sal-binding-broker-impl&revision=2013-10-28</capability>
- <capability>urn:opendaylight:params:xml:ns:yang:controller:md:sal:binding?module=opendaylight-md-sal-binding&revision=2013-10-28</capability>
- <capability>urn:opendaylight:params:xml:ns:yang:controller:md:sal:dom:impl?module=opendaylight-sal-dom-broker-impl&revision=2013-10-28</capability>
- <capability>urn:opendaylight:params:xml:ns:yang:controller:md:sal:dom?module=opendaylight-md-sal-dom&revision=2013-10-28</capability>
- <capability>urn:opendaylight:params:xml:ns:yang:controller:test:impl?module=config-test-impl&revision=2013-04-03</capability>
- <capability>urn:opendaylight:params:xml:ns:yang:controller:test?module=config-test&revision=2013-06-13</capability>
- </required-capabilities>
- <configuration>
- <data xmlns="urn:ietf:params:xml:ns:netconf:base:1.0">
- <modules xmlns="urn:opendaylight:params:xml:ns:yang:controller:config">
- <module>
- <prefix:type xmlns:prefix="urn:opendaylight:params:xml:ns:yang:controller:test:impl">prefix:impl-identity-test</prefix:type>
- <prefix:name xmlns:prefix="urn:opendaylight:params:xml:ns:yang:controller:test:impl">id-test</prefix:name>
- <identities-container xmlns="urn:opendaylight:params:xml:ns:yang:controller:test:impl">
- <prefix:afi xmlns:prefix="urn:opendaylight:params:xml:ns:yang:controller:config:test:types">prefix:test-identity2</prefix:afi>
- </identities-container>
- <identities xmlns="urn:opendaylight:params:xml:ns:yang:controller:test:impl">
- <prefix:safi xmlns:prefix="urn:opendaylight:params:xml:ns:yang:controller:config:test:types">prefix:test-identity2</prefix:safi>
- <prefix:afi xmlns:prefix="urn:opendaylight:params:xml:ns:yang:controller:config:test:types">prefix:test-identity1</prefix:afi>
- </identities>
- <identities xmlns="urn:opendaylight:params:xml:ns:yang:controller:test:impl">
- <prefix:safi xmlns:prefix="urn:opendaylight:params:xml:ns:yang:controller:config:test:types">prefix:test-identity1</prefix:safi>
- <prefix:afi xmlns:prefix="urn:opendaylight:params:xml:ns:yang:controller:config:test:types">prefix:test-identity2</prefix:afi>
- </identities>
- <prefix:afi xmlns:prefix="urn:opendaylight:params:xml:ns:yang:controller:config:test:types">prefix:test-identity1</prefix:afi>
- </module>
- <module>
- <prefix:type xmlns:prefix="urn:opendaylight:params:xml:ns:yang:controller:md:sal:binding:impl">prefix:binding-broker-impl</prefix:type>
- <prefix:name xmlns:prefix="urn:opendaylight:params:xml:ns:yang:controller:md:sal:binding:impl">binding-broker-impl</prefix:name>
- <notification-service xmlns="urn:opendaylight:params:xml:ns:yang:controller:md:sal:binding:impl">
- <prefix:type xmlns:prefix="urn:opendaylight:params:xml:ns:yang:controller:md:sal:binding">prefix:binding-notification-service</prefix:type>
- <name>ref_binding-notification-broker</name>
- </notification-service>
- <data-broker xmlns="urn:opendaylight:params:xml:ns:yang:controller:md:sal:binding:impl">
- <prefix:type xmlns:prefix="urn:opendaylight:params:xml:ns:yang:controller:md:sal:binding">prefix:binding-data-broker</prefix:type>
- <name>ref_binding-data-broker</name>
- </data-broker>
- </module>
- <module>
- <prefix:type xmlns:prefix="urn:opendaylight:params:xml:ns:yang:controller:md:sal:binding:impl">prefix:runtime-generated-mapping</prefix:type>
- <prefix:name xmlns:prefix="urn:opendaylight:params:xml:ns:yang:controller:md:sal:binding:impl">runtime-mapping-singleton</prefix:name>
- </module>
- <module>
- <prefix:type xmlns:prefix="urn:opendaylight:params:xml:ns:yang:controller:md:sal:binding:impl">prefix:binding-notification-broker</prefix:type>
- <prefix:name xmlns:prefix="urn:opendaylight:params:xml:ns:yang:controller:md:sal:binding:impl">binding-notification-broker</prefix:name>
- </module>
- <module>
- <prefix:type xmlns:prefix="urn:opendaylight:params:xml:ns:yang:controller:md:sal:binding:impl">prefix:binding-data-broker</prefix:type>
- <prefix:name xmlns:prefix="urn:opendaylight:params:xml:ns:yang:controller:md:sal:binding:impl">binding-data-broker</prefix:name>
- <dom-broker xmlns="urn:opendaylight:params:xml:ns:yang:controller:md:sal:binding:impl">
- <prefix:type xmlns:prefix="urn:opendaylight:params:xml:ns:yang:controller:md:sal:dom">prefix:dom-broker-osgi-registry</prefix:type>
- <name>ref_dom-broker</name>
- </dom-broker>
- <mapping-service xmlns="urn:opendaylight:params:xml:ns:yang:controller:md:sal:binding:impl">
- <prefix:type xmlns:prefix="urn:opendaylight:params:xml:ns:yang:controller:md:sal:binding:impl">prefix:binding-dom-mapping-service</prefix:type>
- <name>ref_runtime-mapping-singleton</name>
- </mapping-service>
- </module>
- <module>
- <prefix:type xmlns:prefix="urn:opendaylight:params:xml:ns:yang:controller:logback:config">prefix:logback</prefix:type>
- <prefix:name xmlns:prefix="urn:opendaylight:params:xml:ns:yang:controller:logback:config">singleton</prefix:name>
- <console-appenders xmlns="urn:opendaylight:params:xml:ns:yang:controller:logback:config">
- <threshold-filter>DEBUG</threshold-filter>
- <name>console</name>
- <encoder-pattern>%d{HH:mm:ss.SSS} [%thread] %-5level %logger{36} - %msg%n</encoder-pattern>
- </console-appenders>
- <loggers xmlns="urn:opendaylight:params:xml:ns:yang:controller:logback:config">
- <level>DEBUG</level>
- <logger-name>ROOT</logger-name>
- <appenders>console</appenders>
- </loggers>
- </module>
- <module>
- <prefix:type xmlns:prefix="urn:opendaylight:params:xml:ns:yang:controller:md:sal:dom:impl">prefix:schema-service-singleton</prefix:type>
- <prefix:name xmlns:prefix="urn:opendaylight:params:xml:ns:yang:controller:md:sal:dom:impl">yang-schema-service</prefix:name>
- </module>
- <module>
- <prefix:type xmlns:prefix="urn:opendaylight:params:xml:ns:yang:controller:md:sal:dom:impl">prefix:hash-map-data-store</prefix:type>
- <prefix:name xmlns:prefix="urn:opendaylight:params:xml:ns:yang:controller:md:sal:dom:impl">hash-map-data-store</prefix:name>
- </module>
- <module>
- <prefix:type xmlns:prefix="urn:opendaylight:params:xml:ns:yang:controller:md:sal:dom:impl">prefix:dom-broker-impl</prefix:type>
- <prefix:name xmlns:prefix="urn:opendaylight:params:xml:ns:yang:controller:md:sal:dom:impl">dom-broker</prefix:name>
- <data-store xmlns="urn:opendaylight:params:xml:ns:yang:controller:md:sal:dom:impl">
- <prefix:type xmlns:prefix="urn:opendaylight:params:xml:ns:yang:controller:md:sal:dom">prefix:dom-data-store</prefix:type>
- <name>ref_hash-map-data-store</name>
- </data-store>
- </module>
- </modules>
- <services xmlns="urn:opendaylight:params:xml:ns:yang:controller:config">
- <service>
- <prefix:type xmlns:prefix="urn:opendaylight:params:xml:ns:yang:controller:md:sal:dom">prefix:schema-service</prefix:type>
- <instance>
- <name>ref_yang-schema-service</name>
- <provider>/modules/module[type='schema-service-singleton'][name='yang-schema-service']</provider>
- </instance>
- </service>
- <service>
- <prefix:type xmlns:prefix="urn:opendaylight:params:xml:ns:yang:controller:md:sal:dom">prefix:dom-data-store</prefix:type>
- <instance>
- <name>ref_hash-map-data-store</name>
- <provider>/modules/module[type='hash-map-data-store'][name='hash-map-data-store']</provider>
- </instance>
- </service>
- <service>
- <prefix:type xmlns:prefix="urn:opendaylight:params:xml:ns:yang:controller:md:sal:dom">prefix:dom-broker-osgi-registry</prefix:type>
- <instance>
- <name>ref_dom-broker</name>
- <provider>/modules/module[type='dom-broker-impl'][name='dom-broker']</provider>
- </instance>
- </service>
- <service>
- <prefix:type xmlns:prefix="urn:opendaylight:params:xml:ns:yang:controller:test">prefix:testing</prefix:type>
- <instance>
- <name>ref_id-test</name>
- <provider>/modules/module[type='impl-identity-test'][name='id-test']</provider>
- </instance>
- </service>
- <service>
- <prefix:type xmlns:prefix="urn:opendaylight:params:xml:ns:yang:controller:md:sal:binding:impl">prefix:binding-dom-mapping-service</prefix:type>
- <instance>
- <name>ref_runtime-mapping-singleton</name>
- <provider>/modules/module[type='runtime-generated-mapping'][name='runtime-mapping-singleton']</provider>
- </instance>
- </service>
- <service>
- <prefix:type xmlns:prefix="urn:opendaylight:params:xml:ns:yang:controller:md:sal:binding">prefix:binding-data-consumer-broker</prefix:type>
- <instance>
- <name>ref_binding-data-broker</name>
- <provider>/modules/module[type='binding-data-broker'][name='binding-data-broker']</provider>
- </instance>
- </service>
- <service>
- <prefix:type xmlns:prefix="urn:opendaylight:params:xml:ns:yang:controller:md:sal:binding">prefix:binding-rpc-registry</prefix:type>
- <instance>
- <name>ref_binding-broker-impl</name>
- <provider>/modules/module[type='binding-broker-impl'][name='binding-broker-impl']</provider>
- </instance>
- </service>
- <service>
- <prefix:type xmlns:prefix="urn:opendaylight:params:xml:ns:yang:controller:md:sal:binding">prefix:binding-notification-service</prefix:type>
- <instance>
- <name>ref_binding-notification-broker</name>
- <provider>/modules/module[type='binding-notification-broker'][name='binding-notification-broker']</provider>
- </instance>
- </service>
- <service>
- <prefix:type xmlns:prefix="urn:opendaylight:params:xml:ns:yang:controller:md:sal:binding">prefix:binding-broker-osgi-registry</prefix:type>
- <instance>
- <name>ref_binding-broker-impl</name>
- <provider>/modules/module[type='binding-broker-impl'][name='binding-broker-impl']</provider>
- </instance>
- </service>
- <service>
- <prefix:type xmlns:prefix="urn:opendaylight:params:xml:ns:yang:controller:md:sal:binding">prefix:binding-notification-subscription-service</prefix:type>
- <instance>
- <name>ref_binding-notification-broker</name>
- <provider>/modules/module[type='binding-notification-broker'][name='binding-notification-broker']</provider>
- </instance>
- </service>
- <service>
- <prefix:type xmlns:prefix="urn:opendaylight:params:xml:ns:yang:controller:md:sal:binding">prefix:binding-data-broker</prefix:type>
- <instance>
- <name>ref_binding-data-broker</name>
- <provider>/modules/module[type='binding-data-broker'][name='binding-data-broker']</provider>
- </instance>
- </service>
- </services>
- </data>
- </configuration>
- </snapshot>
- </snapshots>
-</persisted-snapshots>
+++ /dev/null
-<rpc xmlns="urn:ietf:params:xml:ns:netconf:base:1.0" message-id="101">
- <commit></commit>
-</rpc>
+++ /dev/null
-<rpc id="a" a="64" xmlnx="a:b:c:d" xmlns="urn:ietf:params:xml:ns:netconf:base:1.0" message-id="101">
- <get-config>
- <source>
- <running/>
- </source>
- </get-config>
-</rpc>
package org.opendaylight.controller.networkconfig.neutron.northbound;
import java.util.ArrayList;
+import java.util.Collections;
+import java.util.Comparator;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import javax.ws.rs.Consumes;
import javax.ws.rs.DELETE;
+import javax.ws.rs.DefaultValue;
import javax.ws.rs.GET;
import javax.ws.rs.POST;
import javax.ws.rs.PUT;
import javax.ws.rs.PathParam;
import javax.ws.rs.Produces;
import javax.ws.rs.QueryParam;
+import javax.ws.rs.core.Context;
import javax.ws.rs.core.MediaType;
+import javax.ws.rs.core.UriInfo;
import javax.ws.rs.core.Response;
import org.codehaus.enunciate.jaxrs.ResponseCode;
@Path("/networks")
public class NeutronNetworksNorthbound {
+ @Context
+ UriInfo uriInfo;
+
private NeutronNetwork extractFields(NeutronNetwork o, List<String> fields) {
return o.extractFields(fields);
}
//@TypeHint(OpenStackNetworks.class)
@StatusCodes({
@ResponseCode(code = 200, condition = "Operation successful"),
- @ResponseCode(code = 401, condition = "Unauthorized") })
+ @ResponseCode(code = 401, condition = "Unauthorized")})
public Response listNetworks(
// return fields
@QueryParam("fields") List<String> fields,
@QueryParam("provider_physical_network") String queryProviderPhysicalNetwork,
@QueryParam("provider_segmentation_id") String queryProviderSegmentationID,
// pagination
- @QueryParam("limit") String limit,
+ @QueryParam("limit") Integer limit,
@QueryParam("marker") String marker,
- @QueryParam("page_reverse") String pageReverse
+ @DefaultValue("false") @QueryParam("page_reverse") Boolean pageReverse
// sorting not supported
) {
INeutronNetworkCRUD networkInterface = NeutronCRUDInterfaces.getINeutronNetworkCRUD( this);
}
}
}
- //TODO: apply pagination to results
- return Response.status(200).entity(
- new NeutronNetworkRequest(ans)).build();
+
+ Comparator<NeutronNetwork> neutronNetworkComparator = new Comparator<NeutronNetwork>() {
+ @Override
+ public int compare(NeutronNetwork o1, NeutronNetwork o2) {
+ return o1.getID().compareTo(o2.getID());
+ }
+ };
+
+ Collections.sort(ans, neutronNetworkComparator);
+
+ if (limit != null && ans.size() > 1) {
+ List<NeutronPageLink> links = new ArrayList<>();
+ Integer startPos = null;
+ String startMarker;
+ String endMarker;
+ Boolean firstPage = false;
+ Boolean lastPage = false;
+
+ if (marker == null) {
+ startPos = 0;
+ }
+
+ else {
+
+ NeutronNetwork markerNetwork = new NeutronNetwork();
+ markerNetwork.setNetworkUUID(marker);
+
+ startPos = Collections.binarySearch(ans, markerNetwork, neutronNetworkComparator);
+
+ if (!pageReverse){
+ startPos = startPos + 1;
+ }
+ else {
+ startPos = startPos - limit;
+ }
+
+ }
+
+ if (startPos == null) {
+ throw new ResourceNotFoundException("UUID for marker:" + marker + " could not be found");
+ }
+
+ if (startPos == 0){
+ firstPage = true;
+ }
+
+ if (startPos + limit >= ans.size()) {
+ ans = ans.subList(startPos, ans.size());
+ startMarker = ans.get(0).getID();
+ endMarker = ans.get(ans.size() - 1).getID();
+ lastPage = true;
+ }
+ else if (startPos < 0) {
+ if (startPos + limit > 0) {
+ ans = ans.subList(0, startPos + limit);
+ startMarker = ans.get(0).getID();
+ endMarker = ans.get(ans.size() - 1).getID();
+ firstPage = true;
+ }
+ else {
+ throw new BadRequestException("Requested page is out of bounds. Please check the supplied limit and marker");
+ }
+ }
+ else {
+ ans = ans.subList(startPos, startPos + limit);
+ startMarker = ans.get(0).getID();
+ endMarker = ans.get(limit-1).getID();
+ }
+
+ if (!lastPage) {
+ NeutronPageLink next = new NeutronPageLink();
+ next.setRef("next");
+ next.setHref(uriInfo.getAbsolutePath().toString() + "?limit=" + limit.toString() + "&marker=" + endMarker);
+ links.add(next);
+ }
+
+ if (!firstPage) {
+ NeutronPageLink previous = new NeutronPageLink();
+ previous.setRef("previous");
+ previous.setHref(uriInfo.getAbsolutePath().toString() + "?limit=" + limit.toString() + "&marker=" + startMarker + "&page_reverse=True");
+ links.add(previous);
+ }
+
+ return Response.status(200).entity(new PaginatedNeutronNetworkRequest(ans, links)).build();
+ }
+
+ return Response.status(200).entity(new NeutronNetworkRequest(ans)).build();
+
}
/**
--- /dev/null
+/*
+ * Copyright (C) 2014 Hewlett-Packard Development Company L.P
+ *
+ * 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
+ *
+ * Authors : Dave Tucker
+ */
+
+package org.opendaylight.controller.networkconfig.neutron.northbound;
+
+import javax.xml.bind.annotation.XmlAccessType;
+import javax.xml.bind.annotation.XmlAccessorType;
+import javax.xml.bind.annotation.XmlElement;
+import javax.xml.bind.annotation.XmlRootElement;
+
+@XmlRootElement
+@XmlAccessorType(XmlAccessType.NONE)
+
+public class NeutronPageLink {
+
+ @XmlElement(name="ref")
+ String ref;
+
+ @XmlElement (name="href")
+ String href;
+
+ public String getRef() {
+ return ref;
+ }
+
+ public void setRef(String ref) {
+ this.ref = ref;
+ }
+
+ public String getHref() {
+ return href;
+ }
+
+ public void setHref(String href) {
+ this.href = href;
+ }
+}
\ No newline at end of file
--- /dev/null
+/*
+ * Copyright (C) 2014 Hewlett-Packard Development Company L.P
+ *
+ * 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
+ *
+ * Authors : Dave Tucker
+ */
+
+package org.opendaylight.controller.networkconfig.neutron.northbound;
+
+import org.opendaylight.controller.networkconfig.neutron.NeutronNetwork;
+
+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 PaginatedNeutronNetworkRequest {
+
+ @XmlElement (name="networks")
+ List<NeutronNetwork> networks;
+
+ @XmlElement (name="network_links")
+ List<NeutronPageLink> networkLinks;
+
+ public PaginatedNeutronNetworkRequest() {
+ }
+
+ public PaginatedNeutronNetworkRequest(List<NeutronNetwork> networks, List<NeutronPageLink> networkLinks) {
+ this.networks = networks;
+ this.networkLinks = networkLinks;
+ }
+
+ public List<NeutronNetwork> getNetworks() {
+ return networks;
+ }
+
+ public void setNetworks(List<NeutronNetwork> networks) {
+ this.networks = networks;
+ }
+
+ public List<NeutronPageLink> getNetworkLinks() {
+ return networkLinks;
+ }
+
+ public void setNetworkLinks(List<NeutronPageLink> networkLinks) {
+ this.networkLinks = networkLinks;
+ }
+}
return NorthboundUtils.getResponse(status);
}
+ /**
+ * Get a property of a node
+ *
+ * @param containerName
+ * Name of the Container (Eg. 'SliceRed')
+ * @param nodeType
+ * Type of the node being programmed (Eg. 'OF')
+ * @param nodeId
+ * Node Identifier as specified by
+ * {@link org.opendaylight.controller.sal.core.Node} (Eg.
+ * '00:00:00:00:00:03:01:02')
+ * @param propertyName
+ * Name of the Property. Properties that can be deleted are
+ * description, forwarding(only in default container) and tier.
+ * @return Property value of the property
+ *
+ * <pre>
+ *
+ * Example:
+ *
+ * Request URL:
+ * http://localhost:8080/controller/nb/v2/switchmanager/default/node/OF/00:00:00:00:00:00:00:01/property/description
+ *
+ * Response body in XML
+ * <description>
+ *   <value>switch1</value>
+ * </description>
+ *
+ * Response body in JSON
+ * {
+ *   "value": "switch1"
+ * }
+ * </pre>
+ */
+
+ @Path("/{containerName}/node/{nodeType}/{nodeId}/property/{propertyName}")
+ @GET
+ @Produces({ MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML })
+ @TypeHint(String.class)
+ @StatusCodes({ @ResponseCode(code = 200, condition = "Operation successful"),
+ @ResponseCode(code = 401, condition = "User not authorized to perform this operation"),
+ @ResponseCode(code = 404, condition = "The containerName is not found"),
+ @ResponseCode(code = 503, condition = "One or more of Controller Services are unavailable") })
+ public Property getNodeProperty(@PathParam("containerName") String containerName,
+ @PathParam("nodeType") String nodeType, @PathParam("nodeId") String nodeId,
+ @PathParam("propertyName") String propertyName) {
+
+ if (!isValidContainer(containerName)) {
+ throw new ResourceNotFoundException("Container " + containerName + " does not exist.");
+ }
+ if (!NorthboundUtils.isAuthorized(getUserName(), containerName, Privilege.READ, this)) {
+ throw new UnauthorizedException("User is not authorized to perform this operation on container "
+ + containerName);
+ }
+ ISwitchManager switchManager = getIfSwitchManagerService(containerName);
+ if (switchManager == null) {
+ throw new ServiceUnavailableException("Switch Manager " + RestMessages.SERVICEUNAVAILABLE.toString());
+ }
+
+ handleNodeAvailability(containerName, nodeType, nodeId);
+ Node node = Node.fromString(nodeType, nodeId);
+ if (node == null) {
+ throw new ResourceNotFoundException(nodeId + " : " + RestMessages.NONODE.toString());
+ }
+ SwitchConfig switchConfig = switchManager.getSwitchConfig(node.toString());
+ if (switchConfig == null) {
+ throw new ResourceNotFoundException(nodeId + " : " + "Config Not Found" );
+ } else {
+ Map<String, Property> nodeProperties = new HashMap<String, Property>(switchConfig.getNodeProperties());
+ if (!nodeProperties.containsKey(propertyName.toLowerCase())) {
+ String msg = "Property " + propertyName + " does not exist or not "
+ + "configured for switch " + nodeId;
+ throw new ResourceNotFoundException(msg);
+ } else {
+ return nodeProperties.get(propertyName.toLowerCase());
+ }
+ }
+ }
+
/**
*
* Retrieve a list of all the nodeconnectors and their properties in a given
*/
@Override
public void notifyNodeDisconnectFromMaster(Node node) {
- for (String pluginType : this.pluginService.keySet()) {
- IPluginInConnectionService s = pluginService.get(pluginType);
- s.notifyNodeDisconnectFromMaster(node);
+ IPluginInConnectionService s = pluginService.get(node.getType());
+ if (s != null) {
+ s.notifyNodeDisconnectFromMaster(node);
}
}
-}
\ No newline at end of file
+}
import org.opendaylight.controller.sal.reader.NodeDescription;
import org.opendaylight.controller.sal.utils.GlobalConstants;
import org.opendaylight.controller.sal.utils.IObjectReader;
+import org.opendaylight.controller.sal.utils.ServiceHelper;
import org.opendaylight.controller.sal.utils.Status;
import org.opendaylight.controller.sal.utils.StatusCode;
import org.opendaylight.controller.statisticsmanager.IStatisticsManager;
ForwardingMode mode = (ForwardingMode) nodeProperties.get(ForwardingMode.name);
forwardingModeChanged = mode.isProactive();
}
+ } else if ((conf == null) && !(GlobalConstants.DEFAULT.toString().equals(containerName))) {
+ ISwitchManager defaultSwitchManager = (ISwitchManager) ServiceHelper.getInstance(ISwitchManager.class, GlobalConstants.DEFAULT.toString(), this);
+ if (defaultSwitchManager != null) {
+ Property defaultContainerSwitchDesc = (Description) defaultSwitchManager.getNodeProp(node, Description.propertyName);
+ if (defaultContainerSwitchDesc != null) {
+ Map<String, Property> descPropMap = new HashMap<String, Property>();
+ descPropMap.put(Description.propertyName, defaultContainerSwitchDesc);
+ conf = new SwitchConfig(nodeId, descPropMap);
+ updateNodeConfig(conf);
+ propMap.put(Description.propertyName, defaultContainerSwitchDesc);
+ }
+ }
}
}
<module>opendaylight/commons/parent</module>
<module>opendaylight/commons/logback_settings</module>
- <!-- Karaf Distribution
- <module>feature</module> -->
+ <!-- Karaf Distribution -->
+ <module>features/base</module>
<module>opendaylight/dummy-console</module>
<module>opendaylight/distribution/opendaylight-karaf</module>
</modules>