<arphandler.version>0.5.2-SNAPSHOT</arphandler.version>
<forwarding.staticrouting>0.5.2-SNAPSHOT</forwarding.staticrouting>
<samples.loadbalancer>0.5.2-SNAPSHOT</samples.loadbalancer>
- <config.version>0.2.4-SNAPSHOT</config.version>
- <netconf.version>0.2.4-SNAPSHOT</netconf.version>
+ <config.version>0.2.5-SNAPSHOT</config.version>
+ <netconf.version>0.2.5-SNAPSHOT</netconf.version>
<mdsal.version>1.1-SNAPSHOT</mdsal.version>
<containermanager.version>0.5.2-SNAPSHOT</containermanager.version>
<containermanager.it.version>0.5.2-SNAPSHOT</containermanager.it.version>
<java.version.target>1.7</java.version.target>
<!-- enforcer version -->
<enforcer.version>1.3.1</enforcer.version>
+ <xtend.version>2.4.3</xtend.version>
+ <xtend.dstdir>${project.build.directory}/generated-sources/xtend-gen</xtend.dstdir>
</properties>
<dependencyManagement>
</dependency>
<!-- md-sal -->
+ <dependency>
+ <groupId>org.eclipse.xtend</groupId>
+ <artifactId>org.eclipse.xtend.lib</artifactId>
+ <version>${xtend.version}</version>
+ </dependency>
<dependency>
<groupId>org.opendaylight.controller</groupId>
<artifactId>sal-common</artifactId>
<artifactId>config-persister-impl</artifactId>
<version>${netconf.version}</version>
</dependency>
- <dependency>
- <groupId>${project.groupId}</groupId>
- <artifactId>ietf-netconf-monitoring</artifactId>
- <version>${netconf.version}</version>
- </dependency>
- <dependency>
- <groupId>${project.groupId}</groupId>
- <artifactId>ietf-netconf-monitoring-extension</artifactId>
- <version>${netconf.version}</version>
- </dependency>
<!-- threadpool -->
<dependency>
<testTarget>${java.version.target}</testTarget>
</configuration>
</plugin>
+ <plugin>
+ <groupId>org.eclipse.xtend</groupId>
+ <artifactId>xtend-maven-plugin</artifactId>
+ <version>${xtend.version}</version>
+ <executions>
+ <execution>
+ <goals>
+ <goal>compile</goal>
+ </goals>
+ <configuration>
+ <outputDirectory>${xtend.dstdir}</outputDirectory>
+ </configuration>
+ </execution>
+ </executions>
+ </plugin>
</plugins>
</pluginManagement>
</build>
}
@Override
+ @SuppressWarnings("unchecked")
protected final void channelRead0(final ChannelHandlerContext ctx, final Object msg) {
LOG.debug("Message was received: {}", msg);
handleMessage((M) msg);
}
@Override
+ @SuppressWarnings("unchecked")
public final void channelRead(final ChannelHandlerContext ctx, final Object msg) {
LOG.debug("Negotiation read invoked on channel {}", channel);
try {
<parent>
<artifactId>config-subsystem</artifactId>
<groupId>org.opendaylight.controller</groupId>
- <version>0.2.4-SNAPSHOT</version>
+ <version>0.2.5-SNAPSHOT</version>
</parent>
<artifactId>config-api</artifactId>
* transaction was committed after creating this transaction. Clients can create
* new transaction and merge the changes.
*/
-public class ConflictingVersionException extends RuntimeException {
+public class ConflictingVersionException extends Exception {
private static final long serialVersionUID = 1L;
public ConflictingVersionException() {
@ConstructorProperties(QNAME_ATTR_NAME)
public IdentityAttributeRef(String qNameOfIdentity) {
- if (qNameOfIdentity == null)
+ if (qNameOfIdentity == null) {
throw new NullPointerException("Parameter " + QNAME_ATTR_NAME + " is null");
+ }
this.qNameOfIdentity = qNameOfIdentity;
}
@Override
public boolean equals(Object o) {
- if (this == o) return true;
- if (!(o instanceof IdentityAttributeRef)) return false;
+ if (this == o) {
+ return true;
+ }
+ if (!(o instanceof IdentityAttributeRef)) {
+ return false;
+ }
IdentityAttributeRef that = (IdentityAttributeRef) o;
- if (!qNameOfIdentity.equals(that.qNameOfIdentity)) return false;
+ if (!qNameOfIdentity.equals(that.qNameOfIdentity)) {
+ return false;
+ }
return true;
}
private final String attributeName;
public JmxAttribute(String attributeName) {
- if (attributeName == null)
+ if (attributeName == null) {
throw new NullPointerException("Parameter 'attributeName' is null");
+ }
this.attributeName = attributeName;
}
@Override
public boolean equals(Object o) {
- if (this == o)
+ if (this == o) {
return true;
- if (o == null || getClass() != o.getClass())
+ }
+ if (o == null || getClass() != o.getClass()) {
return false;
+ }
JmxAttribute that = (JmxAttribute) o;
if (attributeName != null ? !attributeName.equals(that.attributeName)
- : that.attributeName != null)
+ : that.attributeName != null) {
return false;
+ }
return true;
}
private final String factoryName, instanceName;
public ModuleIdentifier(String factoryName, String instanceName) {
- if (factoryName == null)
- throw new IllegalArgumentException(
- "Parameter 'factoryName' is null");
- if (instanceName == null)
- throw new IllegalArgumentException(
- "Parameter 'instanceName' is null");
+ if (factoryName == null) {
+ throw new IllegalArgumentException("Parameter 'factoryName' is null");
+ }
+ if (instanceName == null) {
+ throw new IllegalArgumentException("Parameter 'instanceName' is null");
+ }
this.factoryName = factoryName;
this.instanceName = instanceName;
}
@Override
public boolean equals(Object o) {
- if (this == o)
+ if (this == o) {
return true;
- if (o == null || getClass() != o.getClass())
+ }
+ if (o == null || getClass() != o.getClass()) {
return false;
+ }
ModuleIdentifier that = (ModuleIdentifier) o;
- if (!factoryName.equals(that.factoryName))
+ if (!factoryName.equals(that.factoryName)) {
return false;
- if (!instanceName.equals(that.instanceName))
+ }
+ if (!instanceName.equals(that.instanceName)) {
return false;
+ }
return true;
}
/**
* This exception is not intended to be used while implementing modules,
- * itaggregates validation exceptions and sends them back to the user.
+ * it aggregates validation exceptions and sends them back to the user.
+ * Use {@link org.opendaylight.controller.config.api.JmxAttributeValidationException} for
+ * validating modules instead.
*/
-public class ValidationException extends RuntimeException {
+public class ValidationException extends Exception {
private static final long serialVersionUID = -6072893219820274247L;
private final Map<String/* module name */, Map<String/* instance name */, ExceptionMessageWithStackTrace>> failedValidations;
@Override
public boolean equals(Object obj) {
- if (this == obj)
+ if (this == obj) {
return true;
- if (obj == null)
+ }
+ if (obj == null) {
return false;
- if (getClass() != obj.getClass())
+ }
+ if (getClass() != obj.getClass()) {
return false;
+ }
ExceptionMessageWithStackTrace other = (ExceptionMessageWithStackTrace) obj;
if (message == null) {
- if (other.message != null)
+ if (other.message != null) {
return false;
- } else if (!message.equals(other.message))
+ }
+ } else if (!message.equals(other.message)) {
return false;
+ }
if (stackTrace == null) {
- if (other.stackTrace != null)
+ if (other.stackTrace != null) {
return false;
- } else if (!stackTrace.equals(other.stackTrace))
+ }
+ } else if (!stackTrace.equals(other.stackTrace)) {
return false;
+ }
return true;
}
*/
package org.opendaylight.controller.config.api.jmx;
+import javax.annotation.concurrent.Immutable;
+import javax.management.ObjectName;
import java.beans.ConstructorProperties;
import java.util.Collections;
import java.util.List;
-import javax.annotation.concurrent.Immutable;
-import javax.management.ObjectName;
-
@Immutable
public class CommitStatus {
private final List<ObjectName> newInstances, reusedInstances,
recreatedInstances;
/**
- *
- * @param newInstances
- * newly created instances
- * @param reusedInstances
- * reused instances
- * @param recreatedInstances
- * recreated instances
+ * @param newInstances newly created instances
+ * @param reusedInstances reused instances
+ * @param recreatedInstances recreated instances
*/
- @ConstructorProperties({ "newInstances", "reusedInstances",
- "recreatedInstances" })
+ @ConstructorProperties({"newInstances", "reusedInstances",
+ "recreatedInstances"})
public CommitStatus(List<ObjectName> newInstances,
- List<ObjectName> reusedInstances,
- List<ObjectName> recreatedInstances) {
+ List<ObjectName> reusedInstances,
+ List<ObjectName> recreatedInstances) {
this.newInstances = Collections.unmodifiableList(newInstances);
this.reusedInstances = Collections.unmodifiableList(reusedInstances);
this.recreatedInstances = Collections
}
/**
- *
* @return list of objectNames representing newly created instances
*/
public List<ObjectName> getNewInstances() {
}
/**
- *
* @return list of objectNames representing reused instances
*/
public List<ObjectName> getReusedInstances() {
}
/**
- *
* @return list of objectNames representing recreated instances
*/
public List<ObjectName> getRecreatedInstances() {
result = prime
* result
+ ((recreatedInstances == null) ? 0 : recreatedInstances
- .hashCode());
+ .hashCode());
result = prime * result
+ ((reusedInstances == null) ? 0 : reusedInstances.hashCode());
return result;
@Override
public boolean equals(Object obj) {
- if (this == obj)
+ if (this == obj) {
return true;
- if (obj == null)
+ }
+ if (obj == null) {
return false;
- if (getClass() != obj.getClass())
+ }
+ if (getClass() != obj.getClass()) {
return false;
+ }
CommitStatus other = (CommitStatus) obj;
if (newInstances == null) {
- if (other.newInstances != null)
+ if (other.newInstances != null) {
return false;
- } else if (!newInstances.equals(other.newInstances))
+ }
+ } else if (!newInstances.equals(other.newInstances)) {
return false;
+ }
if (recreatedInstances == null) {
- if (other.recreatedInstances != null)
+ if (other.recreatedInstances != null) {
return false;
- } else if (!recreatedInstances.equals(other.recreatedInstances))
+ }
+ } else if (!recreatedInstances.equals(other.recreatedInstances)) {
return false;
+ }
if (reusedInstances == null) {
- if (other.reusedInstances != null)
+ if (other.reusedInstances != null) {
return false;
- } else if (!reusedInstances.equals(other.reusedInstances))
+ }
+ } else if (!reusedInstances.equals(other.reusedInstances)) {
return false;
+ }
return true;
}
import org.opendaylight.controller.config.api.jmx.constants.ConfigRegistryConstants;
import javax.annotation.concurrent.ThreadSafe;
+import javax.management.MalformedObjectNameException;
import javax.management.ObjectName;
import java.util.Arrays;
import java.util.HashMap;
public static ObjectName createON(String on) {
try {
return new ObjectName(on);
- } catch (Exception e) {
- throw new RuntimeException(e);
+ } catch (MalformedObjectNameException e) {
+ throw new IllegalArgumentException(e);
}
}
Hashtable<String, String> table = new Hashtable<>(attribs);
try {
return new ObjectName(domain, table);
- } catch (Exception e) {
- throw new RuntimeException(e);
+ } catch (MalformedObjectNameException e) {
+ throw new IllegalArgumentException(e);
}
}
public static String getServiceQName(ObjectName objectName) {
checkType(objectName, TYPE_SERVICE_REFERENCE);
String quoted = objectName.getKeyProperty(SERVICE_QNAME_KEY);
- String result = unquoteAndUnescape(objectName, quoted);
- return result;
+ return unquoteAndUnescape(objectName, quoted);
}
// ObjectName supports quotation and ignores tokens like =, but fails to ignore ? sign.
}
}
- public static void checkTypeOneOf(ObjectName objectName, String ... types) {
- for(String type: types) {
+ public static void checkTypeOneOf(ObjectName objectName, String... types) {
+ for (String type : types) {
if (type.equals(objectName.getKeyProperty(TYPE_KEY))) {
return;
}
public static ObjectName createModulePattern(String moduleName,
String instanceName) {
- if (moduleName == null)
+ if (moduleName == null) {
moduleName = "*";
- if (instanceName == null)
+ }
+ if (instanceName == null) {
instanceName = "*";
+ }
// do not return object names containing transaction name
ObjectName namePattern = ObjectNameUtil
.createON(ObjectNameUtil.ON_DOMAIN + ":"
String expectedType) {
checkType(objectName, expectedType);
String factoryName = getFactoryName(objectName);
- if (factoryName == null)
+ if (factoryName == null) {
throw new IllegalArgumentException(
"ObjectName does not contain module name");
+ }
String instanceName = getInstanceName(objectName);
- if (instanceName == null)
+ if (instanceName == null) {
throw new IllegalArgumentException(
"ObjectName does not contain instance name");
+ }
return new ModuleIdentifier(factoryName, instanceName);
}
*/
package org.opendaylight.controller.config.api.jmx.constants;
+import javax.management.MalformedObjectNameException;
import javax.management.ObjectName;
public class ConfigRegistryConstants {
public static final ObjectName OBJECT_NAME = createONWithDomainAndType(TYPE_CONFIG_REGISTRY);
- public static String GET_AVAILABLE_MODULE_NAMES_ATTRIBUT_NAME = "AvailableModuleNames";
+ public static final String GET_AVAILABLE_MODULE_NAMES_ATTRIBUT_NAME = "AvailableModuleNames";
public static ObjectName createONWithDomainAndType(String type) {
return createON(ON_DOMAIN, TYPE_KEY, type);
public static ObjectName createON(String name, String key, String value) {
try {
return new ObjectName(name, key, value);
- } catch (Exception e) {
- throw new RuntimeException(e);
+ } catch (MalformedObjectNameException e) {
+ throw new IllegalArgumentException(e);
}
}
*/
package org.opendaylight.controller.config.spi;
-import javax.annotation.concurrent.NotThreadSafe;
-
import org.opendaylight.controller.config.api.ModuleIdentifier;
import org.opendaylight.yangtools.concepts.Identifiable;
+import javax.annotation.concurrent.NotThreadSafe;
+
/**
* Represents one service that is to be configured. These methods need to be
* ConfigBeans.
* <p>
* In order to guide dependency resolution, the setter method should be
- * annotated with {@link RequireInterface}.
+ * annotated with {@link org.opendaylight.controller.config.api.annotations.RequireInterface}.
* </p>
* <p>
* Thread safety note: implementations of this interface are not required to be
* Returns 'live' object that was configured using this object. It is
* allowed to call this method only after all ConfigBeans were validated. In
* this method new resources might be opened or old instance might be
- * modified. Note that when obtaining dependent Module using
- * {@link org.opendaylight.controller.config.api.DependencyResolver#validateDependency(Class, javax.management.ObjectName, String)}
- * a proxy will be created that will disallow calling this method before
- * second commit phase begins.
+ * modified. This method must be implemented so that it returns same
+ * result for a single transaction. Since Module is created per transaction
+ * this means that it must be safe to cache result of first call.
+ *
*
* @return closeable instance: After bundle update the factory might be able
* to copy old configuration into new one without being able to cast
<parent>
<artifactId>config-subsystem</artifactId>
<groupId>org.opendaylight.controller</groupId>
- <version>0.2.4-SNAPSHOT</version>
+ <version>0.2.5-SNAPSHOT</version>
<relativePath>..</relativePath>
</parent>
<artifactId>config-manager</artifactId>
<dependency>
<groupId>com.google.guava</groupId>
<artifactId>guava</artifactId>
- <scope>test</scope>
</dependency>
<dependency>
<groupId>org.opendaylight.yangtools</groupId>
import javax.annotation.concurrent.Immutable;
import org.opendaylight.controller.config.api.ModuleIdentifier;
+import org.opendaylight.controller.config.manager.impl.dependencyresolver.DestroyedModule;
+import org.opendaylight.controller.config.manager.impl.dependencyresolver.ModuleInternalTransactionalInfo;
/**
* Structure obtained during first phase commit, contains destroyed modules from
*/
package org.opendaylight.controller.config.manager.impl;
+import com.google.common.collect.Maps;
import org.opendaylight.controller.config.api.ConflictingVersionException;
import org.opendaylight.controller.config.api.ModuleIdentifier;
import org.opendaylight.controller.config.api.RuntimeBeanRegistratorAwareModule;
import org.opendaylight.controller.config.api.ValidationException;
import org.opendaylight.controller.config.api.jmx.CommitStatus;
import org.opendaylight.controller.config.api.jmx.ObjectNameUtil;
+import org.opendaylight.controller.config.manager.impl.dependencyresolver.DestroyedModule;
+import org.opendaylight.controller.config.manager.impl.dependencyresolver.ModuleInternalTransactionalInfo;
import org.opendaylight.controller.config.manager.impl.dynamicmbean.DynamicReadableWrapper;
import org.opendaylight.controller.config.manager.impl.factoriesresolver.HierarchicalConfigMBeanFactoriesHolder;
import org.opendaylight.controller.config.manager.impl.factoriesresolver.ModuleFactoriesResolver;
private List<ModuleFactory> lastListOfFactories = Collections.emptyList();
@GuardedBy("this") // switched in every 2ndPC
- private CloseableServiceReferenceReadableRegistry readableSRRegistry = ServiceReferenceRegistryImpl.createInitialSRLookupRegistry();
+ private CloseableServiceReferenceReadableRegistry readableSRRegistry = ServiceReferenceRegistryImpl.createInitialSRLookupRegistry();
// constructor
public ConfigRegistryImpl(ModuleFactoriesResolver resolver,
- MBeanServer configMBeanServer, CodecRegistry codecRegistry) {
+ MBeanServer configMBeanServer, CodecRegistry codecRegistry) {
this(resolver, configMBeanServer,
new BaseJMXRegistrator(configMBeanServer), codecRegistry);
}
// constructor
public ConfigRegistryImpl(ModuleFactoriesResolver resolver,
- MBeanServer configMBeanServer,
- BaseJMXRegistrator baseJMXRegistrator, CodecRegistry codecRegistry) {
+ MBeanServer configMBeanServer,
+ BaseJMXRegistrator baseJMXRegistrator, CodecRegistry codecRegistry) {
this.resolver = resolver;
this.beanToOsgiServiceManager = new BeanToOsgiServiceManager();
this.configMBeanServer = configMBeanServer;
throw new IllegalStateException(e);
}
transactionController.copyExistingModulesAndProcessFactoryDiff(currentConfig.getEntries(), lastListOfFactories);
- transactionsHolder.add(transactionName, transactionController);
+ transactionsHolder.add(transactionName, transactionController, txLookupRegistry);
return transactionController;
}
* {@inheritDoc}
*/
@Override
+ @SuppressWarnings("PMD.AvoidCatchingThrowable")
public synchronized CommitStatus commitConfig(ObjectName transactionControllerON)
throws ConflictingVersionException, ValidationException {
final String transactionName = ObjectNameUtil
logger.trace("About to commit {}. Current parentVersion: {}, versionCounter {}", transactionName, version, versionCounter);
// find ConfigTransactionController
- Map<String, ConfigTransactionControllerInternal> transactions = transactionsHolder.getCurrentTransactions();
- ConfigTransactionControllerInternal configTransactionController = transactions.get(transactionName);
- if (configTransactionController == null) {
+ Map<String, Entry<ConfigTransactionControllerInternal, ConfigTransactionLookupRegistry>> transactions = transactionsHolder.getCurrentTransactions();
+ Entry<ConfigTransactionControllerInternal, ConfigTransactionLookupRegistry> configTransactionControllerEntry = transactions.get(transactionName);
+ if (configTransactionControllerEntry == null) {
throw new IllegalArgumentException(String.format(
"Transaction with name '%s' not found", transactionName));
}
+ ConfigTransactionControllerInternal configTransactionController = configTransactionControllerEntry.getKey();
// check optimistic lock
if (version != configTransactionController.getParentVersion()) {
throw new ConflictingVersionException(
lastListOfFactories = Collections.unmodifiableList(configTransactionController.getCurrentlyRegisteredFactories());
// non recoverable from here:
try {
- return secondPhaseCommit(
- configTransactionController, commitInfo);
+ return secondPhaseCommit(configTransactionController, commitInfo, configTransactionControllerEntry.getValue());
} catch (Throwable t) { // some libs throw Errors: e.g.
- // javax.xml.ws.spi.FactoryFinder$ConfigurationError
+ // javax.xml.ws.spi.FactoryFinder$ConfigurationError
isHealthy = false;
logger.error("Configuration Transaction failed on 2PC, server is unhealthy", t);
if (t instanceof RuntimeException) {
}
private CommitStatus secondPhaseCommit(ConfigTransactionControllerInternal configTransactionController,
- CommitInfo commitInfo) {
+ CommitInfo commitInfo, ConfigTransactionLookupRegistry txLookupRegistry) {
// close instances which were destroyed by the user, including
// (hopefully) runtime beans
for (DestroyedModule toBeDestroyed : commitInfo
.getDestroyedFromPreviousTransactions()) {
toBeDestroyed.close(); // closes instance (which should close
- // runtime jmx registrator),
+ // runtime jmx registrator),
// also closes osgi registration and ModuleJMXRegistrator
// registration
currentConfig.remove(toBeDestroyed.getIdentifier());
.getRuntimeBeanRegistrator();
}
// set runtime jmx registrator if required
- Module module = entry.getModule();
+ Module module = entry.getProxiedModule();
if (module instanceof RuntimeBeanRegistratorAwareModule) {
((RuntimeBeanRegistratorAwareModule) module)
.setRuntimeBeanRegistrator(runtimeBeanRegistrator);
}
// can register runtime beans
- List<ModuleIdentifier> orderedModuleIdentifiers = configTransactionController
- .secondPhaseCommit();
+ List<ModuleIdentifier> orderedModuleIdentifiers = configTransactionController.secondPhaseCommit();
+ txLookupRegistry.close();
+ configTransactionController.close();
// copy configuration to read only mode
List<ObjectName> newInstances = new LinkedList<>();
for (ModuleIdentifier moduleIdentifier : orderedModuleIdentifiers) {
ModuleInternalTransactionalInfo entry = commitInfo.getCommitted()
.get(moduleIdentifier);
- if (entry == null)
+ if (entry == null) {
throw new NullPointerException("Module not found "
+ moduleIdentifier);
- Module module = entry.getModule();
+ }
+
ObjectName primaryReadOnlyON = ObjectNameUtil
.createReadOnlyModuleON(moduleIdentifier);
.createModuleJMXRegistrator();
OsgiRegistration osgiRegistration = null;
+ AutoCloseable instance = entry.getProxiedModule().getInstance();
if (entry.hasOldModule()) {
ModuleInternalInfo oldInternalInfo = entry.getOldInternalInfo();
DynamicReadableWrapper oldReadableConfigBean = oldInternalInfo.getReadableModule();
currentConfig.remove(entry.getIdentifier());
// test if old instance == new instance
- if (oldReadableConfigBean.getInstance().equals(module.getInstance())) {
+ if (oldReadableConfigBean.getInstance().equals(instance)) {
// reused old instance:
// wrap in readable dynamic mbean
reusedInstances.add(primaryReadOnlyON);
// wrap in readable dynamic mbean
newInstances.add(primaryReadOnlyON);
}
+ Module realModule = entry.getRealModule();
DynamicReadableWrapper newReadableConfigBean = new DynamicReadableWrapper(
- module, module.getInstance(), moduleIdentifier,
+ realModule, instance, moduleIdentifier,
registryMBeanServer, configMBeanServer);
// register to JMX
// register to OSGi
if (osgiRegistration == null) {
ModuleFactory moduleFactory = entry.getModuleFactory();
- if(moduleFactory != null) {
+ if (moduleFactory != null) {
BundleContext bc = configTransactionController.
getModuleFactoryBundleContext(moduleFactory.getImplementationName());
- osgiRegistration = beanToOsgiServiceManager.registerToOsgi(module.getClass(),
+ osgiRegistration = beanToOsgiServiceManager.registerToOsgi(realModule.getClass(),
newReadableConfigBean.getInstance(), entry.getIdentifier(), bc);
} else {
throw new NullPointerException(entry.getIdentifier().getFactoryName() + " ModuleFactory not found.");
runtimeBeanRegistrator, newModuleJMXRegistrator,
orderingIdx, entry.isDefaultBean());
- newConfigEntries.put(module, newInfo);
+ newConfigEntries.put(realModule, newInfo);
orderingIdx++;
}
currentConfig.addAll(newConfigEntries.values());
*/
@Override
public synchronized List<ObjectName> getOpenConfigs() {
- Map<String, ConfigTransactionControllerInternal> transactions = transactionsHolder
+ Map<String, Entry<ConfigTransactionControllerInternal, ConfigTransactionLookupRegistry>> transactions = transactionsHolder
.getCurrentTransactions();
List<ObjectName> result = new ArrayList<>(transactions.size());
- for (ConfigTransactionControllerInternal configTransactionController : transactions
+ for (Entry<ConfigTransactionControllerInternal, ConfigTransactionLookupRegistry> configTransactionControllerEntry : transactions
.values()) {
- result.add(configTransactionController.getControllerObjectName());
+ result.add(configTransactionControllerEntry.getKey().getControllerObjectName());
}
return result;
}
@Override
public synchronized void close() {
// abort transactions
- Map<String, ConfigTransactionControllerInternal> transactions = transactionsHolder
+ Map<String, Entry<ConfigTransactionControllerInternal, ConfigTransactionLookupRegistry>> transactions = transactionsHolder
.getCurrentTransactions();
- for (ConfigTransactionControllerInternal configTransactionController : transactions
+ for (Entry<ConfigTransactionControllerInternal, ConfigTransactionLookupRegistry> configTransactionControllerEntry : transactions
.values()) {
+
+ ConfigTransactionControllerInternal configTransactionController = configTransactionControllerEntry.getKey();
try {
+ configTransactionControllerEntry.getValue().close();
configTransactionController.abortConfig();
} catch (RuntimeException e) {
logger.warn("Ignoring exception while aborting {}",
*/
@Override
public Set<ObjectName> lookupConfigBeans(String moduleName,
- String instanceName) {
+ String instanceName) {
ObjectName namePattern = ObjectNameUtil.createModulePattern(moduleName,
instanceName);
return baseJMXRegistrator.queryNames(namePattern, null);
*/
@Override
public Set<ObjectName> lookupRuntimeBeans(String moduleName,
- String instanceName) {
- if (moduleName == null)
+ String instanceName) {
+ if (moduleName == null) {
moduleName = "*";
- if (instanceName == null)
+ }
+ if (instanceName == null) {
instanceName = "*";
+ }
ObjectName namePattern = ObjectNameUtil.createRuntimeBeanPattern(
moduleName, instanceName);
return baseJMXRegistrator.queryNames(namePattern, null);
* {@link ConfigTransactionControllerInternal} instances, because platform
* MBeanServer transforms mbeans into another representation. Map is cleaned
* every time current transactions are requested.
- *
*/
@GuardedBy("ConfigRegistryImpl.this")
- private final Map<String /* transactionName */, ConfigTransactionControllerInternal> transactions = new HashMap<>();
+ private final Map<String /* transactionName */,
+ Entry<ConfigTransactionControllerInternal, ConfigTransactionLookupRegistry>> transactions = new HashMap<>();
/**
* Can only be called from within synchronized method.
*/
public void add(String transactionName,
- ConfigTransactionControllerInternal transactionController) {
+ ConfigTransactionControllerInternal transactionController, ConfigTransactionLookupRegistry txLookupRegistry) {
Object oldValue = transactions.put(transactionName,
- transactionController);
+ Maps.immutableEntry(transactionController, txLookupRegistry));
if (oldValue != null) {
throw new IllegalStateException(
"Error: two transactions with same name");
*
* @return current view on transactions map.
*/
- public Map<String, ConfigTransactionControllerInternal> getCurrentTransactions() {
+ public Map<String, Entry<ConfigTransactionControllerInternal, ConfigTransactionLookupRegistry>> getCurrentTransactions() {
// first, remove closed transaction
- for (Iterator<Entry<String, ConfigTransactionControllerInternal>> it = transactions
- .entrySet().iterator(); it.hasNext();) {
- Entry<String, ConfigTransactionControllerInternal> entry = it
+ for (Iterator<Entry<String, Entry<ConfigTransactionControllerInternal, ConfigTransactionLookupRegistry>>> it = transactions
+ .entrySet().iterator(); it.hasNext(); ) {
+ Entry<String, Entry<ConfigTransactionControllerInternal, ConfigTransactionLookupRegistry>> entry = it
.next();
- if (entry.getValue().isClosed()) {
+ if (entry.getValue().getKey().isClosed()) {
it.remove();
}
}
import org.opendaylight.controller.config.api.ValidationException;
import org.opendaylight.controller.config.api.jmx.ObjectNameUtil;
import org.opendaylight.controller.config.manager.impl.dependencyresolver.DependencyResolverManager;
+import org.opendaylight.controller.config.manager.impl.dependencyresolver.ModuleInternalTransactionalInfo;
import org.opendaylight.controller.config.manager.impl.dynamicmbean.DynamicWritableWrapper;
import org.opendaylight.controller.config.manager.impl.dynamicmbean.ReadOnlyAtomicBoolean;
import org.opendaylight.controller.config.manager.impl.dynamicmbean.ReadOnlyAtomicBoolean.ReadOnlyAtomicBooleanImpl;
class ConfigTransactionControllerImpl implements
ConfigTransactionControllerInternal,
ConfigTransactionControllerImplMXBean,
- Identifiable<TransactionIdentifier>{
+ Identifiable<TransactionIdentifier> {
private static final Logger logger = LoggerFactory.getLogger(ConfigTransactionControllerImpl.class);
private final ConfigTransactionLookupRegistry txLookupRegistry;
this.currentlyRegisteredFactories = currentlyRegisteredFactories;
this.factoriesHolder = new HierarchicalConfigMBeanFactoriesHolder(currentlyRegisteredFactories);
this.transactionStatus = new TransactionStatus();
- this.dependencyResolverManager = new DependencyResolverManager(transactionName, transactionStatus, writableSRRegistry, codecRegistry);
+ this.dependencyResolverManager = new DependencyResolverManager(txLookupRegistry.getTransactionIdentifier(),
+ transactionStatus, writableSRRegistry, codecRegistry);
this.transactionsMBeanServer = transactionsMBeanServer;
this.configMBeanServer = configMBeanServer;
this.blankTransaction = blankTransaction;
List<ModuleFactory> toBeAdded = new ArrayList<>();
List<ModuleFactory> toBeRemoved = new ArrayList<>();
- for(ModuleFactory moduleFactory: factoriesHolder.getModuleFactories()) {
- if (oldSet.contains(moduleFactory) == false){
+ for (ModuleFactory moduleFactory : factoriesHolder.getModuleFactories()) {
+ if (oldSet.contains(moduleFactory) == false) {
toBeAdded.add(moduleFactory);
}
}
- for(ModuleFactory moduleFactory: lastListOfFactories){
+ for (ModuleFactory moduleFactory : lastListOfFactories) {
if (newSet.contains(moduleFactory) == false) {
toBeRemoved.add(moduleFactory);
}
}
// remove modules belonging to removed factories
- for(ModuleFactory removedFactory: toBeRemoved){
+ for (ModuleFactory removedFactory : toBeRemoved) {
List<ModuleIdentifier> modulesOfRemovedFactory = dependencyResolverManager.findAllByFactory(removedFactory);
for (ModuleIdentifier name : modulesOfRemovedFactory) {
destroyModule(name);
@Override
public synchronized ObjectName createModule(String factoryName,
- String instanceName) throws InstanceAlreadyExistsException {
+ String instanceName) throws InstanceAlreadyExistsException {
transactionStatus.checkNotCommitStarted();
transactionStatus.checkNotAborted();
throws InstanceAlreadyExistsException {
logger.debug("Adding module {} to transaction {}", moduleIdentifier, this);
- if (moduleIdentifier.equals(module.getIdentifier())==false) {
+ if (moduleIdentifier.equals(module.getIdentifier()) == false) {
throw new IllegalStateException("Incorrect name reported by module. Expected "
- + moduleIdentifier + ", got " + module.getIdentifier());
+ + moduleIdentifier + ", got " + module.getIdentifier());
}
- if (dependencyResolver.getIdentifier().equals(moduleIdentifier) == false ) {
+ if (dependencyResolver.getIdentifier().equals(moduleIdentifier) == false) {
throw new IllegalStateException("Incorrect name reported by dependency resolver. Expected "
+ moduleIdentifier + ", got " + dependencyResolver.getIdentifier());
}
// put wrapper to jmx
TransactionModuleJMXRegistration transactionModuleJMXRegistration = getTxModuleJMXRegistrator()
.registerMBean(writableDynamicWrapper, writableON);
- ModuleInternalTransactionalInfo moduleInternalTransactionalInfo = new ModuleInternalTransactionalInfo(
+
+ dependencyResolverManager.put(
moduleIdentifier, module, moduleFactory,
maybeOldConfigBeanInfo, transactionModuleJMXRegistration, isDefaultBean);
-
- dependencyResolverManager.put(moduleInternalTransactionalInfo);
return writableON;
}
// first remove refNames, it checks for objectname existence
try {
writableSRRegistry.removeServiceReferences(
- ObjectNameUtil.createTransactionModuleON(getTransactionName(),moduleIdentifier));
+ ObjectNameUtil.createTransactionModuleON(getTransactionName(), moduleIdentifier));
} catch (InstanceNotFoundException e) {
logger.error("Possible code error: cannot find {} in {}", moduleIdentifier, writableSRRegistry);
throw new IllegalStateException("Possible code error: cannot find " + moduleIdentifier, e);
@Override
public synchronized void validateConfig() throws ValidationException {
- if (configBeanModificationDisabled.get())
+ if (configBeanModificationDisabled.get()) {
throw new IllegalStateException("Cannot start validation");
+ }
configBeanModificationDisabled.set(true);
try {
validate_noLocks();
logger.error("Commit failed on {} in transaction {}", name,
getTransactionIdentifier(), e);
internalAbort();
- throw new RuntimeException(
+ throw new IllegalStateException(
format("Error - getInstance() failed for %s in transaction %s",
name, getTransactionIdentifier()), e);
}
logger.trace("Committed configuration {}", getTransactionIdentifier());
transactionStatus.setCommitted();
- // unregister this and all modules from jmx
- close();
return dependencyResolverManager.getSortedModuleIdentifiers();
}
}
public void close() {
- //FIXME: should not close object that was retrieved in constructor, a wrapper object should do that perhaps
- txLookupRegistry.close();
+ dependencyResolverManager.close();
}
@Override
return writableSRRegistry;
}
+ @Override
public TransactionIdentifier getTransactionIdentifier() {
return txLookupRegistry.getTransactionIdentifier();
}
* and {@link ConfigRegistryImpl} (consumer).
*/
interface ConfigTransactionControllerInternal extends
- ConfigTransactionControllerImplMXBean {
+ ConfigTransactionControllerImplMXBean, AutoCloseable {
ServiceReferenceWritableRegistry getWritableRegistry();
+ TransactionIdentifier getTransactionIdentifier();
+
+ @Override
+ void close();
}
--- /dev/null
+package org.opendaylight.controller.config.manager.impl;
+
+import org.opendaylight.controller.config.api.ModuleIdentifier;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import javax.annotation.Nullable;
+import javax.annotation.concurrent.GuardedBy;
+import java.util.concurrent.TimeUnit;
+
+public class DeadlockMonitor implements AutoCloseable {
+ private static final Logger logger = LoggerFactory.getLogger(DeadlockMonitorRunnable.class);
+
+ private static final long WARN_AFTER_MILLIS = 5000;
+
+ private final TransactionIdentifier transactionIdentifier;
+ private final DeadlockMonitorRunnable thread;
+ @GuardedBy("this")
+ private ModuleIdentifierWithNanos moduleIdentifierWithNanos = new ModuleIdentifierWithNanos();
+
+ public DeadlockMonitor(TransactionIdentifier transactionIdentifier) {
+ this.transactionIdentifier = transactionIdentifier;
+ thread = new DeadlockMonitorRunnable();
+ thread.start();
+ }
+
+ public synchronized void setCurrentlyInstantiatedModule(ModuleIdentifier currentlyInstantiatedModule) {
+ this.moduleIdentifierWithNanos = new ModuleIdentifierWithNanos(currentlyInstantiatedModule);
+ }
+
+ public boolean isAlive() {
+ return thread.isAlive();
+ }
+
+ @Override
+ public void close() {
+ thread.interrupt();
+ }
+
+ @Override
+ public String toString() {
+ return "DeadlockMonitor{" + transactionIdentifier + '}';
+ }
+
+ private class DeadlockMonitorRunnable extends Thread {
+
+ private DeadlockMonitorRunnable() {
+ super(DeadlockMonitor.this.toString());
+ }
+
+ @Override
+ public void run() {
+ ModuleIdentifierWithNanos old = new ModuleIdentifierWithNanos(); // null moduleId
+ while (this.isInterrupted() == false) {
+ ModuleIdentifierWithNanos copy = new ModuleIdentifierWithNanos(DeadlockMonitor.this.moduleIdentifierWithNanos);
+ if (old.moduleIdentifier == null) {
+ // started
+ old = copy;
+ } else if (old.moduleIdentifier != null && old.equals(copy)) {
+ // is the getInstance() running longer than WARN_AFTER_MILLIS ?
+ long runningTime = TimeUnit.NANOSECONDS.toMillis(System.nanoTime() - copy.nanoTime);
+ if (runningTime > WARN_AFTER_MILLIS) {
+ logger.warn("{} did not finish after {} ms", copy.moduleIdentifier, runningTime);
+ }
+ }
+ try {
+ sleep(1000);
+ } catch (InterruptedException e) {
+ interrupt();
+ }
+ }
+ logger.trace("Exiting {}", this);
+ }
+
+ @Override
+ public String toString() {
+ return "DeadLockMonitorRunnable{" + transactionIdentifier + "}";
+ }
+ }
+
+ private class ModuleIdentifierWithNanos {
+ @Nullable
+ private final ModuleIdentifier moduleIdentifier;
+ private final long nanoTime;
+
+ private ModuleIdentifierWithNanos() {
+ moduleIdentifier = null;
+ nanoTime = System.nanoTime();
+ }
+
+ private ModuleIdentifierWithNanos(ModuleIdentifier moduleIdentifier) {
+ this.moduleIdentifier = moduleIdentifier;
+ nanoTime = System.nanoTime();
+ }
+
+ private ModuleIdentifierWithNanos(ModuleIdentifierWithNanos copy) {
+ moduleIdentifier = copy.moduleIdentifier;
+ nanoTime = copy.nanoTime;
+ }
+
+ @Override
+ public boolean equals(Object o) {
+ if (this == o) return true;
+ if (o == null || getClass() != o.getClass()) return false;
+
+ ModuleIdentifierWithNanos that = (ModuleIdentifierWithNanos) o;
+
+ if (nanoTime != that.nanoTime) return false;
+ if (moduleIdentifier != null ? !moduleIdentifier.equals(that.moduleIdentifier) : that.moduleIdentifier != null)
+ return false;
+
+ return true;
+ }
+
+ @Override
+ public int hashCode() {
+ int result = moduleIdentifier != null ? moduleIdentifier.hashCode() : 0;
+ result = 31 * result + (int) (nanoTime ^ (nanoTime >>> 32));
+ return result;
+ }
+ }
+}
import javax.annotation.Nullable;
import org.opendaylight.controller.config.api.ModuleIdentifier;
+import org.opendaylight.controller.config.manager.impl.dependencyresolver.DestroyedModule;
import org.opendaylight.controller.config.manager.impl.dynamicmbean.DynamicReadableWrapper;
import org.opendaylight.controller.config.manager.impl.jmx.ModuleJMXRegistrator;
import org.opendaylight.controller.config.manager.impl.jmx.RootRuntimeBeanRegistratorImpl;
this.serviceReferenceRegistrator = serviceReferenceRegistratorFactory.create();
- Map<String, Set<String /* QName */>> factoryNamesToQNames = new HashMap<>();
+ Map<String, Set<String /* QName */>> modifiableFactoryNamesToQNames = new HashMap<>();
Set<ServiceInterfaceAnnotation> allAnnotations = new HashSet<>();
Set<String /* qName */> allQNames = new HashSet<>();
for (Entry<String, ModuleFactory> entry : factories.entrySet()) {
}
allAnnotations.addAll(siAnnotations);
allQNames.addAll(qNames);
- factoryNamesToQNames.put(entry.getKey(), Collections.unmodifiableSet(qNames));
+ modifiableFactoryNamesToQNames.put(entry.getKey(), Collections.unmodifiableSet(qNames));
}
- this.factoryNamesToQNames = Collections.unmodifiableMap(factoryNamesToQNames);
+ this.factoryNamesToQNames = Collections.unmodifiableMap(modifiableFactoryNamesToQNames);
this.allQNames = Collections.unmodifiableSet(allQNames);
// fill namespacesToAnnotations
- Map<String /* namespace */, Map<String /* localName */, ServiceInterfaceAnnotation>> namespacesToAnnotations =
+ Map<String /* namespace */, Map<String /* localName */, ServiceInterfaceAnnotation>> modifiableNamespacesToAnnotations =
new HashMap<>();
for (ServiceInterfaceAnnotation sia : allAnnotations) {
- Map<String, ServiceInterfaceAnnotation> ofNamespace = namespacesToAnnotations.get(sia.namespace());
+ Map<String, ServiceInterfaceAnnotation> ofNamespace = modifiableNamespacesToAnnotations.get(sia.namespace());
if (ofNamespace == null) {
ofNamespace = new HashMap<>();
- namespacesToAnnotations.put(sia.namespace(), ofNamespace);
+ modifiableNamespacesToAnnotations.put(sia.namespace(), ofNamespace);
}
if (ofNamespace.containsKey(sia.localName())) {
logger.error("Cannot construct namespacesToAnnotations map, conflict between local names in {}, offending local name: {}, map so far {}",
- sia.namespace(), sia.localName(), namespacesToAnnotations);
+ sia.namespace(), sia.localName(), modifiableNamespacesToAnnotations);
throw new IllegalArgumentException("Conflict between local names in " + sia.namespace() + " : " + sia.localName());
}
ofNamespace.put(sia.localName(), sia);
}
- this.namespacesToAnnotations = Collections.unmodifiableMap(namespacesToAnnotations);
+ this.namespacesToAnnotations = Collections.unmodifiableMap(modifiableNamespacesToAnnotations);
// copy refNames
logger.trace("factoryNamesToQNames:{}", this.factoryNamesToQNames);
}
@Override
public boolean equals(Object o) {
- if (this == o)
+ if (this == o) {
return true;
- if (o == null || getClass() != o.getClass())
+ }
+ if (o == null || getClass() != o.getClass()) {
return false;
+ }
TransactionIdentifier that = (TransactionIdentifier) o;
- if (name != null ? !name.equals(that.name) : that.name != null)
+ if (name != null ? !name.equals(that.name) : that.name != null) {
return false;
+ }
return true;
}
}
public synchronized void checkNotCommitStarted() {
- if (secondPhaseCommitStarted == true)
+ if (secondPhaseCommitStarted == true) {
throw new IllegalStateException("Commit was triggered");
+ }
}
public synchronized void checkCommitStarted() {
- if (secondPhaseCommitStarted == false)
+ if (secondPhaseCommitStarted == false) {
throw new IllegalStateException("Commit was not triggered");
+ }
}
public synchronized void checkNotAborted() {
- if (aborted == true)
+ if (aborted == true) {
throw new IllegalStateException("Configuration was aborted");
+ }
}
public synchronized void checkNotCommitted() {
* during validation. Tracks dependencies for ordering purposes.
*/
final class DependencyResolverImpl implements DependencyResolver,
- Comparable<DependencyResolverImpl> {
+ Comparable<DependencyResolverImpl> {
private static final Logger logger = LoggerFactory.getLogger(DependencyResolverImpl.class);
private final ModulesHolder modulesHolder;
throw new NullPointerException(
"Parameter 'expectedServiceInterface' is null");
}
- if (jmxAttribute == null)
+ if (jmxAttribute == null) {
throw new NullPointerException("Parameter 'jmxAttribute' is null");
+ }
JmxAttributeValidationException.checkNotNull(dependentReadOnlyON,
"is null, expected dependency implementing "
+ expectedServiceInterface, jmxAttribute);
-
// check that objectName belongs to this transaction - this should be
// stripped
// in DynamicWritableWrapper
}
}
- // transalate from serviceref to module ON
+ // translate from serviceref to module ON
private ObjectName translateServiceRefIfPossible(ObjectName dependentReadOnlyON) {
if (ObjectNameUtil.isServiceReference(dependentReadOnlyON)) {
String serviceQName = ObjectNameUtil.getServiceQName(dependentReadOnlyON);
//TODO: check for cycles
@Override
public <T> T resolveInstance(Class<T> expectedType, ObjectName dependentReadOnlyON,
- JmxAttribute jmxAttribute) {
+ JmxAttribute jmxAttribute) {
if (expectedType == null || dependentReadOnlyON == null || jmxAttribute == null) {
throw new IllegalArgumentException(format(
"Null parameters not allowed, got %s %s %s", expectedType,
throw new JmxAttributeValidationException(message, jmxAttribute);
}
try {
- T result = expectedType.cast(instance);
- return result;
+ return expectedType.cast(instance);
} catch (ClassCastException e) {
String message = format(
"Instance cannot be cast to expected type. Instance class is %s , "
IdentityCodec<?> identityCodec = codecRegistry.getIdentityCodec();
Class<? extends BaseIdentity> deserialized = identityCodec.deserialize(qName);
if (deserialized == null) {
- throw new RuntimeException("Unable to retrieve identity class for " + qName + ", null response from "
+ throw new IllegalStateException("Unable to retrieve identity class for " + qName + ", null response from "
+ codecRegistry);
}
if (expectedBaseClass.isAssignableFrom(deserialized)) {
public <T extends BaseIdentity> void validateIdentity(IdentityAttributeRef identityRef, Class<T> expectedBaseClass, JmxAttribute jmxAttribute) {
try {
resolveIdentity(identityRef, expectedBaseClass);
- } catch(Exception e) {
+ } catch (Exception e) {
throw JmxAttributeValidationException.wrap(e, jmxAttribute);
}
}
return maxDependencyDepth;
}
- public void countMaxDependencyDepth(DependencyResolverManager manager) {
+ void countMaxDependencyDepth(DependencyResolverManager manager) {
transactionStatus.checkCommitted();
if (maxDependencyDepth == null) {
maxDependencyDepth = getMaxDepth(this, manager,
}
private static int getMaxDepth(DependencyResolverImpl impl,
- DependencyResolverManager manager,
- LinkedHashSet<ModuleIdentifier> chainForDetectingCycles) {
+ DependencyResolverManager manager,
+ LinkedHashSet<ModuleIdentifier> chainForDetectingCycles) {
int maxDepth = 0;
LinkedHashSet<ModuleIdentifier> chainForDetectingCycles2 = new LinkedHashSet<>(
chainForDetectingCycles);
public ModuleIdentifier getIdentifier() {
return name;
}
+
}
*/
package org.opendaylight.controller.config.manager.impl.dependencyresolver;
+import com.google.common.reflect.AbstractInvocationHandler;
+import com.google.common.reflect.Reflection;
import org.opendaylight.controller.config.api.DependencyResolver;
import org.opendaylight.controller.config.api.DependencyResolverFactory;
import org.opendaylight.controller.config.api.JmxAttribute;
import org.opendaylight.controller.config.api.ModuleIdentifier;
+import org.opendaylight.controller.config.api.RuntimeBeanRegistratorAwareModule;
import org.opendaylight.controller.config.api.ServiceReferenceReadableRegistry;
import org.opendaylight.controller.config.manager.impl.CommitInfo;
-import org.opendaylight.controller.config.manager.impl.ModuleInternalTransactionalInfo;
+import org.opendaylight.controller.config.manager.impl.DeadlockMonitor;
+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.manager.impl.jmx.TransactionModuleJMXRegistrator.TransactionModuleJMXRegistration;
import org.opendaylight.controller.config.spi.Module;
import org.opendaylight.controller.config.spi.ModuleFactory;
import org.opendaylight.yangtools.yang.data.impl.codec.CodecRegistry;
import javax.annotation.concurrent.GuardedBy;
import javax.management.InstanceAlreadyExistsException;
+import java.lang.reflect.InvocationTargetException;
+import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
+import static com.google.common.base.Preconditions.checkState;
+
/**
* Holds information about modules being created and destroyed within this
* transaction. Observes usage of DependencyResolver within modules to figure
* out dependency tree.
*/
-public class DependencyResolverManager implements TransactionHolder, DependencyResolverFactory {
+public class DependencyResolverManager implements DependencyResolverFactory, AutoCloseable {
@GuardedBy("this")
private final Map<ModuleIdentifier, DependencyResolverImpl> moduleIdentifiersToDependencyResolverMap = new HashMap<>();
private final ModulesHolder modulesHolder;
private final TransactionStatus transactionStatus;
private final ServiceReferenceReadableRegistry readableRegistry;
private final CodecRegistry codecRegistry;
+ private final DeadlockMonitor deadlockMonitor;
- public DependencyResolverManager(String transactionName,
+ public DependencyResolverManager(TransactionIdentifier transactionIdentifier,
TransactionStatus transactionStatus, ServiceReferenceReadableRegistry readableRegistry, CodecRegistry codecRegistry) {
- this.modulesHolder = new ModulesHolder(transactionName);
+ this.modulesHolder = new ModulesHolder(transactionIdentifier);
this.transactionStatus = transactionStatus;
this.readableRegistry = readableRegistry;
this.codecRegistry = codecRegistry;
+ this.deadlockMonitor = new DeadlockMonitor(transactionIdentifier);
}
@Override
return result;
}
- @Override
public ModuleInternalTransactionalInfo destroyModule(
ModuleIdentifier moduleIdentifier) {
transactionStatus.checkNotCommitted();
}
// protect write access
- @Override
+
public void put(
- ModuleInternalTransactionalInfo moduleInternalTransactionalInfo) {
+ final ModuleIdentifier moduleIdentifier,
+ final Module module,
+ ModuleFactory moduleFactory,
+ ModuleInternalInfo maybeOldInternalInfo,
+ TransactionModuleJMXRegistration transactionModuleJMXRegistration,
+ boolean isDefaultBean) {
transactionStatus.checkNotCommitted();
+
+ Class<? extends Module> moduleClass = Module.class;
+ if (module instanceof RuntimeBeanRegistratorAwareModule) {
+ moduleClass = RuntimeBeanRegistratorAwareModule.class;
+ }
+ Module proxiedModule = Reflection.newProxy(moduleClass, new AbstractInvocationHandler() {
+ // optimization: subsequent calls to getInstance MUST return the same value during transaction,
+ // so it is safe to cache the response
+ private Object cachedInstance;
+
+ @Override
+ protected Object handleInvocation(Object proxy, Method method, Object[] args) throws Throwable {
+ boolean isGetInstance = method.getName().equals("getInstance");
+ if (isGetInstance) {
+ if (cachedInstance != null) {
+ return cachedInstance;
+ }
+
+ checkState(deadlockMonitor.isAlive(), "Deadlock monitor is not alive");
+ deadlockMonitor.setCurrentlyInstantiatedModule(moduleIdentifier);
+ }
+ try {
+ Object response = method.invoke(module, args);
+ if (isGetInstance) {
+ cachedInstance = response;
+ }
+ return response;
+ } catch(InvocationTargetException e) {
+ throw e.getCause();
+ } finally {
+ if (isGetInstance) {
+ deadlockMonitor.setCurrentlyInstantiatedModule(null);
+ }
+ }
+ }
+ });
+
+
+ ModuleInternalTransactionalInfo moduleInternalTransactionalInfo = new ModuleInternalTransactionalInfo(
+ moduleIdentifier, proxiedModule, moduleFactory,
+ maybeOldInternalInfo, transactionModuleJMXRegistration, isDefaultBean, module);
modulesHolder.put(moduleInternalTransactionalInfo);
}
// wrapped methods:
- @Override
public CommitInfo toCommitInfo() {
return modulesHolder.toCommitInfo();
}
- @Override
public Module findModule(ModuleIdentifier moduleIdentifier,
- JmxAttribute jmxAttributeForReporting) {
+ JmxAttribute jmxAttributeForReporting) {
return modulesHolder.findModule(moduleIdentifier,
jmxAttributeForReporting);
}
- @Override
public ModuleInternalTransactionalInfo findModuleInternalTransactionalInfo(ModuleIdentifier moduleIdentifier) {
return modulesHolder.findModuleInternalTransactionalInfo(moduleIdentifier);
}
- @Override
public ModuleFactory findModuleFactory(ModuleIdentifier moduleIdentifier,
- JmxAttribute jmxAttributeForReporting) {
+ JmxAttribute jmxAttributeForReporting) {
return modulesHolder.findModuleFactory(moduleIdentifier,
jmxAttributeForReporting);
}
- @Override
public Map<ModuleIdentifier, Module> getAllModules() {
return modulesHolder.getAllModules();
}
- @Override
public void assertNotExists(ModuleIdentifier moduleIdentifier)
throws InstanceAlreadyExistsException {
modulesHolder.assertNotExists(moduleIdentifier);
public List<ModuleIdentifier> findAllByFactory(ModuleFactory factory) {
List<ModuleIdentifier> result = new ArrayList<>();
- for( ModuleInternalTransactionalInfo info : modulesHolder.getAllInfos()) {
+ for (ModuleInternalTransactionalInfo info : modulesHolder.getAllInfos()) {
if (factory.equals(info.getModuleFactory())) {
result.add(info.getIdentifier());
}
}
return result;
}
+
+ public void close() {
+ deadlockMonitor.close();
+ }
+
}
* 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.config.manager.impl;
+package org.opendaylight.controller.config.manager.impl.dependencyresolver;
import org.opendaylight.controller.config.api.ModuleIdentifier;
import org.opendaylight.controller.config.manager.impl.jmx.ModuleJMXRegistrator;
private final OsgiRegistration osgiRegistration;
private final int orderingIdx;
- DestroyedModule(ModuleIdentifier identifier, AutoCloseable instance,
+ public DestroyedModule(ModuleIdentifier identifier, AutoCloseable instance,
ModuleJMXRegistrator oldJMXRegistrator,
OsgiRegistration osgiRegistration, int orderingIdx) {
this.identifier = identifier;
* 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.config.manager.impl;
-
-import javax.annotation.Nullable;
+package org.opendaylight.controller.config.manager.impl.dependencyresolver;
import org.opendaylight.controller.config.api.ModuleIdentifier;
+import org.opendaylight.controller.config.manager.impl.ModuleInternalInfo;
import org.opendaylight.controller.config.manager.impl.dynamicmbean.DynamicReadableWrapper;
-import org.opendaylight.controller.config.manager.impl.jmx.TransactionModuleJMXRegistrator
- .TransactionModuleJMXRegistration;
+import org.opendaylight.controller.config.manager.impl.jmx.TransactionModuleJMXRegistrator.TransactionModuleJMXRegistration;
import org.opendaylight.controller.config.spi.Module;
import org.opendaylight.controller.config.spi.ModuleFactory;
import org.opendaylight.yangtools.concepts.Identifiable;
+import javax.annotation.Nullable;
+
public class ModuleInternalTransactionalInfo implements Identifiable<ModuleIdentifier> {
private final ModuleIdentifier name;
- private final Module module;
+ private final Module proxiedModule, realModule;
private final ModuleFactory moduleFactory;
@Nullable
private final ModuleInternalInfo maybeOldInternalInfo;
private final TransactionModuleJMXRegistration transactionModuleJMXRegistration;
private final boolean isDefaultBean;
- ModuleInternalTransactionalInfo(ModuleIdentifier name, Module module,
- ModuleFactory moduleFactory,
- ModuleInternalInfo maybeOldInternalInfo,
- TransactionModuleJMXRegistration transactionModuleJMXRegistration,
- boolean isDefaultBean) {
+ public ModuleInternalTransactionalInfo(ModuleIdentifier name, Module proxiedModule,
+ ModuleFactory moduleFactory,
+ ModuleInternalInfo maybeOldInternalInfo,
+ TransactionModuleJMXRegistration transactionModuleJMXRegistration,
+ boolean isDefaultBean, Module realModule) {
this.name = name;
- this.module = module;
+ this.proxiedModule = proxiedModule;
this.moduleFactory = moduleFactory;
this.maybeOldInternalInfo = maybeOldInternalInfo;
this.transactionModuleJMXRegistration = transactionModuleJMXRegistration;
this.isDefaultBean = isDefaultBean;
+ this.realModule = realModule;
}
}
- public Module getModule() {
- return module;
+ public Module getProxiedModule() {
+ return proxiedModule;
}
public ModuleFactory getModuleFactory() {
@Nullable
public ModuleInternalInfo getOldInternalInfo() {
- if (maybeOldInternalInfo == null)
+ if (maybeOldInternalInfo == null) {
throw new NullPointerException();
+ }
return maybeOldInternalInfo;
}
public boolean isDefaultBean() {
return isDefaultBean;
}
+
+ public Module getRealModule() {
+ return realModule;
+ }
}
import org.opendaylight.controller.config.api.JmxAttributeValidationException;
import org.opendaylight.controller.config.api.ModuleIdentifier;
import org.opendaylight.controller.config.manager.impl.CommitInfo;
-import org.opendaylight.controller.config.manager.impl.DestroyedModule;
-import org.opendaylight.controller.config.manager.impl.ModuleInternalTransactionalInfo;
+import org.opendaylight.controller.config.manager.impl.TransactionIdentifier;
import org.opendaylight.controller.config.spi.Module;
import org.opendaylight.controller.config.spi.ModuleFactory;
/**
* Represents modules to be committed.
*/
-class ModulesHolder implements TransactionHolder {
- private final String transactionName;
+class ModulesHolder {
+ private final TransactionIdentifier transactionIdentifier;
@GuardedBy("this")
private final Map<ModuleIdentifier, ModuleInternalTransactionalInfo> commitMap = new HashMap<>();
@GuardedBy("this")
private final Set<ModuleInternalTransactionalInfo> unorderedDestroyedFromPreviousTransactions = new HashSet<>();
- ModulesHolder(String transactionName) {
- this.transactionName = transactionName;
+ ModulesHolder(TransactionIdentifier transactionIdentifier) {
+ this.transactionIdentifier = transactionIdentifier;
}
- @Override
+
public CommitInfo toCommitInfo() {
List<DestroyedModule> orderedDestroyedFromPreviousTransactions = new ArrayList<>(
unorderedDestroyedFromPreviousTransactions.size());
.get(moduleIdentifier);
JmxAttributeValidationException.checkNotNull(
moduleInternalTransactionalInfo, "Module " + moduleIdentifier
- + "" + " not found in transaction " + transactionName,
+ + "" + " not found in transaction " + transactionIdentifier,
jmxAttributeForReporting);
return moduleInternalTransactionalInfo;
}
- @Override
public Module findModule(ModuleIdentifier moduleIdentifier,
JmxAttribute jmxAttributeForReporting) {
return findModuleInternalTransactionalInfo(moduleIdentifier,
- jmxAttributeForReporting).getModule();
+ jmxAttributeForReporting).getProxiedModule();
}
- @Override
public ModuleFactory findModuleFactory(ModuleIdentifier moduleIdentifier,
JmxAttribute jmxAttributeForReporting) {
return findModuleInternalTransactionalInfo(moduleIdentifier,
jmxAttributeForReporting).getModuleFactory();
}
- @Override
public Map<ModuleIdentifier, Module> getAllModules() {
Map<ModuleIdentifier, Module> result = new HashMap<>();
for (ModuleInternalTransactionalInfo entry : commitMap.values()) {
ModuleIdentifier name = entry.getIdentifier();
- result.put(name, entry.getModule());
+ result.put(name, entry.getProxiedModule());
}
return result;
}
- @Override
public void put(
ModuleInternalTransactionalInfo moduleInternalTransactionalInfo) {
commitMap.put(moduleInternalTransactionalInfo.getIdentifier(),
moduleInternalTransactionalInfo);
}
- @Override
public ModuleInternalTransactionalInfo destroyModule(
ModuleIdentifier moduleIdentifier) {
ModuleInternalTransactionalInfo found = commitMap.remove(moduleIdentifier);
return found;
}
- @Override
public void assertNotExists(ModuleIdentifier moduleIdentifier)
throws InstanceAlreadyExistsException {
if (commitMap.containsKey(moduleIdentifier)) {
return commitMap.values();
}
- @Override
public ModuleInternalTransactionalInfo findModuleInternalTransactionalInfo(ModuleIdentifier moduleIdentifier) {
ModuleInternalTransactionalInfo found = commitMap.get(moduleIdentifier);
if (found == null) {
+++ /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.config.manager.impl.dependencyresolver;
-
-import org.opendaylight.controller.config.api.JmxAttribute;
-import org.opendaylight.controller.config.api.ModuleIdentifier;
-import org.opendaylight.controller.config.manager.impl.CommitInfo;
-import org.opendaylight.controller.config.manager.impl.ModuleInternalTransactionalInfo;
-import org.opendaylight.controller.config.spi.Module;
-import org.opendaylight.controller.config.spi.ModuleFactory;
-
-import javax.management.InstanceAlreadyExistsException;
-import java.util.Map;
-
-interface TransactionHolder {
- CommitInfo toCommitInfo();
-
- Module findModule(ModuleIdentifier moduleIdentifier,
- JmxAttribute jmxAttributeForReporting);
-
- ModuleFactory findModuleFactory(ModuleIdentifier moduleIdentifier,
- JmxAttribute jmxAttributeForReporting);
-
- Map<ModuleIdentifier, Module> getAllModules();
-
- void put(ModuleInternalTransactionalInfo moduleInternalTransactionalInfo);
-
- ModuleInternalTransactionalInfo destroyModule(
- ModuleIdentifier moduleIdentifier);
-
- void assertNotExists(ModuleIdentifier moduleIdentifier)
- throws InstanceAlreadyExistsException;
-
- ModuleInternalTransactionalInfo findModuleInternalTransactionalInfo(ModuleIdentifier moduleIdentifier);
-
-}
* requests (getAttribute, setAttribute, invoke) into the actual instance, but
* provides additional functionality - namely it disallows setting attribute on
* a read only wrapper.
- *
*/
abstract class AbstractDynamicWrapper implements DynamicMBeanModuleWrapper {
private static final Logger logger = LoggerFactory
protected final MBeanServer internalServer;
public AbstractDynamicWrapper(Module module, boolean writable,
- ModuleIdentifier moduleIdentifier,
- ObjectName thisWrapperObjectName, MBeanOperationInfo[] dOperations,
- MBeanServer internalServer, MBeanServer configMBeanServer) {
+ ModuleIdentifier moduleIdentifier,
+ ObjectName thisWrapperObjectName, MBeanOperationInfo[] dOperations,
+ MBeanServer internalServer, MBeanServer configMBeanServer) {
this.writable = writable;
this.module = module;
* case unregister the module and remove listener.
*/
private final NotificationListener registerActualModule(Module module,
- final ObjectName thisWrapperObjectName,
- final ObjectName objectNameInternal,
- final MBeanServer internalServer,
- final MBeanServer configMBeanServer) {
+ final ObjectName thisWrapperObjectName,
+ final ObjectName objectNameInternal,
+ final MBeanServer internalServer,
+ final MBeanServer configMBeanServer) {
try {
internalServer.registerMBean(module, objectNameInternal);
public void handleNotification(Notification n, Object handback) {
if (n instanceof MBeanServerNotification
&& n.getType()
- .equals(MBeanServerNotification.UNREGISTRATION_NOTIFICATION)) {
+ .equals(MBeanServerNotification.UNREGISTRATION_NOTIFICATION)) {
if (((MBeanServerNotification) n).getMBeanName().equals(
thisWrapperObjectName)) {
try {
}
private static MBeanInfo generateMBeanInfo(String className, Module module,
- Map<String, AttributeHolder> attributeHolderMap,
- MBeanOperationInfo[] dOperations, Set<Class<?>> jmxInterfaces) {
+ Map<String, AttributeHolder> attributeHolderMap,
+ MBeanOperationInfo[] dOperations, Set<Class<?>> jmxInterfaces) {
String dDescription = findDescription(module.getClass(), jmxInterfaces);
MBeanConstructorInfo[] dConstructors = new MBeanConstructorInfo[0];
// inspect all exported interfaces ending with MXBean, extract getters &
// setters into attribute holder
private static Map<String, AttributeHolder> buildMBeanInfo(Module module,
- boolean writable, ModuleIdentifier moduleIdentifier,
- Set<Class<?>> jmxInterfaces, MBeanServer internalServer,
- ObjectName internalObjectName) {
+ boolean writable, ModuleIdentifier moduleIdentifier,
+ Set<Class<?>> jmxInterfaces, MBeanServer internalServer,
+ ObjectName internalObjectName) {
// internal variables for describing MBean elements
Set<Method> methods = new HashSet<>();
}
AttributeHolder attributeHolder = new AttributeHolder(
attribName, module, attributeMap.get(attribName)
- .getType(), writable, ifc, description);
+ .getType(), writable, ifc, description);
attributeHolderMap.put(attribName, attributeHolder);
}
}
}
- if(isDependencyListAttr(attributeName, obj)) {
+ if (isDependencyListAttr(attributeName, obj)) {
obj = fixDependencyListAttribute(obj);
}
}
private Object fixDependencyListAttribute(Object attribute) {
- if(attribute.getClass().isArray() == false)
+ if (attribute.getClass().isArray() == false) {
throw new IllegalArgumentException("Unexpected attribute type, should be an array, but was " + attribute.getClass());
+ }
for (int i = 0; i < Array.getLength(attribute); i++) {
Object on = Array.get(attribute, i);
- if(on instanceof ObjectName == false)
+ if (on instanceof ObjectName == false) {
throw new IllegalArgumentException("Unexpected attribute type, should be an ObjectName, but was " + on.getClass());
+ }
on = fixObjectName((ObjectName) on);
Array.set(attribute, i, on);
}
private boolean isDependencyListAttr(String attributeName, Object attribute) {
- if (attributeHolderMap.containsKey(attributeName) == false)
+ if (attributeHolderMap.containsKey(attributeName) == false) {
return false;
+ }
AttributeHolder attributeHolder = attributeHolderMap.get(attributeName);
}
protected ObjectName fixObjectName(ObjectName on) {
- if (!ObjectNameUtil.ON_DOMAIN.equals(on.getDomain()))
+ if (!ObjectNameUtil.ON_DOMAIN.equals(on.getDomain())) {
throw new IllegalArgumentException("Wrong domain, expected "
+ ObjectNameUtil.ON_DOMAIN + " setter on " + on);
+ }
// if on contains transaction name, remove it
String transactionName = ObjectNameUtil.getTransactionName(on);
- if (transactionName != null)
+ if (transactionName != null) {
return ObjectNameUtil.withoutTransactionName(on);
- else
+ } else {
return on;
+ }
}
@Override
*/
package org.opendaylight.controller.config.manager.impl.dynamicmbean;
+import org.opendaylight.controller.config.api.annotations.Description;
+
import java.lang.annotation.Annotation;
import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.List;
import java.util.Set;
-import org.opendaylight.controller.config.api.annotations.Description;
-
-class AnnotationsHelper {
+public class AnnotationsHelper {
/**
* Look for annotation specified by annotationType on method. First observe
}
public AttributeHolder(String name, Object object, String returnType,
- boolean writable,
- @Nullable RequireInterface requireInterfaceAnnotation,
- String description) {
+ boolean writable,
+ @Nullable RequireInterface requireInterfaceAnnotation,
+ String description) {
if (name == null) {
throw new NullPointerException();
}
/**
* @return annotation if setter sets ObjectName or ObjectName[], and is
- * annotated. Return null otherwise.
+ * annotated. Return null otherwise.
*/
RequireInterface getRequireInterfaceOrNull() {
return requireInterfaceAnnotation;
* @param setter
* @param jmxInterfaces
* @return empty string if no annotation is found, or list of descriptions
- * separated by newline
+ * separated by newline
*/
static String findDescription(Method setter, Set<Class<?>> jmxInterfaces) {
List<Description> descriptions = AnnotationsHelper
*
* @param setter
* @param inspectedInterfaces
- * @throws IllegalStateException
- * if more than one value is specified by found annotations
- * @throws IllegalArgumentException
- * if set of exported interfaces contains non interface type
* @return null if no annotation is found, otherwise return the annotation
+ * @throws IllegalStateException if more than one value is specified by found annotations
+ * @throws IllegalArgumentException if set of exported interfaces contains non interface type
*/
static RequireInterface findRequireInterfaceAnnotation(final Method setter,
- Set<Class<?>> inspectedInterfaces) {
+ Set<Class<?>> inspectedInterfaces) {
// only allow setX(ObjectName y) or setX(ObjectName[] y) or setX(List<ObjectName> y) to continue
- if (setter.getParameterTypes().length > 1)
+ if (setter.getParameterTypes().length > 1) {
return null;
- if(PERMITTED_PARAMETER_TYPES_FOR_DEPENDENCY_SETTER.contains(setter.getParameterTypes()[0]) == false)
+ }
+ if (PERMITTED_PARAMETER_TYPES_FOR_DEPENDENCY_SETTER.contains(setter.getParameterTypes()[0]) == false) {
return null;
+ }
List<RequireInterface> foundRequireInterfaces = AnnotationsHelper
.findMethodAnnotationInSuperClassesAndIfcs(setter, RequireInterface.class, inspectedInterfaces);
try {
validate();
} catch (Exception e) {
- throw ValidationException.createForSingleException(
- moduleIdentifier, e);
+
+ throw new MBeanException(ValidationException.createForSingleException(
+ moduleIdentifier, e));
}
return Void.TYPE;
}
import org.opendaylight.controller.config.spi.ModuleFactory;
import org.osgi.framework.BundleContext;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-import java.util.Map.Entry;
-import java.util.Set;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.Collections;
import java.util.List;
import java.util.Map;
-import java.util.Collections;
+import java.util.Map.Entry;
+import java.util.Set;
import java.util.TreeSet;
-import java.util.Collection;
-import java.util.ArrayList;
/**
* Hold sorted ConfigMBeanFactories by their module names. Check that module
* names are globally unique.
*/
public class HierarchicalConfigMBeanFactoriesHolder {
- private static final Logger logger = LoggerFactory
- .getLogger(HierarchicalConfigMBeanFactoriesHolder.class);
private final Map<String, Map.Entry<ModuleFactory, BundleContext>> moduleNamesToConfigBeanFactories;
private final Set<String> moduleNames;
*/
package org.opendaylight.controller.config.manager.impl.jmx;
-import java.io.Closeable;
-import java.util.ArrayList;
-import java.util.Collections;
-import java.util.HashSet;
-import java.util.List;
-import java.util.Set;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
import javax.annotation.concurrent.GuardedBy;
import javax.management.InstanceAlreadyExistsException;
+import javax.management.InstanceNotFoundException;
import javax.management.JMX;
+import javax.management.MBeanRegistrationException;
import javax.management.MBeanServer;
+import javax.management.NotCompliantMBeanException;
import javax.management.ObjectName;
import javax.management.QueryExp;
-
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
+import java.io.Closeable;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Set;
public class InternalJMXRegistrator implements Closeable {
private static final Logger logger = LoggerFactory
private final ObjectName on;
InternalJMXRegistration(InternalJMXRegistrator internalJMXRegistrator,
- ObjectName on) {
+ ObjectName on) {
this.internalJMXRegistrator = internalJMXRegistrator;
this.on = on;
}
private final List<InternalJMXRegistrator> children = new ArrayList<>();
public synchronized InternalJMXRegistration registerMBean(Object object,
- ObjectName on) throws InstanceAlreadyExistsException {
+ ObjectName on) throws InstanceAlreadyExistsException {
try {
configMBeanServer.registerMBean(object, on);
- } catch (InstanceAlreadyExistsException e) {
- throw e;
- } catch (Exception e) {
- throw new RuntimeException(e);
+ } catch (MBeanRegistrationException | NotCompliantMBeanException e) {
+ throw new IllegalStateException(e);
}
registeredObjectNames.add(on);
return new InternalJMXRegistration(this, on);
private synchronized void unregisterMBean(ObjectName on) {
// first check that on was registered using this instance
boolean removed = registeredObjectNames.remove(on);
- if (!removed)
- throw new IllegalStateException(
- "Cannot unregister - ObjectName not found in 'registeredObjectNames': "
- + on);
+ if (!removed) {
+ throw new IllegalStateException("Cannot unregister - ObjectName not found in 'registeredObjectNames': " + on);
+ }
try {
configMBeanServer.unregisterMBean(on);
- } catch (Exception e) {
- throw new RuntimeException(e);
+ } catch (InstanceNotFoundException | MBeanRegistrationException e) {
+ throw new IllegalStateException(e);
}
}
}
public <T> T newMBeanProxy(ObjectName objectName, Class<T> interfaceClass,
- boolean notificationBroadcaster) {
+ boolean notificationBroadcaster) {
return JMX.newMBeanProxy(configMBeanServer, objectName, interfaceClass,
notificationBroadcaster);
}
}
public <T> T newMXBeanProxy(ObjectName objectName, Class<T> interfaceClass,
- boolean notificationBroadcaster) {
+ boolean notificationBroadcaster) {
return JMX.newMXBeanProxy(configMBeanServer, objectName,
interfaceClass, notificationBroadcaster);
}
@Override
public boolean equals(Object o) {
- if (this == o) return true;
- if (o == null || getClass() != o.getClass()) return false;
+ if (this == o) {
+ return true;
+ }
+ if (o == null || getClass() != o.getClass()) {
+ return false;
+ }
ServiceReference that = (ServiceReference) o;
- if (!refName.equals(that.refName)) return false;
- if (!serviceInterfaceName.equals(that.serviceInterfaceName)) return false;
+ if (!refName.equals(that.refName)) {
+ return false;
+ }
+ if (!serviceInterfaceName.equals(that.serviceInterfaceName)) {
+ return false;
+ }
return true;
}
*/
package org.opendaylight.controller.config.manager.impl.jmx;
-import java.io.Closeable;
-import java.util.Set;
+import org.opendaylight.controller.config.api.jmx.ObjectNameUtil;
+import org.opendaylight.controller.config.manager.impl.jmx.InternalJMXRegistrator.InternalJMXRegistration;
import javax.management.InstanceAlreadyExistsException;
import javax.management.ObjectName;
import javax.management.QueryExp;
-
-import org.opendaylight.controller.config.api.jmx.ObjectNameUtil;
-import org.opendaylight.controller.config.manager.impl.jmx.InternalJMXRegistrator.InternalJMXRegistration;
+import java.io.Closeable;
+import java.util.Set;
/**
* Contains constraints on passed {@link ObjectName} parameters. Only allow (un)
private final String transactionName;
TransactionJMXRegistrator(InternalJMXRegistrator internalJMXRegistrator,
- String transactionName) {
+ String transactionName) {
this.childJMXRegistrator = internalJMXRegistrator.createChild();
this.transactionName = transactionName;
}
public TransactionJMXRegistration registerMBean(Object object, ObjectName on)
throws InstanceAlreadyExistsException {
- if (!transactionName.equals(ObjectNameUtil.getTransactionName(on)))
+ if (!transactionName.equals(ObjectNameUtil.getTransactionName(on))) {
throw new IllegalArgumentException(
"Transaction name mismatch between expected "
+ transactionName + " " + "and " + on);
+ }
ObjectNameUtil.checkType(on, ObjectNameUtil.TYPE_CONFIG_TRANSACTION);
return new TransactionJMXRegistration(
childJMXRegistrator.registerMBean(object, on));
package org.opendaylight.controller.config.manager.impl.osgi;
import org.opendaylight.controller.config.api.ConflictingVersionException;
+import org.opendaylight.controller.config.api.ValidationException;
import org.opendaylight.controller.config.api.jmx.CommitStatus;
import org.opendaylight.controller.config.manager.impl.ConfigRegistryImpl;
import org.opendaylight.controller.config.spi.ModuleFactory;
synchronized void blankTransaction() {
// race condition check: config-persister might push new configuration while server is starting up.
ConflictingVersionException lastException = null;
- for (int i = 0; i < 10; i++) {
+ int maxAttempts = 10;
+ for (int i = 0; i < maxAttempts; i++) {
try {
// create transaction
boolean blankTransaction = true;
Thread.currentThread().interrupt();
throw new IllegalStateException(interruptedException);
}
+ } catch (ValidationException e) {
+ logger.error("Validation exception while running blank transaction indicates programming error", e);
+ throw new RuntimeException("Validation exception while running blank transaction indicates programming error", e);
}
}
- throw lastException;
+ throw new RuntimeException("Maximal number of attempts reached and still cannot get optimistic lock from " +
+ "config manager",lastException);
}
@Override
if(factory == null) {
throw new NullPointerException("ServiceReference of class" + serviceReference.getClass() + "not found.");
}
- StringBuffer errors = new StringBuffer();
+
String moduleName = factory.getImplementationName();
if (moduleName == null || moduleName.isEmpty()) {
throw new IllegalStateException(
throw new NullPointerException("Bundle context of " + factory + " ModuleFactory not found.");
}
logger.debug("Reading factory {} {}", moduleName, factory);
- String error = null;
+
Map.Entry<ModuleFactory, BundleContext> conflicting = result.get(moduleName);
if (conflicting != null) {
- error = String
- .format("Module name is not unique. Found two conflicting factories with same name '%s': " +
- "\n\t%s\n\t%s\n", moduleName, conflicting.getKey(), factory);
-
- }
-
- if (error == null) {
+ String error = String
+ .format("Module name is not unique. Found two conflicting factories with same name '%s': '%s' '%s'",
+ moduleName, conflicting.getKey(), factory);
+ logger.error(error);
+ throw new IllegalArgumentException(error);
+ } else {
result.put(moduleName, new AbstractMap.SimpleImmutableEntry<>(factory,
serviceReference.getBundle().getBundleContext()));
- } else {
- errors.append(error);
- }
- if (errors.length() > 0) {
- throw new IllegalArgumentException(errors.toString());
}
}
return result;
private RuntimeGeneratedMappingServiceActivator mappingServiceActivator;
@Override
- public void start(BundleContext context) throws Exception {
+ public void start(BundleContext context) {
// track bundles containing YangModuleInfo
ModuleInfoBundleTracker moduleInfoBundleTracker = new ModuleInfoBundleTracker();
try {
configRegistryJMXRegistrator.registerToJMX(configRegistry);
} catch (InstanceAlreadyExistsException e) {
- throw new RuntimeException("Config Registry was already registered to JMX", e);
+ throw new IllegalStateException("Config Registry was already registered to JMX", e);
}
ServiceTracker<ModuleFactory, Object> serviceTracker = new ServiceTracker<>(context, ModuleFactory.class,
}
@Override
- public void stop(BundleContext context) throws Exception {
+ public void stop(BundleContext context) {
try {
configRegistry.close();
} catch (Exception e) {
import org.slf4j.LoggerFactory;
import java.io.InputStream;
-import java.lang.reflect.InvocationTargetException;
import java.net.URL;
import java.util.Collection;
import java.util.LinkedList;
errorMessage = logMessage("Class {} does not implement {} in bundle {}", clazz, YangModelBindingProvider.class, bundle);
throw new IllegalStateException(errorMessage);
}
-
+ YangModelBindingProvider instance;
try {
- Object instance = clazz.newInstance();
- Object result = clazz.getMethod(GET_MODULE_INFO_METHOD).invoke(instance);
-
- if (YangModuleInfo.class.isAssignableFrom(result.getClass()) == false) {
- errorMessage = logMessage("Error invoking method not found {} in bundle {}, reason {}",
- GET_MODULE_INFO_METHOD, bundle, "Not assignable from " + YangModuleInfo.class);
- } else {
- return (YangModuleInfo) result;
- }
-
+ Object instanceObj = clazz.newInstance();
+ instance = YangModelBindingProvider.class.cast(instanceObj);
} catch (InstantiationException e) {
errorMessage = logMessage("Could not instantiate {} in bundle {}, reason {}", moduleInfoClass, bundle, e);
+ throw new IllegalStateException(errorMessage, e);
} catch (IllegalAccessException e) {
errorMessage = logMessage("Illegal access during instatiation of class {} in bundle {}, reason {}",
moduleInfoClass, bundle, e);
- } catch (NoSuchMethodException e) {
- errorMessage = logMessage("Method not found {} in bundle {}, reason {}", GET_MODULE_INFO_METHOD, bundle, e);
- } catch (InvocationTargetException e) {
- errorMessage = logMessage("Error invoking method {} in bundle {}, reason {}", GET_MODULE_INFO_METHOD,
- bundle, e);
+ throw new IllegalStateException(errorMessage, e);
}
+ try{
+ return instance.getModuleInfo();
+ } catch (NoClassDefFoundError e) {
- throw new IllegalStateException(errorMessage);
+
+ logger.error("Error while executing getModuleInfo on {}", instance, e);
+ throw e;
+ }
}
private static Class<?> loadClass(String moduleInfoClass, Bundle bundle) {
*/
package org.opendaylight.controller.config.manager.impl.dependencyresolver;
-import static org.junit.Assert.assertEquals;
-import static org.mockito.Mockito.doNothing;
-import static org.mockito.Mockito.doReturn;
-import static org.mockito.Mockito.mock;
-import static org.mockito.Mockito.reset;
-
-import java.util.Arrays;
-import java.util.List;
-
import org.junit.Before;
import org.junit.Test;
import org.opendaylight.controller.config.api.JmxAttribute;
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.ModuleInternalTransactionalInfo;
+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.manager.impl.jmx.TransactionModuleJMXRegistrator.TransactionModuleJMXRegistration;
import org.opendaylight.controller.config.spi.Module;
+import org.opendaylight.controller.config.spi.ModuleFactory;
+
+import java.util.Arrays;
+import java.util.List;
+
+import static org.junit.Assert.assertEquals;
+import static org.mockito.Mockito.doNothing;
+import static org.mockito.Mockito.doReturn;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.reset;
public class DependencyResolverManagerTest {
public void setUp() {
transactionStatus = mock(TransactionStatus.class);
ServiceReferenceReadableRegistry mockedRegistry = mock(ServiceReferenceReadableRegistry.class);
- tested = new DependencyResolverManager("txName", transactionStatus, mockedRegistry, null);
+ tested = new DependencyResolverManager(new TransactionIdentifier("txName"), transactionStatus, mockedRegistry, null);
doNothing().when(transactionStatus).checkCommitStarted();
doNothing().when(transactionStatus).checkNotCommitted();
}
private static void mockGetInstance(DependencyResolverManager tested,
ModuleIdentifier moduleIdentifier) {
- ModuleInternalTransactionalInfo mock = mock(ModuleInternalTransactionalInfo.class);
- doReturn(moduleIdentifier).when(mock).getIdentifier();
- doReturn(mockedModule()).when(mock).getModule();
- tested.put(mock);
+
+ ModuleFactory moduleFactory = mock(ModuleFactory.class);
+ ModuleInternalInfo maybeOldInternalInfo = null;
+ TransactionModuleJMXRegistration transactionModuleJMXRegistration = null;
+ boolean isDefaultBean = false;
+
+ tested.put(moduleIdentifier,
+ mockedModule(),
+ moduleFactory,
+ maybeOldInternalInfo,
+ transactionModuleJMXRegistration,
+ isDefaultBean);
}
private static Module mockedModule() {
*/
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 java.io.Closeable;
-
-import javax.annotation.Nullable;
-import javax.annotation.concurrent.NotThreadSafe;
-import javax.management.ObjectName;
-
+import com.google.common.base.Strings;
import org.opendaylight.controller.config.api.DependencyResolver;
import org.opendaylight.controller.config.api.JmxAttribute;
import org.opendaylight.controller.config.api.ModuleIdentifier;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
-import com.google.common.base.Strings;
+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.
import javax.management.MBeanException;
import javax.management.ObjectName;
import javax.management.ReflectionException;
-import javax.management.RuntimeMBeanException;
import java.util.Arrays;
import java.util.Collections;
import java.util.List;
private void testValidation(ConfigTransactionClient transaction)
throws InstanceAlreadyExistsException, ReflectionException,
- InstanceNotFoundException, MBeanException {
+ InstanceNotFoundException, MBeanException, ConflictingVersionException {
ObjectName fixed1names = transaction.createModule(
TestingFixedThreadPoolModuleFactory.NAME, fixed1);
// call validate on config bean
platformMBeanServer.invoke(fixed1names, "validate", new Object[0],
new String[0]);
fail();
- } catch (RuntimeMBeanException e) {
- RuntimeException targetException = e.getTargetException();
+ } catch (MBeanException e) {
+ Exception targetException = e.getTargetException();
assertNotNull(targetException);
assertEquals(ValidationException.class, targetException.getClass());
}
}
@Test
- public void testAbort() {
+ public void testAbort() throws InstanceAlreadyExistsException, ValidationException {
ConfigTransactionJMXClient transaction = configRegistryClient
.createTransaction();
assertEquals(1, configRegistryClient.getOpenConfigs().size());
transaction.createModule(TestingFixedThreadPoolModuleFactory.NAME,
fixed1);
fail();
- } catch (Exception e) {
- assertTrue(e.getCause() instanceof InstanceNotFoundException);
+ } catch (IllegalStateException e) {
+ assertEquals("Configuration was aborted", e.getMessage());
}
try {
transaction.validateConfig();
fail();
- } catch (Exception e) {
- assertTrue(e.getCause() instanceof InstanceNotFoundException);
+ } catch (IllegalStateException e) {
+ assertEquals("Configuration was aborted", e.getMessage());
}
assertEquals(0, configRegistryClient.getOpenConfigs().size());
}
<parent>
<groupId>org.opendaylight.controller</groupId>
<artifactId>config-subsystem</artifactId>
- <version>0.2.4-SNAPSHOT</version>
+ <version>0.2.5-SNAPSHOT</version>
</parent>
<artifactId>config-module-archetype</artifactId>
<parent>
<artifactId>config-subsystem</artifactId>
<groupId>org.opendaylight.controller</groupId>
- <version>0.2.4-SNAPSHOT</version>
+ <version>0.2.5-SNAPSHOT</version>
<relativePath>..</relativePath>
</parent>
<artifactId>config-persister-api</artifactId>
<parent>
<artifactId>config-subsystem</artifactId>
<groupId>org.opendaylight.controller</groupId>
- <version>0.2.4-SNAPSHOT</version>
+ <version>0.2.5-SNAPSHOT</version>
<relativePath>..</relativePath>
</parent>
<artifactId>config-persister-directory-adapter</artifactId>
<parent>
<artifactId>config-subsystem</artifactId>
<groupId>org.opendaylight.controller</groupId>
- <version>0.2.4-SNAPSHOT</version>
+ <version>0.2.5-SNAPSHOT</version>
<relativePath>..</relativePath>
</parent>
<artifactId>config-persister-directory-autodetect-adapter</artifactId>
<parent>
<artifactId>config-subsystem</artifactId>
<groupId>org.opendaylight.controller</groupId>
- <version>0.2.4-SNAPSHOT</version>
+ <version>0.2.5-SNAPSHOT</version>
<relativePath>..</relativePath>
</parent>
<artifactId>config-persister-directory-xml-adapter</artifactId>
<parent>
<artifactId>config-subsystem</artifactId>
<groupId>org.opendaylight.controller</groupId>
- <version>0.2.4-SNAPSHOT</version>
+ <version>0.2.5-SNAPSHOT</version>
<relativePath>..</relativePath>
</parent>
<artifactId>config-persister-file-adapter</artifactId>
<parent>
<artifactId>config-subsystem</artifactId>
<groupId>org.opendaylight.controller</groupId>
- <version>0.2.4-SNAPSHOT</version>
+ <version>0.2.5-SNAPSHOT</version>
<relativePath>..</relativePath>
</parent>
<artifactId>config-persister-file-xml-adapter</artifactId>
<parent>
<groupId>org.opendaylight.controller</groupId>
<artifactId>config-subsystem</artifactId>
- <version>0.2.4-SNAPSHOT</version>
+ <version>0.2.5-SNAPSHOT</version>
</parent>
<modelVersion>4.0.0</modelVersion>
<artifactId>config-plugin-parent</artifactId>
<properties>
<jmxGeneratorPath>${project.build.directory}/generated-sources/config</jmxGeneratorPath>
- <config.version>0.2.4-SNAPSHOT</config.version>
</properties>
<build>
<parent>
<artifactId>config-subsystem</artifactId>
<groupId>org.opendaylight.controller</groupId>
- <version>0.2.4-SNAPSHOT</version>
+ <version>0.2.5-SNAPSHOT</version>
<relativePath>..</relativePath>
</parent>
<artifactId>config-util</artifactId>
*/
package org.opendaylight.controller.config.util;
-import java.util.Map;
-import java.util.Set;
+import org.opendaylight.controller.config.api.ConflictingVersionException;
+import org.opendaylight.controller.config.api.ValidationException;
+import org.opendaylight.controller.config.api.jmx.CommitStatus;
+import org.opendaylight.controller.config.api.jmx.ConfigRegistryMXBean;
+import org.opendaylight.controller.config.api.jmx.ConfigTransactionControllerMXBean;
+import org.opendaylight.controller.config.api.jmx.ObjectNameUtil;
import javax.management.Attribute;
import javax.management.InstanceAlreadyExistsException;
import javax.management.InstanceNotFoundException;
import javax.management.JMException;
import javax.management.JMX;
+import javax.management.MBeanException;
import javax.management.MBeanServer;
import javax.management.ObjectName;
-import javax.management.RuntimeMBeanException;
-
-import org.opendaylight.controller.config.api.ConflictingVersionException;
-import org.opendaylight.controller.config.api.ValidationException;
-import org.opendaylight.controller.config.api.jmx.CommitStatus;
-import org.opendaylight.controller.config.api.jmx.ConfigRegistryMXBean;
-import org.opendaylight.controller.config.api.jmx.ConfigTransactionControllerMXBean;
-import org.opendaylight.controller.config.api.jmx.ObjectNameUtil;
+import java.util.Map;
+import java.util.Set;
public class ConfigTransactionJMXClient implements ConfigTransactionClient {
private final ConfigRegistryMXBean configRegistryMXBeanProxy;
throws ValidationException {
try {
configMBeanServer.invoke(configBeanON, "validate", null, null);
+ } catch (MBeanException e) {
+ Exception targetException = e.getTargetException();
+ if (targetException instanceof ValidationException){
+ throw (ValidationException) targetException;
+ } else {
+ throw new RuntimeException(e);
+ }
} catch (JMException e) {
throw new RuntimeException(e);
- } catch (RuntimeMBeanException e) {
- throw e.getTargetException();
}
}
<parent>
<groupId>org.opendaylight.controller</groupId>
<artifactId>config-plugin-parent</artifactId>
- <version>0.2.4-SNAPSHOT</version>
+ <version>0.2.5-SNAPSHOT</version>
<relativePath>../config-plugin-parent</relativePath>
</parent>
<artifactId>logback-config</artifactId>
*/
package org.opendaylight.controller.config.yang.logback.config;
-import static org.junit.Assert.assertEquals;
-
-import java.io.File;
-import java.io.IOException;
-import java.lang.management.ManagementFactory;
-import java.util.ArrayList;
-import java.util.Arrays;
-import java.util.List;
-
-import javax.management.InstanceAlreadyExistsException;
-import javax.management.InstanceNotFoundException;
-import javax.management.JMX;
-import javax.management.MalformedObjectNameException;
-import javax.management.ObjectName;
-
+import ch.qos.logback.classic.LoggerContext;
+import ch.qos.logback.classic.encoder.PatternLayoutEncoder;
+import ch.qos.logback.classic.joran.JoranConfigurator;
+import ch.qos.logback.classic.spi.ILoggingEvent;
+import ch.qos.logback.core.joran.spi.JoranException;
+import ch.qos.logback.core.rolling.FixedWindowRollingPolicy;
+import ch.qos.logback.core.rolling.SizeBasedTriggeringPolicy;
+import com.google.common.collect.Lists;
import org.apache.commons.io.FileUtils;
import org.junit.Before;
import org.junit.Test;
+import org.opendaylight.controller.config.api.ConflictingVersionException;
+import org.opendaylight.controller.config.api.ValidationException;
import org.opendaylight.controller.config.api.jmx.ObjectNameUtil;
import org.opendaylight.controller.config.manager.impl.AbstractConfigTest;
import org.opendaylight.controller.config.manager.impl.factoriesresolver.HardcodedModuleFactoriesResolver;
import org.opendaylight.controller.config.util.ConfigTransactionJMXClient;
import org.slf4j.LoggerFactory;
-import ch.qos.logback.classic.LoggerContext;
-import ch.qos.logback.classic.encoder.PatternLayoutEncoder;
-import ch.qos.logback.classic.joran.JoranConfigurator;
-import ch.qos.logback.classic.spi.ILoggingEvent;
-import ch.qos.logback.core.joran.spi.JoranException;
-import ch.qos.logback.core.rolling.FixedWindowRollingPolicy;
-import ch.qos.logback.core.rolling.SizeBasedTriggeringPolicy;
+import javax.management.InstanceAlreadyExistsException;
+import javax.management.InstanceNotFoundException;
+import javax.management.JMX;
+import javax.management.MalformedObjectNameException;
+import javax.management.ObjectName;
+import java.io.File;
+import java.io.IOException;
+import java.lang.management.ManagementFactory;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.List;
-import com.google.common.collect.Lists;
+import static org.junit.Assert.assertEquals;
public class LogbackModuleWithInitialConfigurationTest extends AbstractConfigTest {
}
public ObjectName createBeans() throws JoranException, InstanceAlreadyExistsException, IOException,
- MalformedObjectNameException, InstanceNotFoundException {
+ MalformedObjectNameException, InstanceNotFoundException, ValidationException, ConflictingVersionException {
LoggerContext lc = (LoggerContext) LoggerFactory.getILoggerFactory();
*/
package org.opendaylight.controller.config.yang.logback.config;
-import static org.junit.Assert.assertEquals;
-
-import java.io.File;
-import java.io.IOException;
-import java.lang.management.ManagementFactory;
-import java.util.List;
-
-import javax.management.InstanceAlreadyExistsException;
-import javax.management.InstanceNotFoundException;
-import javax.management.JMX;
-import javax.management.MalformedObjectNameException;
-import javax.management.ObjectName;
-
+import ch.qos.logback.classic.LoggerContext;
+import ch.qos.logback.classic.joran.JoranConfigurator;
+import ch.qos.logback.core.joran.spi.JoranException;
+import com.google.common.collect.Lists;
import org.apache.commons.io.FileUtils;
import org.junit.Before;
import org.junit.Test;
+import org.opendaylight.controller.config.api.ConflictingVersionException;
+import org.opendaylight.controller.config.api.ValidationException;
import org.opendaylight.controller.config.manager.impl.AbstractConfigTest;
import org.opendaylight.controller.config.manager.impl.factoriesresolver.HardcodedModuleFactoriesResolver;
import org.opendaylight.controller.config.util.ConfigTransactionJMXClient;
import org.slf4j.LoggerFactory;
-import ch.qos.logback.classic.LoggerContext;
-import ch.qos.logback.classic.joran.JoranConfigurator;
-import ch.qos.logback.core.joran.spi.JoranException;
+import javax.management.InstanceAlreadyExistsException;
+import javax.management.InstanceNotFoundException;
+import javax.management.JMX;
+import javax.management.MalformedObjectNameException;
+import javax.management.ObjectName;
+import java.io.File;
+import java.io.IOException;
+import java.lang.management.ManagementFactory;
+import java.util.List;
-import com.google.common.collect.Lists;
+import static org.junit.Assert.assertEquals;
public class LogbackWithXmlConfigModuleTest extends AbstractConfigTest {
* @throws MalformedObjectNameException
*/
@Test
- public void test() throws InstanceAlreadyExistsException, InstanceNotFoundException, MalformedObjectNameException {
+ public void test() throws InstanceAlreadyExistsException, InstanceNotFoundException, MalformedObjectNameException, ValidationException, ConflictingVersionException {
ConfigTransactionJMXClient transaction = configRegistryClient.createTransaction();
ObjectName nameRetrieved = transaction.lookupConfigBean(factory.getImplementationName(), LogbackModuleFactory.INSTANCE_NAME);
*/
@Test
public void testAddNewLogger() throws InstanceAlreadyExistsException, InstanceNotFoundException,
- MalformedObjectNameException {
+ MalformedObjectNameException, ValidationException, ConflictingVersionException {
ConfigTransactionJMXClient transaction = configRegistryClient.createTransaction();
ObjectName nameRetrieved = transaction.lookupConfigBean(factory.getImplementationName(), LogbackModuleFactory.INSTANCE_NAME);
<parent>
<groupId>org.opendaylight.controller</groupId>
<artifactId>config-plugin-parent</artifactId>
- <version>0.2.4-SNAPSHOT</version>
+ <version>0.2.5-SNAPSHOT</version>
<relativePath>../config-plugin-parent</relativePath>
</parent>
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>org.opendaylight.controller</groupId>
<artifactId>config-plugin-parent</artifactId>
- <version>0.2.4-SNAPSHOT</version>
+ <version>0.2.5-SNAPSHOT</version>
<relativePath>../config-plugin-parent</relativePath>
</parent>
<modelVersion>4.0.0</modelVersion>
--- /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.config.yang.netty.eventexecutor;
+
+import com.google.common.reflect.AbstractInvocationHandler;
+import com.google.common.reflect.Reflection;
+import io.netty.util.concurrent.EventExecutor;
+
+import java.lang.reflect.Method;
+import java.util.concurrent.TimeUnit;
+
+public interface AutoCloseableEventExecutor extends EventExecutor, AutoCloseable {
+
+
+ public static class CloseableEventExecutorMixin implements AutoCloseable {
+ public static final int DEFAULT_SHUTDOWN_SECONDS = 1;
+ private final EventExecutor eventExecutor;
+
+ public CloseableEventExecutorMixin(EventExecutor eventExecutor) {
+ this.eventExecutor = eventExecutor;
+ }
+
+ @Override
+ public void close() {
+ eventExecutor.shutdownGracefully(0, DEFAULT_SHUTDOWN_SECONDS, TimeUnit.SECONDS);
+ }
+
+
+ public static AutoCloseable createCloseableProxy(final EventExecutor eventExecutor) {
+ final CloseableEventExecutorMixin closeableGlobalEventExecutorMixin =
+ new CloseableEventExecutorMixin(eventExecutor);
+ return Reflection.newProxy(AutoCloseableEventExecutor.class, new AbstractInvocationHandler() {
+ @Override
+ protected Object handleInvocation(Object proxy, Method method, Object[] args) throws Throwable {
+ if (method.getName().equals("close")) {
+ closeableGlobalEventExecutorMixin.close();
+ return null;
+ } else {
+ return method.invoke(eventExecutor, args);
+ }
+ }
+ });
+ }
+
+
+ }
+}
\ No newline at end of file
*/
package org.opendaylight.controller.config.yang.netty.eventexecutor;
-import com.google.common.reflect.AbstractInvocationHandler;
-import com.google.common.reflect.Reflection;
import io.netty.util.concurrent.EventExecutor;
import io.netty.util.concurrent.GlobalEventExecutor;
-
-import java.lang.reflect.Method;
-import java.util.concurrent.TimeUnit;
+import org.opendaylight.controller.config.yang.netty.eventexecutor.AutoCloseableEventExecutor.CloseableEventExecutorMixin;
public final class GlobalEventExecutorModule extends
org.opendaylight.controller.config.yang.netty.eventexecutor.AbstractGlobalEventExecutorModule {
@Override
public java.lang.AutoCloseable createInstance() {
- final CloseableGlobalEventExecutorMixin closeableGlobalEventExecutorMixin =
- new CloseableGlobalEventExecutorMixin(GlobalEventExecutor.INSTANCE);
- return Reflection.newProxy(AutoCloseableEventExecutor.class, new AbstractInvocationHandler() {
- @Override
- protected Object handleInvocation(Object proxy, Method method, Object[] args) throws Throwable {
- if (method.getName().equals("close")) {
- closeableGlobalEventExecutorMixin.close();
- return null;
- } else {
- return method.invoke(GlobalEventExecutor.INSTANCE, args);
- }
- }
- });
+ EventExecutor eventExecutor = GlobalEventExecutor.INSTANCE;
+ return CloseableEventExecutorMixin.createCloseableProxy(eventExecutor);
}
- public static interface AutoCloseableEventExecutor extends EventExecutor, AutoCloseable {
-
- }
- public static class CloseableGlobalEventExecutorMixin implements AutoCloseable {
- private final GlobalEventExecutor eventExecutor;
- public CloseableGlobalEventExecutorMixin(GlobalEventExecutor eventExecutor) {
- this.eventExecutor = eventExecutor;
- }
-
- @Override
- public void close() {
- eventExecutor.shutdownGracefully(0, 1, TimeUnit.SECONDS);
- }
- }
}
--- /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.config.yang.netty.eventexecutor;
+
+import io.netty.util.concurrent.EventExecutor;
+import io.netty.util.concurrent.ImmediateEventExecutor;
+import org.opendaylight.controller.config.yang.netty.eventexecutor.AutoCloseableEventExecutor.CloseableEventExecutorMixin;
+
+public final class ImmediateEventExecutorModule extends org.opendaylight.controller.config.yang.netty.eventexecutor.AbstractImmediateEventExecutorModule {
+
+ public ImmediateEventExecutorModule(org.opendaylight.controller.config.api.ModuleIdentifier identifier, org.opendaylight.controller.config.api.DependencyResolver dependencyResolver) {
+ super(identifier, dependencyResolver);
+ }
+
+ public ImmediateEventExecutorModule(org.opendaylight.controller.config.api.ModuleIdentifier identifier, org.opendaylight.controller.config.api.DependencyResolver dependencyResolver,
+ ImmediateEventExecutorModule oldModule, java.lang.AutoCloseable oldInstance) {
+
+ super(identifier, dependencyResolver, oldModule, oldInstance);
+ }
+
+ @Override
+ protected void customValidation() {
+ // Add custom validation for module attributes here.
+ }
+
+ @Override
+ public java.lang.AutoCloseable createInstance() {
+ EventExecutor eventExecutor = ImmediateEventExecutor.INSTANCE;
+ return CloseableEventExecutorMixin.createCloseableProxy(eventExecutor);
+ }
+}
--- /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.config.yang.netty.eventexecutor;
+
+import org.opendaylight.controller.config.api.DependencyResolver;
+import org.osgi.framework.BundleContext;
+
+import static com.google.common.base.Preconditions.checkArgument;
+
+public class ImmediateEventExecutorModuleFactory extends org.opendaylight.controller.config.yang.netty.eventexecutor.AbstractImmediateEventExecutorModuleFactory {
+ public static final String SINGLETON_NAME = "singleton";
+
+ @Override
+ public ImmediateEventExecutorModule instantiateModule(String instanceName, DependencyResolver dependencyResolver, ImmediateEventExecutorModule oldModule, AutoCloseable oldInstance, BundleContext bundleContext) {
+ checkArgument(SINGLETON_NAME.equals(instanceName), "Illegal instance name '" + instanceName + "', only allowed name is " + SINGLETON_NAME);
+ return super.instantiateModule(instanceName, dependencyResolver, oldModule, oldInstance, bundleContext);
+ }
+
+ @Override
+ public ImmediateEventExecutorModule instantiateModule(String instanceName, DependencyResolver dependencyResolver, BundleContext bundleContext) {
+ checkArgument(SINGLETON_NAME.equals(instanceName), "Illegal instance name '" + instanceName + "', only allowed name is " + SINGLETON_NAME);
+ return super.instantiateModule(instanceName, dependencyResolver, bundleContext);
+ }
+}
augment "/config:modules/config:module/config:configuration" {
case netty-global-event-executor {
when "/config:modules/config:module/config:type = 'netty-global-event-executor'";
+ }
+ }
+ identity netty-immediate-event-executor {
+ base config:module-type;
+ config:provided-service netty:netty-event-executor;
+ config:java-name-prefix ImmediateEventExecutor;
+ }
+
+ augment "/config:modules/config:module/config:configuration" {
+ case netty-immediate-event-executor {
+ when "/config:modules/config:module/config:type = 'netty-immediate-event-executor'";
}
}
}
<parent>
<groupId>org.opendaylight.controller</groupId>
<artifactId>config-plugin-parent</artifactId>
- <version>0.2.4-SNAPSHOT</version>
+ <version>0.2.5-SNAPSHOT</version>
<relativePath>../config-plugin-parent</relativePath>
</parent>
<parent>
<groupId>org.opendaylight.controller</groupId>
<artifactId>config-plugin-parent</artifactId>
- <version>0.2.4-SNAPSHOT</version>
+ <version>0.2.5-SNAPSHOT</version>
<relativePath>../config-plugin-parent</relativePath>
</parent>
<modelVersion>4.0.0</modelVersion>
</parent>
- <version>0.2.4-SNAPSHOT</version>
+ <version>0.2.5-SNAPSHOT</version>
<artifactId>config-subsystem</artifactId>
<packaging>pom</packaging>
<name>${project.artifactId}</name>
<jacoco.version>0.6.2.201302030002</jacoco.version>
<slf4j.version>1.7.2</slf4j.version>
<salGeneratorPath>${project.build.directory}/generated-sources/sal</salGeneratorPath>
- <config.version>0.2.4-SNAPSHOT</config.version>
</properties>
<dependencies>
<parent>
<artifactId>config-plugin-parent</artifactId>
<groupId>org.opendaylight.controller</groupId>
- <version>0.2.4-SNAPSHOT</version>
+ <version>0.2.5-SNAPSHOT</version>
<relativePath>../config-plugin-parent</relativePath>
</parent>
<modelVersion>4.0.0</modelVersion>
<parent>
<artifactId>config-plugin-parent</artifactId>
<groupId>org.opendaylight.controller</groupId>
- <version>0.2.4-SNAPSHOT</version>
+ <version>0.2.5-SNAPSHOT</version>
<relativePath>../config-plugin-parent</relativePath>
</parent>
<modelVersion>4.0.0</modelVersion>
import org.junit.Test;
import org.mockito.Mock;
import org.mockito.MockitoAnnotations;
+import org.opendaylight.controller.config.api.ConflictingVersionException;
+import org.opendaylight.controller.config.api.ValidationException;
import org.opendaylight.controller.config.api.jmx.ObjectNameUtil;
import org.opendaylight.controller.config.manager.impl.AbstractConfigTest;
import org.opendaylight.controller.config.manager.impl.factoriesresolver.HardcodedModuleFactoriesResolver;
shutdownViaRuntimeJMX(secret);
}
- private void setSecret(String secret) throws InstanceNotFoundException {
+ private void setSecret(String secret) throws InstanceNotFoundException, ValidationException, ConflictingVersionException {
ConfigTransactionJMXClient transaction = configRegistryClient.createTransaction();
ObjectName on = transaction.lookupConfigBean(NAME, NAME);
ShutdownModuleMXBean proxy = transaction.newMXBeanProxy(on, ShutdownModuleMXBean.class);
<parent>
<groupId>org.opendaylight.controller</groupId>
<artifactId>config-plugin-parent</artifactId>
- <version>0.2.4-SNAPSHOT</version>
+ <version>0.2.5-SNAPSHOT</version>
<relativePath>../config-plugin-parent</relativePath>
</parent>
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>org.opendaylight.controller</groupId>
<artifactId>config-plugin-parent</artifactId>
- <version>0.2.4-SNAPSHOT</version>
+ <version>0.2.5-SNAPSHOT</version>
<relativePath>../config-plugin-parent</relativePath>
</parent>
<modelVersion>4.0.0</modelVersion>
<parent>
<artifactId>config-subsystem</artifactId>
<groupId>org.opendaylight.controller</groupId>
- <version>0.2.4-SNAPSHOT</version>
+ <version>0.2.5-SNAPSHOT</version>
</parent>
<artifactId>yang-jmx-generator-it</artifactId>
<parent>
<artifactId>config-subsystem</artifactId>
<groupId>org.opendaylight.controller</groupId>
- <version>0.2.4-SNAPSHOT</version>
+ <version>0.2.5-SNAPSHOT</version>
<relativePath>..</relativePath>
</parent>
<artifactId>yang-jmx-generator-plugin</artifactId>
ftlFile.getFtlTempleteLocation());
try {
template.process(ftlFile, writer);
- } catch (Throwable e) {
+ } catch (Exception e) {
throw new IllegalStateException(
"Template error while generating " + ftlFile, e);
}
<parent>
<artifactId>config-subsystem</artifactId>
<groupId>org.opendaylight.controller</groupId>
- <version>0.2.4-SNAPSHOT</version>
+ <version>0.2.5-SNAPSHOT</version>
</parent>
<artifactId>yang-jmx-generator</artifactId>
boolean providedServiceWasSet = false;
for (UnknownSchemaNode unknownNode : id.getUnknownSchemaNodes()) {
// TODO: test this
- if (ConfigConstants.PROVIDED_SERVICE_EXTENSION_QNAME.equals(unknownNode.getNodeType())) {
- // no op: 0 or more provided identities are allowed
- } else if (ConfigConstants.JAVA_NAME_PREFIX_EXTENSION_QNAME.equals(unknownNode.getNodeType())) {
+ boolean unknownNodeIsProvidedServiceExtension = ConfigConstants.PROVIDED_SERVICE_EXTENSION_QNAME.equals(unknownNode.getNodeType());
+ // true => no op: 0 or more provided identities are allowed
+
+ if (ConfigConstants.JAVA_NAME_PREFIX_EXTENSION_QNAME.equals(unknownNode.getNodeType())) {
// 0..1 allowed
checkState(
providedServiceWasSet == false,
format("More than one language extension %s is not allowed here: %s",
ConfigConstants.JAVA_NAME_PREFIX_EXTENSION_QNAME, id));
providedServiceWasSet = true;
- } else {
+ } else if (unknownNodeIsProvidedServiceExtension == false) {
throw new IllegalStateException("Unexpected language extension " + unknownNode.getNodeType());
}
}
import javax.management.openmbean.CompositeType;
import javax.management.openmbean.OpenDataException;
import javax.management.openmbean.OpenType;
+import java.util.ArrayList;
import java.util.HashMap;
+import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Set;
@Override
public CompositeType getOpenType() {
- String description = getNullableDescription() == null ? getAttributeYangName()
- : getNullableDescription();
- final String[] itemNames = new String[yangNameToAttributeMap.keySet()
- .size()];
- String[] itemDescriptions = itemNames;
- FunctionImpl functionImpl = new FunctionImpl(itemNames);
+ String description = getNullableDescription() == null ? getAttributeYangName() : getNullableDescription();
+
+ FunctionImpl functionImpl = new FunctionImpl();
Map<String, AttributeIfc> jmxPropertiesToTypesMap = getJmxPropertiesToTypesMap();
OpenType<?>[] itemTypes = Collections2.transform(
jmxPropertiesToTypesMap.entrySet(), functionImpl).toArray(
new OpenType<?>[] {});
+ String[] itemNames = functionImpl.getItemNames();
try {
// TODO add package name to create fully qualified name for this
// type
CompositeType compositeType = new CompositeType(
getUpperCaseCammelCase(), description, itemNames,
- itemDescriptions, itemTypes);
+ itemNames, itemTypes);
return compositeType;
} catch (OpenDataException e) {
throw new RuntimeException("Unable to create CompositeType for "
return packageName;
}
- private static final class FunctionImpl implements
- Function<Entry<String, AttributeIfc>, OpenType<?>> {
- private final String[] itemNames;
- int i = 0;
+}
- private FunctionImpl(String[] itemNames) {
- this.itemNames = itemNames;
- }
+class FunctionImpl implements
+ Function<Entry<String, AttributeIfc>, OpenType<?>> {
+ private final List<String> itemNames = new ArrayList<>();
- @Override
- public OpenType<?> apply(Entry<String, AttributeIfc> input) {
- AttributeIfc innerType = input.getValue();
- itemNames[i++] = input.getKey();
- return innerType.getOpenType();
- }
+ @Override
+ public OpenType<?> apply(Entry<String, AttributeIfc> input) {
+ AttributeIfc innerType = input.getValue();
+ itemNames.add(input.getKey());
+ return innerType.getOpenType();
+ }
+
+ public String[] getItemNames(){
+ return itemNames.toArray(new String[itemNames.size()]);
}
}
<parent>
<artifactId>config-subsystem</artifactId>
<groupId>org.opendaylight.controller</groupId>
- <version>0.2.4-SNAPSHOT</version>
+ <version>0.2.5-SNAPSHOT</version>
<relativePath>..</relativePath>
</parent>
<artifactId>yang-store-api</artifactId>
<parent>
<artifactId>config-subsystem</artifactId>
<groupId>org.opendaylight.controller</groupId>
- <version>0.2.4-SNAPSHOT</version>
+ <version>0.2.5-SNAPSHOT</version>
<relativePath>..</relativePath>
</parent>
<artifactId>yang-store-impl</artifactId>
<parent>
<groupId>org.opendaylight.controller</groupId>
<artifactId>config-plugin-parent</artifactId>
- <version>0.2.4-SNAPSHOT</version>
+ <version>0.2.5-SNAPSHOT</version>
<relativePath>../config-plugin-parent</relativePath>
</parent>
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>org.opendaylight.controller</groupId>
<artifactId>config-plugin-parent</artifactId>
- <version>0.2.4-SNAPSHOT</version>
+ <version>0.2.5-SNAPSHOT</version>
<relativePath>../config-plugin-parent</relativePath>
</parent>
@Override
public java.lang.AutoCloseable createInstance() {
- System.err.println(getAfi());
- System.err.println(getAfiIdentity());
+ org.slf4j.Logger logger = org.slf4j.LoggerFactory.getLogger(getClass());
+ logger.info("Afi: {}", getAfi());
+ logger.info("Afi class: {}", getAfiIdentity());
- getAfiIdentity();
for (Identities identities : getIdentities()) {
- identities.resolveAfi();
- identities.resolveSafi();
+ logger.info("Identities Afi class: {}", identities.resolveAfi());
+ logger.info("Identities Safi class: {}", identities.resolveSafi());
+
}
- getIdentitiesContainer().resolveAfi();
+ logger.info("IdentityContainer Afi class: {}", getIdentitiesContainer().resolveAfi());
return new AutoCloseable() {
@Override
- System.err.println(getAfi());
- System.err.println(getAfiIdentity());
+ org.slf4j.Logger logger = org.slf4j.LoggerFactory.getLogger(getClass());
+ logger.info("Afi: {}", getAfi());
+ logger.info("Afi class: {}", getAfiIdentity());
- getAfiIdentity();
for (Identities identities : getIdentities()) {
- identities.resolveAfi();
- identities.resolveSafi();
+ logger.info("Identities Afi class: {}", identities.resolveAfi());
+ logger.info("Identities Safi class: {}", identities.resolveSafi());
+
}
- getIdentitiesContainer().resolveAfi();
+ logger.info("IdentityContainer Afi class: {}", getIdentitiesContainer().resolveAfi());
return new AutoCloseable() {
@Override
fi
function usage {
- echo "Usage: $0 [-jmx] [-jmxport <num>] [-debug] [-debugsuspend] [-debugport <num>] [-start [<console port>]] [-stop] [-status] [-console] [-help] [<other args will automatically be used for the JVM>]"
+ echo "Usage: $0 [-jmx] [-jmxport <num>] [-debug] [-debugsuspend] [-debugport <num>] [-start [<console port>]] [-stop] [-status] [-console] [-help] [-agentpath:<path to lib>] [<other args will automatically be used for the JVM>]"
exit 1
}
consolestart=1
dohelp=0
extraJVMOpts=""
+agentPath=""
unknown_option=0
while true ; do
case "$1" in
-help) dohelp=1; shift;;
-D*) extraJVMOpts="${extraJVMOpts} $1"; shift;;
-X*) extraJVMOpts="${extraJVMOpts} $1"; shift;;
+ -agentpath:*) agentPath="$1"; shift;;
"") break ;;
*) echo "Unknown option $1"; unknown_option=1; shift ;;
esac
exit -1
fi
$JAVA_HOME/bin/java ${extraJVMOpts} \
+ ${agentPath} \
-Djava.io.tmpdir="${iotmpdir}/work/tmp" \
-Dosgi.install.area="${bdir}" \
-Dosgi.configuration.area="${confarea}/configuration" \
exit -1
fi
$JAVA_HOME/bin/java ${extraJVMOpts} \
+ ${agentPath} \
-Djava.io.tmpdir="${iotmpdir}/work/tmp" \
-Dosgi.install.area="${bdir}" \
-Dosgi.configuration.area="${confarea}/configuration" \
<!-- Dependency Versions -->
<mockito.version>1.9.5</mockito.version>
- <xtend.version>2.4.3</xtend.version>
+
<!-- Sonar properties using jacoco to retrieve integration test results -->
<sonar.java.coveragePlugin>jacoco</sonar.java.coveragePlugin>
<artifactId>slf4j-api</artifactId>
<version>${slf4j.version}</version>
</dependency>
- <dependency>
- <groupId>org.eclipse.xtend</groupId>
- <artifactId>org.eclipse.xtend.lib</artifactId>
- <version>${xtend.version}</version>
- </dependency>
+
<dependency>
<groupId>org.osgi</groupId>
<artifactId>org.osgi.core</artifactId>
*/
package org.opendaylight.controller.sal.binding.api.data;
-import java.util.concurrent.Future;
-
import org.opendaylight.controller.md.sal.common.api.data.DataChangePublisher;
import org.opendaylight.controller.md.sal.common.api.data.DataModificationTransactionFactory;
import org.opendaylight.controller.md.sal.common.api.data.DataReader;
import org.opendaylight.controller.sal.binding.api.BindingAwareService;
-import org.opendaylight.controller.sal.common.DataStoreIdentifier;
import org.opendaylight.yangtools.concepts.ListenerRegistration;
import org.opendaylight.yangtools.yang.binding.DataObject;
-import org.opendaylight.yangtools.yang.binding.DataRoot;
import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
-import org.opendaylight.yangtools.yang.common.RpcResult;
/**
* DataBrokerService provides unified access to the data stores available in the
* system.
- *
- *
+ *
+ *
* @see DataProviderService
*/
public interface DataBrokerService extends //
DataModificationTransactionFactory<InstanceIdentifier<? extends DataObject>, DataObject>, //
DataReader<InstanceIdentifier<? extends DataObject>, DataObject>, //
DataChangePublisher<InstanceIdentifier<? extends DataObject>, DataObject, DataChangeListener> {
-
- /**
- * Returns a data from specified Data Store.
- *
- * Returns all the data visible to the consumer from specified Data Store.
- *
- * @param <T>
- * Interface generated from YANG module representing root of data
- * @param store
- * Identifier of the store, from which will be data retrieved
- * @return data visible to the consumer
- */
- @Deprecated
- <T extends DataRoot> T getData(DataStoreIdentifier store, Class<T> rootType);
-
- /**
- * Returns a filtered subset of data from specified Data Store.
- *
- * <p>
- * The filter is modeled as an hierarchy of Java TOs starting with
- * implementation of {@link DataRoot} representing data root. The semantics
- * of the filter tree is the same as filter semantics defined in the NETCONF
- * protocol for rpc operations <code>get</code> and <code>get-config</code>
- * in Section 6 of RFC6241.
- *
- *
- * @see http://tools.ietf.org/html/rfc6241#section-6
- * @param <T>
- * Interface generated from YANG module representing root of data
- * @param store
- * Identifier of the store, from which will be data retrieved
- * @param filter
- * Data tree filter similar to the NETCONF filter
- * @return
- */
- @Deprecated
- <T extends DataRoot> T getData(DataStoreIdentifier store, T filter);
-
- /**
- * Returns a candidate data which are not yet commited.
- *
- *
- * @param <T>
- * Interface generated from YANG module representing root of data
- * @param store
- * Identifier of the store, from which will be data retrieved
- * @return
- */
- @Deprecated
- <T extends DataRoot> T getCandidateData(DataStoreIdentifier store, Class<T> rootType);
-
- /**
- * Returns a filtered subset of candidate data from specified Data Store.
- *
- * <p>
- * The filter is modeled as an hierarchy of {@link Node} starting with
- * {@link CompositeNode} representing data root. The semantics of the filter
- * tree is the same as filter semantics defined in the NETCONF protocol for
- * rpc operations <code>get</code> and <code>get-config</code> in Section 6
- * of RFC6241.
- *
- *
- * @see http://tools.ietf.org/html/rfc6241#section-6
- * @param <T>
- * Interface generated from YANG module representing root of data
- * @param store
- * Identifier of the store, from which will be data retrieved
- * @param filter
- * A filter data root
- * @return
- */
- @Deprecated
- <T extends DataRoot> T getCandidateData(DataStoreIdentifier store, T filter);
-
- /**
- *
- * @param <T>
- * Interface generated from YANG module representing root of data
- * @param store
- * Identifier of the store, in which will be the candidate data
- * modified
- * @param changeSet
- * Modification of data tree.
- * @return Result object containing the modified data tree if the operation
- * was successful, otherwise list of the encountered errors.
- */
- @Deprecated
- RpcResult<DataRoot> editCandidateData(DataStoreIdentifier store, DataRoot changeSet);
-
- /**
- * Initiates a two-phase commit of candidate data.
- *
- * <p>
- * The {@link Consumer} could initiate a commit of candidate data
- *
- * <p>
- * The successful commit changes the state of the system and may affect
- * several components.
- *
- * <p>
- * The effects of successful commit of data are described in the
- * specifications and YANG models describing the {@link Provider} components
- * of controller. It is assumed that {@link Consumer} has an understanding
- * of this changes.
- *
- *
- * @see DataCommitHandler for further information how two-phase commit is
- * processed.
- * @param store
- * Identifier of the store, where commit should occur.
- * @return Result of the commit, containing success information or list of
- * encountered errors, if commit was not successful.
- */
- @Deprecated
- Future<RpcResult<Void>> commit(DataStoreIdentifier store);
-
- @Deprecated
- DataObject getData(InstanceIdentifier<? extends DataObject> data);
-
- @Deprecated
- DataObject getConfigurationData(InstanceIdentifier<?> data);
/**
* Creates a data modification transaction.
- *
+ *
* @return new blank data modification transaction.
*/
- DataModificationTransaction beginTransaction();
-
- @Deprecated
- public void registerChangeListener(InstanceIdentifier<? extends DataObject> path, DataChangeListener changeListener);
-
- @Deprecated
- public void unregisterChangeListener(InstanceIdentifier<? extends DataObject> path, DataChangeListener changeListener);
+ @Override
+ DataModificationTransaction beginTransaction();
/**
- * Reads data subtree from configurational store.
- * (Store which is populated by consumer, which is usually used to
+ * Reads data subtree from configurational store.
+ * (Store which is populated by consumer, which is usually used to
* inject state into providers. E.g. Flow configuration)-
- *
+ *
*/
@Override
public DataObject readConfigurationData(InstanceIdentifier<? extends DataObject> path);
-
+
/**
- * Reads data subtree from operational store.
- * (Store which is populated by providers, which is usually used to
+ * Reads data subtree from operational store.
+ * (Store which is populated by providers, which is usually used to
* capture state of providers. E.g. Topology)
- *
+ *
*/
@Override
public DataObject readOperationalData(InstanceIdentifier<? extends DataObject> path);
-
+
/**
- * Register a data change listener for particular subtree.
- *
+ * Register a data change listener for particular subtree.
+ *
* Callback is invoked each time data in subtree changes.
- *
+ *
*/
@Override
public ListenerRegistration<DataChangeListener> registerDataChangeListener(
<dependency>
<groupId>org.opendaylight.controller</groupId>
<artifactId>yang-jmx-generator-plugin</artifactId>
- <version>0.2.4-SNAPSHOT</version>
+ <version>${config.version}</version>
</dependency>
<dependency>
<groupId>org.opendaylight.yangtools</groupId>
\r
import java.util.Map;
import java.util.Map.Entry;
-import java.util.concurrent.Future;
import java.util.concurrent.atomic.AtomicLong;
import org.opendaylight.controller.md.sal.common.impl.service.AbstractDataBroker;
import org.opendaylight.controller.sal.binding.api.data.DataChangeListener;
import org.opendaylight.controller.sal.binding.api.data.DataProviderService;
import org.opendaylight.controller.sal.binding.impl.util.BindingAwareDataReaderRouter;
-import org.opendaylight.controller.sal.common.DataStoreIdentifier;
import org.opendaylight.yangtools.yang.binding.DataObject;
-import org.opendaylight.yangtools.yang.binding.DataRoot;
import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
import org.opendaylight.yangtools.yang.binding.util.DataObjectReadingUtil;
-import org.opendaylight.yangtools.yang.common.RpcResult;
import com.google.common.base.Predicate;
import com.google.common.collect.ImmutableMap;
}\r
\r
@Override\r
- @Deprecated\r
- public <T extends DataRoot> T getData(DataStoreIdentifier store, Class<T> rootType) {\r
- throw new UnsupportedOperationException("Deprecated");\r
- }\r
-\r
- @Override\r
- @Deprecated\r
- public <T extends DataRoot> T getData(DataStoreIdentifier store, T filter) {\r
- throw new UnsupportedOperationException("Deprecated");\r
- }\r
-\r
- @Override\r
- @Deprecated\r
- public <T extends DataRoot> T getCandidateData(DataStoreIdentifier store, Class<T> rootType) {\r
- throw new UnsupportedOperationException("Deprecated");\r
- }\r
-\r
- @Override\r
- @Deprecated\r
- public <T extends DataRoot> T getCandidateData(DataStoreIdentifier store, T filter) {\r
- throw new UnsupportedOperationException("Deprecated");\r
- }\r
-\r
- @Override\r
- @Deprecated\r
- public RpcResult<DataRoot> editCandidateData(DataStoreIdentifier store, DataRoot changeSet) {\r
- throw new UnsupportedOperationException("Deprecated");\r
- }\r
-\r
- @Override\r
- @Deprecated\r
- public Future<RpcResult<Void>> commit(DataStoreIdentifier store) {\r
- throw new UnsupportedOperationException("Deprecated");\r
- }\r
-\r
- @Override\r
- @Deprecated\r
- public DataObject getData(InstanceIdentifier<? extends DataObject> data) {\r
- throw new UnsupportedOperationException("Deprecated");\r
- }\r
-\r
- @Override\r
- @Deprecated\r
- public DataObject getConfigurationData(InstanceIdentifier<?> data) {\r
- throw new UnsupportedOperationException("Deprecated");\r
- }\r
-\r
- @Override\r
- @Deprecated\r
- public void registerChangeListener(InstanceIdentifier<? extends DataObject> path, DataChangeListener changeListener) {\r
- throw new UnsupportedOperationException("Deprecated");\r
- }\r
-\r
- @Override\r
- @Deprecated\r
- public void unregisterChangeListener(InstanceIdentifier<? extends DataObject> path,\r
- DataChangeListener changeListener) {\r
- throw new UnsupportedOperationException("Deprecated");\r
- }\r
-\r
- @Override\r
- public void close() throws Exception {\r
+ public void close() {\r
\r
}
+++ /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.binding.impl
-
-import org.opendaylight.controller.sal.binding.api.data.DataProviderService
-import org.opendaylight.controller.sal.common.DataStoreIdentifier
-import org.opendaylight.yangtools.yang.binding.DataRoot
-import org.opendaylight.yangtools.yang.binding.InstanceIdentifier
-import org.opendaylight.yangtools.yang.binding.DataObject
-import org.opendaylight.controller.sal.binding.api.data.DataChangeListener
-
-abstract class DeprecatedDataAPISupport implements DataProviderService {
-
- @Deprecated
- override commit(DataStoreIdentifier store) {
- throw new UnsupportedOperationException("Deprecated")
- }
-
- @Deprecated
- override editCandidateData(DataStoreIdentifier store, DataRoot changeSet) {
- throw new UnsupportedOperationException("Deprecated")
- }
-
- @Deprecated
- override <T extends DataRoot> getCandidateData(DataStoreIdentifier store, Class<T> rootType) {
- throw new UnsupportedOperationException("Deprecated")
- }
-
- @Deprecated
- override <T extends DataRoot> T getCandidateData(DataStoreIdentifier store, T filter) {
- throw new UnsupportedOperationException("Deprecated")
- }
-
- @Deprecated
- override getConfigurationData(InstanceIdentifier<?> data) {
- throw new UnsupportedOperationException("Deprecated")
- }
-
- @Deprecated
- override <T extends DataRoot> getData(DataStoreIdentifier store, Class<T> rootType) {
- throw new UnsupportedOperationException("Deprecated")
- }
-
- @Deprecated
- override <T extends DataRoot> T getData(DataStoreIdentifier store, T filter) {
- throw new UnsupportedOperationException("Deprecated")
- }
-
- @Deprecated
- override getData(InstanceIdentifier<? extends DataObject> path) {
- return readOperationalData(path);
- }
-
- override registerChangeListener(InstanceIdentifier<? extends DataObject> path, DataChangeListener changeListener) {
- }
-
- override unregisterChangeListener(InstanceIdentifier<? extends DataObject> path,
- DataChangeListener changeListener) {
- }
-
-}
<dependency>
<groupId>org.opendaylight.controller</groupId>
<artifactId>yang-jmx-generator-plugin</artifactId>
- <version>0.2.4-SNAPSHOT</version>
+ <version>${config.version}</version>
</dependency>
<dependency>
<groupId>org.opendaylight.yangtools</groupId>
<artifactId>maven-sal-api-gen-plugin</artifactId>
- <version>${yangtools.version}</version>
+ <version>${yangtools.version}</version>
<type>jar</type>
</dependency>
</dependencies>
--- /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.binding.test.bugfix;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertTrue;
+
+import org.junit.Test;
+import org.opendaylight.controller.md.sal.common.api.TransactionStatus;
+import org.opendaylight.controller.sal.binding.api.data.DataModificationTransaction;
+import org.opendaylight.controller.sal.binding.test.AbstractDataServiceTest;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.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.TableBuilder;
+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.types.rev131026.flow.InstructionsBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.types.rev131026.flow.MatchBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.types.rev131026.instruction.list.Instruction;
+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.yang.gen.v1.urn.opendaylight.l2.types.rev130827.VlanId;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.model.match.types.rev131026.match.VlanMatchBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.model.match.types.rev131026.vlan.match.fields.VlanIdBuilder;
+import org.opendaylight.yangtools.yang.binding.DataObject;
+import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
+import org.opendaylight.yangtools.yang.common.RpcResult;
+
+import com.google.common.collect.ImmutableList;
+
+public class WriteParentReadChildTest extends AbstractDataServiceTest {
+
+ private static final String FLOW_ID = "1234";
+ private static final short TABLE_ID = (short) 0;
+ private static final String NODE_ID = "node:1";
+
+ private static final NodeKey NODE_KEY = new NodeKey(new NodeId(NODE_ID));
+ private static final FlowKey FLOW_KEY = new FlowKey(new FlowId(FLOW_ID));
+ private static final TableKey TABLE_KEY = new TableKey(TABLE_ID);
+
+ private static final InstanceIdentifier<Node> NODE_INSTANCE_ID_BA = InstanceIdentifier.builder(Nodes.class) //
+ .child(Node.class, NODE_KEY).toInstance();
+
+ private static final InstanceIdentifier<Table> TABLE_INSTANCE_ID_BA = //
+ InstanceIdentifier.builder(NODE_INSTANCE_ID_BA) //
+ .augmentation(FlowCapableNode.class).child(Table.class, TABLE_KEY).build();
+
+ private static final InstanceIdentifier<? extends DataObject> FLOW_INSTANCE_ID_BA = //
+ InstanceIdentifier.builder(TABLE_INSTANCE_ID_BA) //
+ .child(Flow.class, FLOW_KEY) //
+ .toInstance();
+ /**
+ *
+ * The scenario tests writing parent node, which also contains child items
+ * and then reading child directly, by specifying path to the child.
+ *
+ * Expected behaviour is child is returned.
+ *
+ * @throws Exception
+ */
+ @Test
+ public void writeTableReadFlow() throws Exception {
+
+ DataModificationTransaction modification = baDataService.beginTransaction();
+
+ Flow flow = new FlowBuilder() //
+ .setKey(FLOW_KEY) //
+ .setMatch(new MatchBuilder() //
+ .setVlanMatch(new VlanMatchBuilder() //
+ .setVlanId(new VlanIdBuilder() //
+ .setVlanId(new VlanId(10)) //
+ .build()) //
+ .build()) //
+ .build()) //
+ .setInstructions(new InstructionsBuilder() //
+ .setInstruction(ImmutableList.<Instruction>builder() //
+ .build()) //
+ .build()) //
+ .build();
+
+ Table table = new TableBuilder()
+ .setKey(TABLE_KEY)
+ .setFlow(ImmutableList.of(flow))
+ .build();
+
+ modification.putConfigurationData(TABLE_INSTANCE_ID_BA, table);
+ RpcResult<TransactionStatus> ret = modification.commit().get();
+ assertNotNull(ret);
+ assertEquals(TransactionStatus.COMMITED, ret.getResult());
+
+ DataObject readedTable = baDataService.readConfigurationData(TABLE_INSTANCE_ID_BA);
+ assertNotNull("Readed table should not be nul.", readedTable);
+ assertTrue(readedTable instanceof Table);
+
+ DataObject readedFlow = baDataService.readConfigurationData(FLOW_INSTANCE_ID_BA);
+ assertNotNull("Readed flow should not be null.",readedFlow);
+ assertTrue(readedFlow instanceof Flow);
+ assertEquals(flow, readedFlow);
+
+ }
+}
\ No newline at end of file
<dependencies>
+ <!--Compile scopes for all testing dependencies are intentional-->
+ <!--This way, all testing dependencies can be transitively used by other integration test modules-->
+ <!--If the dependencies are test scoped, they are not visible to other maven modules depending on sal-binding-it-->
+ <!--TODO Create generic utilities(extract from this module) for integration tests on the controller-->
<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>
- <scope>provided</scope>
</dependency>
<dependency>
<groupId>org.ops4j.pax.exam</groupId>
<artifactId>pax-exam-container-native</artifactId>
- <scope>test</scope>
+ <scope>compile</scope>
</dependency>
<dependency>
<groupId>org.ops4j.pax.exam</groupId>
<artifactId>pax-exam-junit4</artifactId>
- <scope>test</scope>
+ <scope>compile</scope>
</dependency>
<dependency>
<groupId>org.opendaylight.controller</groupId>
<artifactId>config-netconf-connector</artifactId>
- <scope>test</scope>
</dependency>
<dependency>
<groupId>org.opendaylight.controller</groupId>
<dependency>
<groupId>org.ops4j.pax.exam</groupId>
<artifactId>pax-exam-link-mvn</artifactId>
- <scope>test</scope>
+ <scope>compile</scope>
</dependency>
<dependency>
<groupId>equinoxSDK381</groupId>
<artifactId>org.eclipse.osgi</artifactId>
- <scope>test</scope>
</dependency>
<dependency>
<groupId>org.slf4j</groupId>
<dependency>
<groupId>org.mockito</groupId>
<artifactId>mockito-all</artifactId>
- <scope>test</scope>
</dependency>
<dependency>
<groupId>org.opendaylight.controller.model</groupId>
*/
package org.opendaylight.controller.md.sal.binding.util;
-import java.util.concurrent.Future;
-
import org.opendaylight.controller.sal.binding.api.NotificationListener;
import org.opendaylight.controller.sal.binding.api.NotificationService;
import org.opendaylight.controller.sal.binding.api.RpcConsumerRegistry;
import org.opendaylight.controller.sal.binding.api.data.DataBrokerService;
import org.opendaylight.controller.sal.binding.api.data.DataChangeListener;
import org.opendaylight.controller.sal.binding.api.data.DataModificationTransaction;
-import org.opendaylight.controller.sal.common.DataStoreIdentifier;
import org.opendaylight.yangtools.concepts.ListenerRegistration;
import org.opendaylight.yangtools.concepts.Registration;
import org.opendaylight.yangtools.yang.binding.DataObject;
-import org.opendaylight.yangtools.yang.binding.DataRoot;
import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
import org.opendaylight.yangtools.yang.binding.Notification;
import org.opendaylight.yangtools.yang.binding.RpcService;
-import org.opendaylight.yangtools.yang.common.RpcResult;
import com.google.common.base.Preconditions;
return getNotificationBrokerChecked().registerNotificationListener(listener);
}
- @Override
- @Deprecated
- public <T extends DataRoot> T getData(DataStoreIdentifier store, Class<T> rootType) {
- return getDataBrokerChecked().getData(store, rootType);
- }
-
- @Override
- @Deprecated
- public <T extends DataRoot> T getData(DataStoreIdentifier store, T filter) {
- return getDataBrokerChecked().getData(store, filter);
- }
-
- @Override
- @Deprecated
- public <T extends DataRoot> T getCandidateData(DataStoreIdentifier store, Class<T> rootType) {
- return getDataBrokerChecked().getCandidateData(store, rootType);
- }
-
- @Override
- @Deprecated
- public <T extends DataRoot> T getCandidateData(DataStoreIdentifier store, T filter) {
- return getDataBrokerChecked().getCandidateData(store, filter);
- }
-
- @Override
- @Deprecated
- public RpcResult<DataRoot> editCandidateData(DataStoreIdentifier store, DataRoot changeSet) {
- return getDataBrokerChecked().editCandidateData(store, changeSet);
- }
-
- @Override
- @Deprecated
- public Future<RpcResult<Void>> commit(DataStoreIdentifier store) {
- return getDataBrokerChecked().commit(store);
- }
-
- @Override
- @Deprecated
- public DataObject getData(InstanceIdentifier<? extends DataObject> data) {
- return getDataBrokerChecked().getData(data);
- }
-
- @Override
- @Deprecated
- public DataObject getConfigurationData(InstanceIdentifier<?> data) {
- return getDataBrokerChecked().getConfigurationData(data);
- }
-
@Override
public DataModificationTransaction beginTransaction() {
return getDataBrokerChecked().beginTransaction();
}
- @Override
- @Deprecated
- public void registerChangeListener(InstanceIdentifier<? extends DataObject> path, DataChangeListener changeListener) {
- getDataBrokerChecked().registerChangeListener(path, changeListener);
- }
-
- @Override
- @Deprecated
- public void unregisterChangeListener(InstanceIdentifier<? extends DataObject> path,
- DataChangeListener changeListener) {
- getDataBrokerChecked().unregisterChangeListener(path, changeListener);
- }
-
@Override
@Deprecated
public DataObject readConfigurationData(InstanceIdentifier<? extends DataObject> path) {
* this is responsibility of the coordinator (broker or some component of the
* broker).
*
- * The commit handlers are responsible for changing the internal state of the
- * provider to reflect the commited changes in data.
+ * Commit handlers are responsible for changing the internal state of the
+ * provider to reflect the committed changes in data.
*
* <h3>Two-phase commit</h3>
*
.addAll(transaction.getCreatedOperationalData().keySet())
.addAll(transaction.getRemovedOperationalData()).build();
- log.trace("Transaction: {} Affected Subtrees:", transactionId, changedPaths);
+ log.trace("Transaction: {} Affected Subtrees: {}", transactionId, changedPaths);
// The transaction has no effects, let's just shortcut it
if (changedPaths.isEmpty()) {
captureFinalState(listeners);
- log.trace("Transaction: {} Notifying listeners.");
+ log.trace("Transaction: {} Notifying listeners.", transactionId);
publishDataChangeEvent(listeners);
return Rpcs.<TransactionStatus> getRpcResult(true, TransactionStatus.COMMITED,
<dependency>
<groupId>org.opendaylight.controller</groupId>
<artifactId>yang-jmx-generator-plugin</artifactId>
- <version>0.2.4-SNAPSHOT</version>
+ <version>${config.version}</version>
</dependency>
<dependency>
<groupId>org.opendaylight.yangtools</groupId>
/**
* Core component of the SAL layer responsible for wiring the SAL consumers.
- *
+ *
* The responsibility of the broker is to maintain registration of SAL
* functionality {@link Consumer}s and {@link Provider}s, store provider and
* consumer specific context and functionality registration via
* {@link ConsumerSession} and provide access to infrastructure services, which
* removes direct dependencies between providers and consumers.
- *
- *
+ *
+ *
* <h3>Infrastructure services</h3> Some examples of infrastructure services:
- *
+ *
* <ul>
* <li>RPC Invocation - see {@link ConsumerSession#rpc(QName, CompositeNode)},
* {@link ProviderSession#addRpcImplementation(QName, RpcImplementation)} and
* <li>Data Store access and modification - see {@link DataBrokerService} and
* {@link DataProviderService}
* </ul>
- *
+ *
* The services are exposed via session.
- *
+ *
* <h3>Session-based access</h3>
- *
+ *
* The providers and consumers needs to register in order to use the
* binding-independent SAL layer and to expose functionality via SAL layer.
- *
+ *
* For more information about session-based access see {@link ConsumerSession}
* and {@link ProviderSession}
- *
- *
- *
+ *
+ *
+ *
*/
public interface Broker {
/**
* Registers the {@link Consumer}, which will use the SAL layer.
- *
+ *
* <p>
* During the registration, the broker obtains the initial functionality
* from consumer, using the {@link Consumer#getConsumerFunctionality()}, and
* register that functionality into system and concrete infrastructure
* services.
- *
+ *
* <p>
* Note that consumer could register additional functionality at later point
* by using service and functionality specific APIs.
- *
+ *
* <p>
* The consumer is required to use returned session for all communication
* with broker or one of the broker services. The session is announced to
* the consumer by invoking
* {@link Consumer#onSessionInitiated(ConsumerSession)}.
- *
+ *
* @param cons
* Consumer to be registered.
* @param context
/**
* Registers the {@link Provider}, which will use the SAL layer.
- *
+ *
* <p>
* During the registration, the broker obtains the initial functionality
* from consumer, using the {@link Provider#getProviderFunctionality()}, and
* register that functionality into system and concrete infrastructure
* services.
- *
+ *
* <p>
* Note that consumer could register additional functionality at later point
* by using service and functionality specific APIs (e.g.
* {@link ProviderSession#addRpcImplementation(QName, RpcImplementation)}
- *
+ *
* <p>
* The consumer is <b>required to use</b> returned session for all
* communication with broker or one of the broker services. The session is
* announced to the consumer by invoking
* {@link Provider#onSessionInitiated(ProviderSession)}.
- *
- *
+ *
+ *
* @param prov
* Provider to be registered.
* @param context
/**
* {@link Consumer} specific access to the SAL functionality.
- *
+ *
* <p>
* ConsumerSession is {@link Consumer}-specific access to the SAL
* functionality and infrastructure services.
- *
+ *
* <p>
* The session serves to store SAL context (e.g. registration of
* functionality) for the consumer and provides access to the SAL
* infrastructure services and other functionality provided by
* {@link Provider}s.
- *
- *
- *
+ *
+ *
+ *
*/
public interface ConsumerSession {
/**
* Sends an RPC to other components registered to the broker.
- *
+ *
* @see RpcImplementation
* @param rpc
* Name of RPC
/**
* Returns a session specific instance (implementation) of requested
* service
- *
+ *
* @param service
* Broker service
* @return Session specific implementation of service
/**
* Closes a session between consumer and broker.
- *
+ *
* <p>
* The close operation unregisters a consumer and remove all registered
* functionality of the consumer from the system.
- *
+ *
*/
void close();
}
/**
* {@link Provider} specific access to the SAL functionality.
- *
+ *
* <p>
* ProviderSession is {@link Provider}-specific access to the SAL
* functionality and infrastructure services, which also allows for exposing
* the provider's functionality to the other {@link Consumer}s.
- *
+ *
* <p>
* The session serves to store SAL context (e.g. registration of
* functionality) for the providers and exposes access to the SAL
* infrastructure services, dynamic functionality registration and any other
* functionality provided by other {@link Provider}s.
- *
+ *
*/
public interface ProviderSession extends ConsumerSession {
/**
* Registers an implementation of the rpc.
- *
+ *
* <p>
* The registered rpc functionality will be available to all other
* consumers and providers registered to the broker, which are aware of
* the {@link QName} assigned to the rpc.
- *
+ *
* <p>
* There is no assumption that rpc type is in the set returned by
* invoking {@link RpcImplementation#getSupportedRpcs()}. This allows
* for dynamic rpc implementations.
- *
+ *
* @param rpcType
* Name of Rpc
* @param implementation
/**
* Closes a session between provider and SAL.
- *
+ *
* <p>
* The close operation unregisters a provider and remove all registered
* functionality of the provider from the system.
boolean isClosed();
Set<QName> getSupportedRpcs();
-
+
ListenerRegistration<RpcRegistrationListener> addRpcRegistrationListener(RpcRegistrationListener listener);
}
public interface RpcRegistration extends Registration<RpcImplementation> {
QName getType();
+
+ @Override
+ void close();
}
public interface RoutedRpcRegistration extends RpcRegistration,
import org.opendaylight.yangtools.yang.data.api.CompositeNode;
/**
- * {@link Provider}'s implementation of rpc.
- *
- * In order to expose the rpc to other components, the provider MUST register
- * concrete implementation of this interface
- *
+ * {@link Provider}'s implementation of an RPC.
+ *
+ * In order to expose an RPC to other components, the provider MUST register
+ * a concrete implementation of this interface.
+ *
* The registration could be done by :
* <ul>
* <li>returning an instance of implementation in the return value of
* arguments to the
* {@link ProviderSession#addRpcImplementation(QName, RpcImplementation)}
* </ul>
- *
+ *
* The simplified process of the invocation of rpc is following:
- *
+ *
* <ol>
* <li> {@link Consumer} invokes
* {@link ConsumerSession#rpc(QName, CompositeNode)}
* {@link RpcResult}
* <li> {@link Broker} returns the {@link RpcResult} to {@link Consumer}
* </ol>
- *
- *
+ *
+ *
*/
public interface RpcImplementation extends Provider.ProviderFunctionality {
/**
* A set of rpc types supported by implementation.
- *
+ *
* The set of rpc {@link QName}s which are supported by this implementation.
* This set is used, when {@link Provider} is registered to the SAL, to
* register and expose the implementation of the returned rpcs.
- *
+ *
* @return Set of QNames identifying supported RPCs
*/
Set<QName> getSupportedRpcs();
/**
* Invokes a implementation of specified rpc.
- *
- *
+ *
+ *
* @param rpc
* Rpc to be invoked
* @param input
* Input data for rpc.
- *
+ *
* @throws IllegalArgumentException
* <ul>
* <li>If rpc is null.
<dependency>
<groupId>org.opendaylight.controller</groupId>
<artifactId>yang-jmx-generator-plugin</artifactId>
- <version>0.2.4-SNAPSHOT</version>
+ <version>${config.version}</version>
</dependency>
<dependency>
<groupId>org.opendaylight.yangtools</groupId>
import static com.google.common.base.Preconditions.checkState;
+import java.io.Console;
import java.util.ArrayList;
import java.util.Comparator;
+import java.util.HashMap;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Map;
import java.util.Map.Entry;
+import java.util.Set;
import java.util.concurrent.Future;
+import javax.activation.UnsupportedDataTypeException;
+
import org.opendaylight.controller.md.sal.common.api.TransactionStatus;
import org.opendaylight.controller.md.sal.common.api.data.DataModification;
import org.opendaylight.controller.md.sal.common.api.data.DataReader;
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.api.SimpleNode;
import org.opendaylight.yangtools.yang.data.impl.CompositeNodeTOImpl;
+import org.opendaylight.yangtools.yang.model.api.ConstraintDefinition;
+import org.opendaylight.yangtools.yang.model.api.ContainerSchemaNode;
import org.opendaylight.yangtools.yang.model.api.DataSchemaNode;
+import org.opendaylight.yangtools.yang.model.api.ListSchemaNode;
import org.opendaylight.yangtools.yang.model.api.SchemaContext;
import org.opendaylight.yangtools.yang.model.api.SchemaContextListener;
-import org.opendaylight.yangtools.yang.model.api.SchemaServiceListener;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
+import com.google.common.base.Optional;
import com.google.common.base.Predicate;
import com.google.common.collect.FluentIterable;
import com.google.common.collect.ImmutableSet;
public class SchemaAwareDataStoreAdapter extends AbstractLockableDelegator<DataStore> implements //
DataStore, //
- SchemaServiceListener, //
SchemaContextListener, //
AutoCloseable {
DataModification<InstanceIdentifier, CompositeNode> original) {
NormalizedDataModification normalized = new NormalizedDataModification(original);
for (Entry<InstanceIdentifier, CompositeNode> entry : original.getUpdatedConfigurationData().entrySet()) {
- normalized.putConfigurationData(entry.getKey(), entry.getValue());
+ normalized.putDeepConfigurationData(entry.getKey(), entry.getValue());
}
for (Entry<InstanceIdentifier, CompositeNode> entry : original.getUpdatedOperationalData().entrySet()) {
- normalized.putOperationalData(entry.getKey(), entry.getValue());
+ normalized.putDeepOperationalData(entry.getKey(), entry.getValue());
}
for (InstanceIdentifier entry : original.getRemovedConfigurationData()) {
normalized.deepRemoveConfigurationData(entry);
private class NormalizedDataModification extends AbstractDataModification<InstanceIdentifier, CompositeNode> {
+ private final String CONFIGURATIONAL_DATA_STORE_MARKER = "configurational";
+ private final String OPERATIONAL_DATA_STORE_MARKER = "operational";
private final Object identifier;
private TransactionStatus status;
}
}
+ public void putDeepConfigurationData(InstanceIdentifier entryKey, CompositeNode entryData) {
+ this.putCompositeNodeData(entryKey, entryData, CONFIGURATIONAL_DATA_STORE_MARKER);
+ }
+
+ public void putDeepOperationalData(InstanceIdentifier entryKey, CompositeNode entryData) {
+ this.putCompositeNodeData(entryKey, entryData, OPERATIONAL_DATA_STORE_MARKER);
+ }
+
@Override
public Object getIdentifier() {
return this.identifier;
CompositeNode modified) {
return mergeData(path, stored, modified, false);
}
- }
+ private void putData(InstanceIdentifier entryKey, CompositeNode entryData, String dataStoreIdentifier) {
+ if (dataStoreIdentifier != null && entryKey != null && entryData != null) {
+ switch (dataStoreIdentifier) {
+ case (CONFIGURATIONAL_DATA_STORE_MARKER):
+ this.putConfigurationData(entryKey, entryData);
+ break;
+ case (OPERATIONAL_DATA_STORE_MARKER):
+ this.putOperationalData(entryKey, entryData);
+ break;
+
+ default :
+ LOG.error(dataStoreIdentifier + " is NOT valid DataStore switch marker");
+ throw new RuntimeException(dataStoreIdentifier + " is NOT valid DataStore switch marker");
+ }
+ }
+ }
+
+ private void putCompositeNodeData(InstanceIdentifier entryKey, CompositeNode entryData, String dataStoreIdentifier) {
+ this.putData(entryKey, entryData, dataStoreIdentifier);
+
+ for (Node<?> child : entryData.getChildren()) {
+ InstanceIdentifier subEntryId = InstanceIdentifier.builder(entryKey).node(child.getNodeType()).toInstance();
+ if (child instanceof CompositeNode) {
+ DataSchemaNode subSchema = schemaNodeFor(subEntryId);
+ CompositeNode compNode = (CompositeNode) child;
+ InstanceIdentifier instanceId = null;
+
+ if (subSchema instanceof ListSchemaNode) {
+ ListSchemaNode listSubSchema = (ListSchemaNode) subSchema;
+ Map<QName, Object> mapOfSubValues = this.getValuesFromListSchema(listSubSchema, (CompositeNode) child);
+ if (mapOfSubValues != null) {
+ instanceId = InstanceIdentifier.builder(entryKey).nodeWithKey(listSubSchema.getQName(), mapOfSubValues).toInstance();
+ }
+ }
+ else if (subSchema instanceof ContainerSchemaNode) {
+ ContainerSchemaNode containerSchema = (ContainerSchemaNode) subSchema;
+ instanceId = InstanceIdentifier.builder(entryKey).node(subSchema.getQName()).toInstance();
+ }
+ if (instanceId != null) {
+ this.putCompositeNodeData(instanceId, compNode, dataStoreIdentifier);
+ }
+ }
+ }
+ }
+
+ private Map<QName, Object> getValuesFromListSchema (ListSchemaNode listSchema, CompositeNode entryData) {
+ List<QName> keyDef = listSchema.getKeyDefinition();
+ if (keyDef != null && ! keyDef.isEmpty()) {
+ Map<QName, Object> map = new HashMap<QName, Object>();
+ for (QName key : keyDef) {
+ List<Node<?>> data = entryData.get(key);
+ if (data != null && ! data.isEmpty()) {
+ for (Node<?> nodeData : data) {
+ if (nodeData instanceof SimpleNode<?>) {
+ map.put(key, data.get(0).getValue());
+ }
+ }
+ }
+ }
+ return map;
+ }
+ return null;
+ }
+ }
}
<artifactId>sal-parent</artifactId>
<version>1.1-SNAPSHOT</version>
</parent>
- <properties>
- <netconf.version>0.2.4-SNAPSHOT</netconf.version>
- </properties>
+
<artifactId>sal-netconf-connector</artifactId>
<scm>
<connection>scm:git:ssh://git.opendaylight.org:29418/controller.git</connection>
<dependency>
<groupId>org.opendaylight.controller</groupId>
<artifactId>yang-jmx-generator-plugin</artifactId>
- <version>0.2.4-SNAPSHOT</version>
+ <version>${config.version}</version>
</dependency>
<dependency>
<groupId>org.opendaylight.yangtools</groupId>
<artifactId>maven-sal-api-gen-plugin</artifactId>
- <version>${yangtools.version}</version>
+ <version>${yangtools.version}</version>
<type>jar</type>
</dependency>
</dependencies>
package org.opendaylight.controller.sal.restconf.binding.impl;
import java.net.URL;
-import java.util.concurrent.Future;
+
import org.opendaylight.controller.sal.binding.api.data.DataBrokerService;
import org.opendaylight.controller.sal.binding.api.data.DataChangeListener;
import org.opendaylight.controller.sal.binding.api.data.DataModificationTransaction;
-import org.opendaylight.controller.sal.common.DataStoreIdentifier;
import org.opendaylight.yangtools.concepts.ListenerRegistration;
import org.opendaylight.yangtools.restconf.client.api.RestconfClientContext;
import org.opendaylight.yangtools.restconf.client.api.RestconfClientContextFactory;
import org.opendaylight.yangtools.restconf.client.api.UnsupportedProtocolException;
import org.opendaylight.yangtools.yang.binding.DataObject;
-import org.opendaylight.yangtools.yang.binding.DataRoot;
import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
-import org.opendaylight.yangtools.yang.common.RpcResult;
import org.opendaylight.yangtools.yang.data.impl.codec.BindingIndependentMappingService;
import org.opendaylight.yangtools.yang.model.api.SchemaContextHolder;
import org.slf4j.Logger;
public DataBrokerServiceImpl(URL baseUrl, BindingIndependentMappingService mappingService, SchemaContextHolder schemaContextHolder) throws UnsupportedProtocolException {
this.restconfClientContext = restconfClientContextFactory.getRestconfClientContext(baseUrl, mappingService, schemaContextHolder);
}
- @Override
- public <T extends DataRoot> T getData(DataStoreIdentifier store, Class<T> rootType) {
- return null;
- }
-
- @Override
- public <T extends DataRoot> T getData(DataStoreIdentifier store, T filter) {
- return null;
- }
-
- @Override
- public <T extends DataRoot> T getCandidateData(DataStoreIdentifier store, Class<T> rootType) {
- return null;
- }
-
- @Override
- public <T extends DataRoot> T getCandidateData(DataStoreIdentifier store, T filter) {
- return null;
- }
-
- @Override
- public RpcResult<DataRoot> editCandidateData(DataStoreIdentifier store, DataRoot changeSet) {
- return null;
- }
-
- @Override
- public Future<RpcResult<Void>> commit(DataStoreIdentifier store) {
- return null;
- }
-
- @Override
- public DataObject getData(InstanceIdentifier<? extends DataObject> data) {
- return null;
- }
-
- @Override
- public DataObject getConfigurationData(InstanceIdentifier<?> data) {
- return null;
- }
@Override
public DataModificationTransaction beginTransaction() {
return null;
}
- @Override
- public void registerChangeListener(InstanceIdentifier<? extends DataObject> path, DataChangeListener changeListener) {
-
- }
-
- @Override
- public void unregisterChangeListener(InstanceIdentifier<? extends DataObject> path, DataChangeListener changeListener) {
-
- }
-
@Override
public DataObject readConfigurationData(InstanceIdentifier<? extends DataObject> path) {
//TODO implementation using restconf-client
//TODO implementation using restconf-client
return null;
}
-
-
-
-
-
}
--- /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.broker.client;
+
+import org.opendaylight.controller.sal.binding.api.BindingAwareBroker.ConsumerContext;
+
+public interface SalRemoteClient extends AutoCloseable {
+
+ ConsumerContext registerConsumer();
+
+}
--- /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.broker.client;
+
+import java.net.URL;
+
+public class SalRemoteClientDeployer {
+
+ public static SalRemoteClient createSalRemoteClient(final URL url) {
+ return new SalRemoteClientImpl(url);
+ }
+
+}
--- /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.broker.client;
+
+import java.net.URL;
+
+import javassist.ClassPool;
+
+import org.opendaylight.controller.sal.binding.api.BindingAwareBroker.ConsumerContext;
+import org.opendaylight.controller.sal.binding.api.BindingAwareConsumer;
+import org.opendaylight.controller.sal.restconf.broker.SalRemoteServiceBroker;
+import org.opendaylight.yangtools.restconf.client.RestconfClientFactory;
+import org.opendaylight.yangtools.restconf.client.api.RestconfClientContext;
+import org.opendaylight.yangtools.restconf.client.api.UnsupportedProtocolException;
+import org.opendaylight.yangtools.sal.binding.generator.impl.ModuleInfoBackedContext;
+import org.opendaylight.yangtools.sal.binding.generator.impl.RuntimeGeneratedMappingServiceImpl;
+import org.opendaylight.yangtools.yang.binding.Augmentation;
+import org.opendaylight.yangtools.yang.binding.util.BindingReflections;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import com.google.common.base.Preconditions;
+
+class SalRemoteClientImpl implements SalRemoteClient {
+
+ private static final Logger logger = LoggerFactory.getLogger(SalRemoteClientImpl.class);
+
+ private final RestconfClientContext restconfClientContext;
+ private final SalRemoteServiceBroker salRemoteBroker;
+ private final RuntimeGeneratedMappingServiceImpl mappingService;
+
+ public SalRemoteClientImpl(final URL url) {
+ Preconditions.checkNotNull(url);
+
+ this.mappingService = new RuntimeGeneratedMappingServiceImpl();
+ this.mappingService.setPool(ClassPool.getDefault());
+ this.mappingService.init();
+
+ final ModuleInfoBackedContext moduleInfo = ModuleInfoBackedContext.create();
+ moduleInfo.addModuleInfos(BindingReflections.loadModuleInfos());
+ this.mappingService.onGlobalContextUpdated(moduleInfo.tryToCreateSchemaContext().get());
+
+ try {
+ this.restconfClientContext = new RestconfClientFactory().getRestconfClientContext(url, this.mappingService,
+ this.mappingService);
+
+ this.salRemoteBroker = new SalRemoteServiceBroker("remote-broker", restconfClientContext);
+ this.salRemoteBroker.start();
+ } catch (UnsupportedProtocolException e) {
+ logger.error("Unsupported protocol {}.", url.getProtocol(), e);
+ throw new IllegalArgumentException("Unsupported protocol.", e);
+ }
+ }
+
+ @Override
+ public ConsumerContext registerConsumer() {
+ return this.salRemoteBroker.registerConsumer(new BindingAwareConsumer() {
+
+ @Override
+ public void onSessionInitialized(ConsumerContext session) {
+ }
+ }, null);
+ }
+
+ @Override
+ public void close() throws Exception {
+ this.restconfClientContext.close();
+ this.salRemoteBroker.close();
+ }
+
+}
import org.opendaylight.controller.sal.binding.api.data.DataBrokerService;
import org.opendaylight.controller.sal.binding.api.data.DataChangeListener;
import org.opendaylight.controller.sal.binding.api.data.DataModificationTransaction;
-import org.opendaylight.controller.sal.common.DataStoreIdentifier;
import org.opendaylight.controller.sal.restconf.broker.listeners.RemoteDataChangeNotificationListener;
import org.opendaylight.controller.sal.restconf.broker.tools.RemoteStreamTools;
import org.opendaylight.controller.sal.restconf.broker.transactions.RemoteDataModificationTransaction;
import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.controller.md.sal.remote.rev140114.CreateDataChangeEventSubscriptionInputBuilder;
import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.controller.md.sal.remote.rev140114.CreateDataChangeEventSubscriptionOutput;
import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.controller.md.sal.remote.rev140114.SalRemoteService;
+import org.opendaylight.yangtools.concepts.AbstractListenerRegistration;
import org.opendaylight.yangtools.concepts.ListenerRegistration;
import org.opendaylight.yangtools.restconf.client.api.RestconfClientContext;
import org.opendaylight.yangtools.restconf.client.api.event.EventStreamInfo;
import org.opendaylight.yangtools.restconf.client.api.event.ListenableEventStreamContext;
import org.opendaylight.yangtools.yang.binding.DataObject;
-import org.opendaylight.yangtools.yang.binding.DataRoot;
import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
import org.opendaylight.yangtools.yang.common.RpcResult;
import org.slf4j.Logger;
this.restconfClientContext = restconfClientContext;
this.salRemoteService = this.restconfClientContext.getRpcServiceContext(SalRemoteService.class).getRpcService();
}
- @Override
- public <T extends DataRoot> T getData(DataStoreIdentifier store, Class<T> rootType) {
- throw new UnsupportedOperationException("Deprecated");
- }
-
- @Override
- public <T extends DataRoot> T getData(DataStoreIdentifier store, T filter) {
- throw new UnsupportedOperationException("Deprecated");
- }
-
- @Override
- public <T extends DataRoot> T getCandidateData(DataStoreIdentifier store, Class<T> rootType) {
- throw new UnsupportedOperationException("Deprecated");
- }
-
- @Override
- public <T extends DataRoot> T getCandidateData(DataStoreIdentifier store, T filter) {
- throw new UnsupportedOperationException("Deprecated");
- }
-
- @Override
- public RpcResult<DataRoot> editCandidateData(DataStoreIdentifier store, DataRoot changeSet) {
- throw new UnsupportedOperationException("Deprecated");
- }
-
- @Override
- public Future<RpcResult<Void>> commit(DataStoreIdentifier store) {
- throw new UnsupportedOperationException("Deprecated");
- }
-
- @Override
- public DataObject getData(InstanceIdentifier<? extends DataObject> data) {
- throw new UnsupportedOperationException("Deprecated");
- }
-
- @Override
- public DataObject getConfigurationData(InstanceIdentifier<?> data) {
- throw new UnsupportedOperationException("Deprecated");
- }
@Override
public DataModificationTransaction beginTransaction() {
return remoteDataModificationTransaction;
}
- @Override
- public void registerChangeListener(InstanceIdentifier<? extends DataObject> path, DataChangeListener changeListener) {
- throw new UnsupportedOperationException("Deprecated");
- }
-
- @Override
- public void unregisterChangeListener(InstanceIdentifier<? extends DataObject> path, DataChangeListener changeListener) {
- throw new UnsupportedOperationException("Deprecated");
- }
-
@Override
public DataObject readConfigurationData(InstanceIdentifier<? extends DataObject> path) {
try {
final Map<String,EventStreamInfo> desiredEventStream = RemoteStreamTools.createEventStream(restconfClientContext,streamName);
ListenableEventStreamContext restConfListenableEventStreamContext = restconfClientContext.getEventStreamContext(desiredEventStream.get(streamName));
RemoteDataChangeNotificationListener remoteDataChangeNotificationListener = new RemoteDataChangeNotificationListener(listener);
- restConfListenableEventStreamContext.registerNotificationListener(remoteDataChangeNotificationListener);
- return new SalRemoteDataListenerRegistration(listener);
- }
-
- private class SalRemoteDataListenerRegistration implements ListenerRegistration<DataChangeListener> {
- private final DataChangeListener dataChangeListener;
- public SalRemoteDataListenerRegistration(DataChangeListener dataChangeListener){
- this.dataChangeListener = dataChangeListener;
- }
- @Override
- public DataChangeListener getInstance() {
- return this.dataChangeListener;
- }
- @Override
- public void close() {
- //noop
- }
+ final ListenerRegistration<?> reg = restConfListenableEventStreamContext.registerNotificationListener(remoteDataChangeNotificationListener);
+ return new AbstractListenerRegistration<DataChangeListener>(listener) {
+ @Override
+ protected void removeRegistration() {
+ reg.close();
+ }
+ };
}
}
<parent>
<artifactId>netconf-subsystem</artifactId>
<groupId>org.opendaylight.controller</groupId>
- <version>0.2.4-SNAPSHOT</version>
+ <version>0.2.5-SNAPSHOT</version>
</parent>
<artifactId>config-netconf-connector</artifactId>
<name>${project.artifactId}</name>
package org.opendaylight.controller.netconf.confignetconfconnector.operations;
-import java.util.HashMap;
-import java.util.Map;
-
+import org.opendaylight.controller.config.api.ConflictingVersionException;
+import org.opendaylight.controller.config.api.ValidationException;
import org.opendaylight.controller.config.api.jmx.CommitStatus;
import org.opendaylight.controller.config.util.ConfigRegistryClient;
import org.opendaylight.controller.netconf.api.NetconfDocumentedException;
import org.w3c.dom.Document;
import org.w3c.dom.Element;
+import java.util.HashMap;
+import java.util.Map;
+
public class Commit extends AbstractConfigNetconfOperation {
private static final Logger logger = LoggerFactory.getLogger(Commit.class);
try {
status = this.transactionProvider.commitTransaction();
} catch (final IllegalStateException e) {
+ // FIXME: when can IllegalStateException occur?
logger.warn("Commit failed: ", e);
final Map<String, String> errorInfo = new HashMap<>();
errorInfo.put(ErrorTag.operation_failed.name(),
"Operation failed. Use 'get-config' or 'edit-config' before triggering 'commit' operation");
throw new NetconfDocumentedException(e.getMessage(), e, ErrorType.application, ErrorTag.operation_failed,
ErrorSeverity.error, errorInfo);
- } catch (final NetconfDocumentedException e) {
- throw new NetconfDocumentedException(
- "Unable to retrieve config snapshot after commit for persister, details: " + e.getMessage(),
- ErrorType.application, ErrorTag.operation_failed, ErrorSeverity.error, e.getErrorInfo());
+ } catch (ValidationException e) {
+ throw NetconfDocumentedException.wrap(e);
+ } catch (ConflictingVersionException e) {
+ throw NetconfDocumentedException.wrap(e);
+
}
logger.trace("Datastore {} committed successfully: {}", Datastore.candidate, status);
package org.opendaylight.controller.netconf.confignetconfconnector.operations;
-import java.util.HashMap;
-import java.util.Map;
-
import org.opendaylight.controller.config.util.ConfigRegistryClient;
import org.opendaylight.controller.netconf.api.NetconfDocumentedException;
import org.opendaylight.controller.netconf.api.NetconfDocumentedException.ErrorSeverity;
import org.w3c.dom.Document;
import org.w3c.dom.Element;
+import java.util.HashMap;
+import java.util.Map;
+
public class DiscardChanges extends AbstractConfigNetconfOperation {
public static final String DISCARD = "discard-changes";
try {
fromXml(xml);
} catch (final IllegalArgumentException e) {
+ //FIXME where can IllegalStateException be thrown?
logger.warn("Rpc error: {}", ErrorTag.bad_attribute, e);
final Map<String, String> errorInfo = new HashMap<>();
errorInfo.put(ErrorTag.bad_attribute.name(), e.getMessage());
try {
this.transactionProvider.abortTransaction();
} catch (final IllegalStateException e) {
+ //FIXME where can IllegalStateException be thrown?
logger.warn("Abort failed: ", e);
final Map<String, String> errorInfo = new HashMap<>();
errorInfo
try {
checkXml(xml);
} catch (IllegalStateException e) {
+ //FIXME where can IllegalStateException be thrown? I see precondition that guards for programming bugs..
logger.warn("Rpc error: {}", ErrorTag.missing_attribute, e);
final Map<String, String> errorInfo = new HashMap<>();
errorInfo.put(ErrorTag.missing_attribute.name(), "Missing value of datastore attribute");
throw new NetconfDocumentedException(e.getMessage(), e, ErrorType.rpc, ErrorTag.missing_attribute,
ErrorSeverity.error, errorInfo);
} catch (final IllegalArgumentException e) {
+ // FIXME use checked exception if it has domain meaning
logger.warn("Rpc error: {}", ErrorTag.bad_attribute, e);
final Map<String, String> errorInfo = new HashMap<>();
errorInfo.put(ErrorTag.bad_attribute.name(), e.getMessage());
transactionProvider.validateTransaction();
} catch (ValidationException e) {
logger.warn("Validation failed", e);
- final Map<String, String> errorInfo = new HashMap<>();
- errorInfo.put(ErrorTag.operation_failed.name(), "Validation failed");
- throw new NetconfDocumentedException(e.getMessage(), e, ErrorType.application, ErrorTag.operation_failed,
- ErrorSeverity.error, errorInfo);
+ throw NetconfDocumentedException.wrap(e);
} catch (IllegalStateException e) {
logger.warn("Validation failed", e);
final Map<String, String> errorInfo = new HashMap<>();
import com.google.common.base.Preconditions;
import com.google.common.collect.Maps;
import com.google.common.collect.Multimap;
-import org.opendaylight.controller.config.api.JmxAttributeValidationException;
import org.opendaylight.controller.config.api.ValidationException;
import org.opendaylight.controller.config.util.ConfigRegistryClient;
import org.opendaylight.controller.config.util.ConfigTransactionClient;
EditConfigXmlParser.EditConfigExecution editConfigExecution) throws NetconfDocumentedException {
try {
set(configRegistryClient, editConfigExecution);
- } catch (IllegalStateException | JmxAttributeValidationException | ValidationException e) {
+
+ } catch (IllegalStateException e) {
+ //FIXME: when can IllegalStateException be thrown?
+ // JmxAttributeValidationException is wrapped in DynamicWritableWrapper with ValidationException
+ // ValidationException is not thrown until validate or commit is issued
logger.warn("Set phase for {} failed", EditConfigXmlParser.EDIT_CONFIG, e);
final Map<String, String> errorInfo = new HashMap<>();
errorInfo.put(ErrorTag.operation_failed.name(), e.getMessage());
EditConfigExecution editConfigExecution) throws NetconfDocumentedException {
try {
test(configRegistryClient, editConfigExecution, editConfigExecution.getDefaultStrategy());
- } catch (IllegalStateException | JmxAttributeValidationException | ValidationException e) {
+ } catch (IllegalStateException | ValidationException e) {
+ //FIXME: when can IllegalStateException be thrown?
logger.warn("Test phase for {} failed", EditConfigXmlParser.EDIT_CONFIG, e);
final Map<String, String> errorInfo = new HashMap<>();
errorInfo.put(ErrorTag.operation_failed.name(), e.getMessage());
}
private void test(ConfigRegistryClient configRegistryClient, EditConfigExecution execution,
- EditStrategyType editStrategyType) {
+ EditStrategyType editStrategyType) throws ValidationException {
ObjectName taON = transactionProvider.getTestTransaction();
try {
return identityNameToSchemaNode.containsKey(idName);
}
+ // FIXME method never used
public IdentitySchemaNode getIdentitySchemaNode(String idName) {
Preconditions.checkState(identityNameToSchemaNode.containsKey(idName), "No identity under name %s", idName);
return identityNameToSchemaNode.get(idName);
private static final Logger logger = LoggerFactory.getLogger(Activator.class);
private BundleContext context;
- ServiceRegistration osgiRegistration;
+ private ServiceRegistration osgiRegistration;
+ private ConfigRegistryLookupThread configRegistryLookup = null;
@Override
public void start(BundleContext context) throws Exception {
@Override
public void stop(BundleContext context) throws Exception {
+ if (configRegistryLookup != null) {
+ configRegistryLookup.interrupt();
+ }
}
@Override
public synchronized void onYangStoreAdded(YangStoreService yangStoreService) {
- checkState(osgiRegistration == null, "More than one onYangStoreAdded received");
- NetconfOperationServiceFactoryImpl factory = new NetconfOperationServiceFactoryImpl(yangStoreService);
- logger.debug("Registering into OSGi");
- osgiRegistration = context.registerService(new String[]{NetconfOperationServiceFactory.class.getName()}, factory,
- new Hashtable<String, Object>());
+ checkState(configRegistryLookup == null, "More than one onYangStoreAdded received");
+ configRegistryLookup = new ConfigRegistryLookupThread(yangStoreService);
+ configRegistryLookup.start();
}
@Override
public synchronized void onYangStoreRemoved() {
- osgiRegistration.unregister();
+ configRegistryLookup.interrupt();
+ if (osgiRegistration != null) {
+ osgiRegistration.unregister();
+ }
osgiRegistration = null;
+ configRegistryLookup = null;
+ }
+
+ private class ConfigRegistryLookupThread extends Thread {
+ private final YangStoreService yangStoreService;
+
+ private ConfigRegistryLookupThread(YangStoreService yangStoreService) {
+ super("config-registry-lookup");
+ this.yangStoreService = yangStoreService;
+ }
+
+ @Override
+ public void run() {
+ NetconfOperationServiceFactoryImpl factory = new NetconfOperationServiceFactoryImpl(yangStoreService);
+ logger.debug("Registering into OSGi");
+ osgiRegistration = context.registerService(new String[]{NetconfOperationServiceFactory.class.getName()}, factory,
+ new Hashtable<String, Object>());
+ }
}
}
import com.google.common.base.Optional;
import com.google.common.base.Preconditions;
+import org.opendaylight.controller.config.api.ConflictingVersionException;
import org.opendaylight.controller.config.api.ValidationException;
import org.opendaylight.controller.config.api.jmx.CommitStatus;
import org.opendaylight.controller.config.util.ConfigRegistryClient;
import org.opendaylight.controller.config.util.ConfigTransactionClient;
-import org.opendaylight.controller.netconf.api.NetconfDocumentedException;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/**
* Commit and notification send must be atomic
*/
- public synchronized CommitStatus commitTransaction() throws NetconfDocumentedException {
+ public synchronized CommitStatus commitTransaction() throws ValidationException, ConflictingVersionException {
final Optional<ObjectName> maybeTaON = getTransaction();
Preconditions.checkState(maybeTaON.isPresent(), "No transaction found for session " + netconfSessionIdForReporting);
ObjectName taON = maybeTaON.get();
// no clean up: user can reconfigure and recover this transaction
logger.warn("Transaction {} failed on {}", taON, validationException.toString());
throw validationException;
- } catch (Exception e) {
+ } catch (ConflictingVersionException e) {
logger.error("Exception while commit of {}, aborting transaction", taON, e);
// clean up
abortTransaction();
transactionClient.validateConfig();
}
- public void validateTestTransaction(ObjectName taON) {
+ public void validateTestTransaction(ObjectName taON) throws ValidationException {
ConfigTransactionClient transactionClient = configRegistryClient.getConfigTransactionClient(taON);
transactionClient.validateConfig();
}
package org.opendaylight.controller.netconf.confignetconfconnector;
-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.mockito.Mockito.doNothing;
-import static org.mockito.Mockito.doReturn;
-import static org.mockito.Mockito.mock;
-import static org.mockito.Mockito.verify;
-import static org.mockito.Mockito.verifyNoMoreInteractions;
-
-import java.io.FileNotFoundException;
-import java.io.IOException;
-import java.io.InputStream;
-import java.math.BigInteger;
-import java.net.URISyntaxException;
-import java.util.ArrayList;
-import java.util.Arrays;
-import java.util.Collection;
-import java.util.List;
-import java.util.Map;
-import java.util.Set;
-
-import javax.management.InstanceAlreadyExistsException;
-import javax.management.InstanceNotFoundException;
-import javax.management.ObjectName;
-import javax.xml.parsers.ParserConfigurationException;
-
+import com.google.common.base.Optional;
+import com.google.common.base.Preconditions;
+import com.google.common.collect.Lists;
+import com.google.common.collect.Maps;
+import com.google.common.collect.Sets;
import org.apache.commons.lang3.StringUtils;
import org.junit.Before;
import org.junit.Ignore;
import org.junit.matchers.JUnitMatchers;
import org.mockito.Mock;
import org.mockito.MockitoAnnotations;
+import org.opendaylight.controller.config.api.ConflictingVersionException;
+import org.opendaylight.controller.config.api.ValidationException;
import org.opendaylight.controller.config.api.annotations.AbstractServiceInterface;
import org.opendaylight.controller.config.api.annotations.ServiceInterfaceAnnotation;
import org.opendaylight.controller.config.manager.impl.AbstractConfigTest;
import org.w3c.dom.NodeList;
import org.xml.sax.SAXException;
-import com.google.common.base.Optional;
-import com.google.common.base.Preconditions;
-import com.google.common.collect.Lists;
-import com.google.common.collect.Maps;
-import com.google.common.collect.Sets;
+import javax.management.InstanceAlreadyExistsException;
+import javax.management.InstanceNotFoundException;
+import javax.management.ObjectName;
+import javax.xml.parsers.ParserConfigurationException;
+import java.io.FileNotFoundException;
+import java.io.IOException;
+import java.io.InputStream;
+import java.math.BigInteger;
+import java.net.URISyntaxException;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collection;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+
+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.mockito.Mockito.doNothing;
+import static org.mockito.Mockito.doReturn;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.verifyNoMoreInteractions;
public class NetconfMappingTest extends AbstractConfigTest {
transactionProvider = new TransactionProvider(this.configRegistryClient, NETCONF_SESSION_ID);
}
- private ObjectName createModule(final String instanceName) throws InstanceAlreadyExistsException, InstanceNotFoundException, URISyntaxException {
+ private ObjectName createModule(final String instanceName) throws InstanceAlreadyExistsException, InstanceNotFoundException, URISyntaxException, ValidationException, ConflictingVersionException {
final ConfigTransactionJMXClient transaction = this.configRegistryClient.createTransaction();
final ObjectName on = transaction.createModule(this.factory.getImplementationName(), instanceName);
import org.mockito.Mock;
import org.mockito.MockitoAnnotations;
import org.opendaylight.controller.config.api.ServiceReferenceReadableRegistry;
+import org.opendaylight.controller.config.api.ValidationException;
import org.opendaylight.controller.config.util.ConfigRegistryClient;
import org.opendaylight.controller.config.util.ConfigTransactionClient;
import org.opendaylight.controller.config.yang.store.api.YangStoreSnapshot;
}
@Test
- public void test() throws NetconfDocumentedException {
+ public void test() throws NetconfDocumentedException, ValidationException {
EditConfig edit = new EditConfig(yangStoreSnapshot, provider, configRegistry,
ValidateTest.NETCONF_SESSION_ID_FOR_REPORTING);
EditConfigStrategy editStrat = mock(EditConfigStrategy.class);
<parent>
<artifactId>netconf-subsystem</artifactId>
<groupId>org.opendaylight.controller</groupId>
- <version>0.2.4-SNAPSHOT</version>
+ <version>0.2.5-SNAPSHOT</version>
</parent>
<artifactId>config-persister-impl</artifactId>
<name>${project.artifactId}</name>
package org.opendaylight.controller.netconf.persist.impl;
-import java.io.IOException;
-import java.io.InputStream;
-import java.net.InetSocketAddress;
-import java.util.Collections;
-import java.util.HashSet;
-import java.util.LinkedHashMap;
-import java.util.List;
-import java.util.Set;
-import java.util.concurrent.ExecutionException;
-import java.util.concurrent.TimeUnit;
-import java.util.concurrent.TimeoutException;
-
-import javax.annotation.concurrent.Immutable;
-
+import com.google.common.base.Preconditions;
+import io.netty.channel.EventLoopGroup;
import org.opendaylight.controller.config.api.ConflictingVersionException;
import org.opendaylight.controller.config.persist.api.ConfigSnapshotHolder;
import org.opendaylight.controller.netconf.api.NetconfMessage;
import org.w3c.dom.Element;
import org.xml.sax.SAXException;
-import com.google.common.base.Preconditions;
-import io.netty.channel.EventLoopGroup;
+import javax.annotation.concurrent.Immutable;
+import java.io.IOException;
+import java.io.InputStream;
+import java.net.InetSocketAddress;
+import java.util.Collections;
+import java.util.HashSet;
+import java.util.LinkedHashMap;
+import java.util.List;
+import java.util.Set;
+import java.util.concurrent.ExecutionException;
+import java.util.concurrent.TimeUnit;
+import java.util.concurrent.TimeoutException;
@Immutable
public class ConfigPusher {
- private static final Logger logger = LoggerFactory.getLogger(ConfigPusher.class);
+ private static final Logger logger = LoggerFactory.getLogger(ConfigPersisterNotificationHandler.class);
private static final int NETCONF_SEND_ATTEMPT_MS_DELAY = 1000;
private static final int NETCONF_SEND_ATTEMPTS = 20;
}
public ConfigPusher(InetSocketAddress address, EventLoopGroup nettyThreadGroup,
- long maxWaitForCapabilitiesMillis, long connectionTimeoutMillis) {
+ long maxWaitForCapabilitiesMillis, long connectionTimeoutMillis) {
this.address = address;
this.nettyThreadGroup = nettyThreadGroup;
this.maxWaitForCapabilitiesMillis = maxWaitForCapabilitiesMillis;
EditAndCommitResponse editAndCommitResponse = pushLastConfig(configSnapshotHolder, netconfClient);
return new EditAndCommitResponseWithRetries(editAndCommitResponse, retryAttempt);
} catch (ConflictingVersionException e) {
+ logger.debug("Conflicting version detected, will retry after timeout");
lastException = e;
Thread.sleep(1000);
} catch (RuntimeException e) {
logger.trace("Session id received from netconf server: {}", netconfClient.getClientSession());
return netconfClient;
}
- logger.debug("Polling hello from netconf, attempt {}, capabilities {}", attempt, latestCapabilities);
+ Set<String> allNotFound = computeNotFoundCapabilities(expectedCaps, latestCapabilities);
+ logger.debug("Netconf server did not provide required capabilities. Attempt {}. " +
+ "Expected but not found: {}, all expected {}, current {}",
+ attempt, allNotFound, expectedCaps, latestCapabilities);
Util.closeClientAndDispatcher(netconfClient);
Thread.sleep(delayMillis);
}
logger.error("Could not connect to the server in {} ms", maxWaitForCapabilitiesMillis);
throw new RuntimeException("Could not connect to netconf server");
}
- Set<String> allNotFound = new HashSet<>(expectedCaps);
- allNotFound.removeAll(latestCapabilities);
+ Set<String> allNotFound = computeNotFoundCapabilities(expectedCaps, latestCapabilities);
logger.error("Netconf server did not provide required capabilities. Expected but not found: {}, all expected {}, current {}",
allNotFound, expectedCaps, latestCapabilities);
throw new RuntimeException("Netconf server did not provide required capabilities. Expected but not found:" + allNotFound);
}
+ private static Set<String> computeNotFoundCapabilities(Set<String> expectedCaps, Set<String> latestCapabilities) {
+ Set<String> allNotFound = new HashSet<>(expectedCaps);
+ allNotFound.removeAll(latestCapabilities);
+ return allNotFound;
+ }
+
/**
* Sends two RPCs to the netconf server: edit-config and commit.
}
- private static NetconfMessage sendRequestGetResponseCheckIsOK(NetconfMessage request, NetconfClient netconfClient) throws IOException {
+ private static NetconfMessage sendRequestGetResponseCheckIsOK(NetconfMessage request, NetconfClient netconfClient)
+ throws ConflictingVersionException, IOException {
try {
NetconfMessage netconfMessage = netconfClient.sendMessage(request, NETCONF_SEND_ATTEMPTS, NETCONF_SEND_ATTEMPT_MS_DELAY);
NetconfUtil.checkIsMessageOk(netconfMessage);
return netconfMessage;
- } catch (RuntimeException | ExecutionException | InterruptedException | TimeoutException e) {
+ }catch(ConflictingVersionException e) {
+ logger.trace("conflicting version detected: {}", e.toString());
+ throw e;
+ } catch (RuntimeException | ExecutionException | InterruptedException | TimeoutException e) { // TODO: change NetconfClient#sendMessage to throw checked exceptions
logger.debug("Error while executing netconf transaction {} to {}", request, netconfClient, e);
throw new IOException("Failed to execute netconf transaction", e);
}
}
+
// load editConfig.xml template, populate /rpc/edit-config/config with parameter
private static NetconfMessage createEditConfigMessage(Element dataElement) {
String editConfigResourcePath = "/netconfOp/editConfig.xml";
<parent>
<artifactId>netconf-subsystem</artifactId>
<groupId>org.opendaylight.controller</groupId>
- <version>0.2.4-SNAPSHOT</version>
+ <version>0.2.5-SNAPSHOT</version>
</parent>
<modelVersion>4.0.0</modelVersion>
<artifactId>ietf-netconf-monitoring-extension</artifactId>
<parent>
<artifactId>netconf-subsystem</artifactId>
<groupId>org.opendaylight.controller</groupId>
- <version>0.2.4-SNAPSHOT</version>
+ <version>0.2.5-SNAPSHOT</version>
</parent>
<modelVersion>4.0.0</modelVersion>
<artifactId>ietf-netconf-monitoring</artifactId>
<parent>
<artifactId>netconf-subsystem</artifactId>
<groupId>org.opendaylight.controller</groupId>
- <version>0.2.4-SNAPSHOT</version>
+ <version>0.2.5-SNAPSHOT</version>
</parent>
<modelVersion>4.0.0</modelVersion>
<artifactId>netconf-api</artifactId>
</Private-Package>
<Import-Package>
javax.management,
+ org.opendaylight.controller.config.api,
org.opendaylight.controller.config.api.jmx,
org.opendaylight.protocol.framework,
io.netty.channel,
package org.opendaylight.controller.netconf.api;
+import org.opendaylight.controller.config.api.ConflictingVersionException;
+import org.opendaylight.controller.config.api.ValidationException;
+
import java.util.Collections;
+import java.util.HashMap;
import java.util.Map;
/**
private static final long serialVersionUID = 1L;
+
+
public enum ErrorType {
transport, rpc, protocol, application;
this.errorInfo = errorInfo;
}
+ public static NetconfDocumentedException wrap(ValidationException e) throws NetconfDocumentedException {
+ final Map<String, String> errorInfo = new HashMap<>();
+ errorInfo.put(ErrorTag.operation_failed.name(), "Validation failed");
+ throw new NetconfDocumentedException(e.getMessage(), e, ErrorType.application, ErrorTag.operation_failed,
+ ErrorSeverity.error, errorInfo);
+ }
+
+ public static NetconfDocumentedException wrap(ConflictingVersionException e) throws NetconfDocumentedException {
+ final Map<String, String> errorInfo = new HashMap<>();
+ errorInfo.put(ErrorTag.operation_failed.name(), "Optimistic lock failed");
+ throw new NetconfDocumentedException(e.getMessage(), e, ErrorType.application, ErrorTag.operation_failed,
+ ErrorSeverity.error, errorInfo);
+ }
+
public ErrorType getErrorType() {
return this.errorType;
}
<parent>
<artifactId>netconf-subsystem</artifactId>
<groupId>org.opendaylight.controller</groupId>
- <version>0.2.4-SNAPSHOT</version>
+ <version>0.2.5-SNAPSHOT</version>
</parent>
<artifactId>netconf-client</artifactId>
<name>${project.artifactId}</name>
<parent>
<artifactId>netconf-subsystem</artifactId>
<groupId>org.opendaylight.controller</groupId>
- <version>0.2.4-SNAPSHOT</version>
+ <version>0.2.5-SNAPSHOT</version>
</parent>
<modelVersion>4.0.0</modelVersion>
<artifactId>netconf-impl</artifactId>
<parent>
<artifactId>netconf-subsystem</artifactId>
<groupId>org.opendaylight.controller</groupId>
- <version>0.2.4-SNAPSHOT</version>
+ <version>0.2.5-SNAPSHOT</version>
</parent>
<artifactId>netconf-it</artifactId>
<artifactId>yang-store-api</artifactId>
<scope>test</scope>
</dependency>
- <dependency>
- <groupId>${project.groupId}</groupId>
- <artifactId>yang-test</artifactId>
- <scope>test</scope>
- </dependency>
<dependency>
<groupId>${project.groupId}</groupId>
<artifactId>netconf-api</artifactId>
<artifactId>netconf-monitoring</artifactId>
<scope>test</scope>
</dependency>
+ <dependency>
+ <groupId>${project.groupId}</groupId>
+ <artifactId>sal-binding-it</artifactId>
+ <version>${mdsal.version}</version>
+ <scope>test</scope>
+ </dependency>
<dependency>
<groupId>${project.groupId}</groupId>
<artifactId>netconf-mapping-api</artifactId>
<scope>test</scope>
<type>test-jar</type>
</dependency>
+ <dependency>
+ <groupId>org.opendaylight.controller</groupId>
+ <artifactId>yang-test</artifactId>
+ <version>${config.version}</version>
+ <scope>test</scope>
+ </dependency>
<dependency>
<groupId>${project.groupId}</groupId>
<artifactId>yang-store-impl</artifactId>
</execution>
</executions>
</plugin>
+ <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>
</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.netconf.it.pax;
+
+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.systemProperty;
+
+import javax.inject.Inject;
+import javax.xml.parsers.ParserConfigurationException;
+
+import com.google.common.base.Preconditions;
+import io.netty.channel.nio.NioEventLoopGroup;
+import org.junit.Assert;
+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.NetconfClient;
+import org.opendaylight.controller.netconf.client.NetconfClientDispatcher;
+import org.opendaylight.controller.netconf.util.xml.XmlUtil;
+import org.opendaylight.controller.sal.binding.api.BindingAwareBroker;
+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.w3c.dom.Document;
+import org.xml.sax.SAXException;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.net.InetSocketAddress;
+import java.util.concurrent.ExecutionException;
+import java.util.concurrent.TimeoutException;
+
+@RunWith(PaxExam.class)
+public class IdentityRefNetconfTest {
+
+ public static final int CLIENT_CONNECTION_TIMEOUT_MILLIS = 5000;
+
+ // Wait for controller to start
+ @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"),
+
+ testingModules(),
+ loggingModules(),
+ mdSalCoreBundles(),
+ bindingAwareSalBundles(), configMinumumBundles(), baseModelBundles(), flowCapableModelBundles(),
+ junitAndMockitoBundles());
+ }
+
+ 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());
+ }
+
+ 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");
+
+ NioEventLoopGroup nettyThreadgroup = new NioEventLoopGroup();
+ NetconfClientDispatcher clientDispatcher = new NetconfClientDispatcher(nettyThreadgroup, nettyThreadgroup,
+ CLIENT_CONNECTION_TIMEOUT_MILLIS);
+
+ NetconfMessage edit = xmlFileToNetconfMessage("netconfMessages/editConfig_identities.xml");
+ NetconfMessage commit = xmlFileToNetconfMessage("netconfMessages/commit.xml");
+ NetconfMessage getConfig = xmlFileToNetconfMessage("netconfMessages/getConfig.xml");
+
+ try (NetconfClient netconfClient = new NetconfClient("client", tcpAddress, CLIENT_CONNECTION_TIMEOUT_MILLIS, clientDispatcher)) {
+ sendMessage(edit, netconfClient);
+ sendMessage(commit, netconfClient);
+ sendMessage(getConfig, netconfClient, "id-test",
+ "<afi xmlns:prefix=\"urn:opendaylight:params:xml:ns:yang:controller:config:test:types\">prefix:test-identity1</afi>",
+ "<afi xmlns:prefix=\"urn:opendaylight:params:xml:ns:yang:controller:config:test:types\">prefix:test-identity2</afi>",
+ "<safi xmlns:prefix=\"urn:opendaylight:params:xml:ns:yang:controller:config:test:types\">prefix:test-identity2</safi>",
+ "<safi xmlns:prefix=\"urn:opendaylight:params:xml:ns:yang:controller:config:test:types\">prefix:test-identity1</safi>");
+ }
+
+ clientDispatcher.close();
+ }
+
+ private void sendMessage(NetconfMessage edit, NetconfClient 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 new NetconfMessage(xmlFileToDocument(fileName));
+ }
+
+ public static Document xmlFileToDocument(final String fileName) throws IOException, SAXException,
+ ParserConfigurationException {
+ // TODO xml messages from netconf-util test-jar cannot be loaded here(in OSGi), since test jar is not a bundle
+ try (InputStream resourceAsStream = IdentityRefNetconfTest.class.getClassLoader().getResourceAsStream(fileName)) {
+ Preconditions.checkNotNull(resourceAsStream);
+ final Document doc = XmlUtil.readXmlToDocument(resourceAsStream);
+ return doc;
+ }
+ }
+}
--- /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>
+ <type xmlns:prefix="urn:opendaylight:params:xml:ns:yang:controller:test:impl">prefix:impl-identity-test</type>
+ <name>id-test</name>
+ <identities-container xmlns="urn:opendaylight:params:xml:ns:yang:controller:test:impl">
+ <afi xmlns:prefix="urn:opendaylight:params:xml:ns:yang:controller:config:test:types">prefix:test-identity2</afi>
+ </identities-container>
+ <identities xmlns="urn:opendaylight:params:xml:ns:yang:controller:test:impl">
+ <safi xmlns:prefix="urn:opendaylight:params:xml:ns:yang:controller:config:test:types">prefix:test-identity2</safi>
+ <afi xmlns:prefix="urn:opendaylight:params:xml:ns:yang:controller:config:test:types">prefix:test-identity1</afi>
+ </identities>
+ <identities xmlns="urn:opendaylight:params:xml:ns:yang:controller:test:impl">
+ <safi xmlns:prefix="urn:opendaylight:params:xml:ns:yang:controller:config:test:types">prefix:test-identity1</safi>
+ <afi xmlns:prefix="urn:opendaylight:params:xml:ns:yang:controller:config:test:types">prefix:test-identity2</afi>
+ </identities>
+ <afi xmlns="urn:opendaylight:params:xml:ns:yang:controller:test:impl" xmlns:prefix="urn:opendaylight:params:xml:ns:yang:controller:config:test:types">prefix:test-identity1</afi>
+ </module>
+ <module>
+ <type xmlns:prefix="urn:opendaylight:params:xml:ns:yang:controller:md:sal:binding:impl">prefix:binding-broker-impl</type>
+ <name>binding-broker-impl</name>
+ <notification-service xmlns="urn:opendaylight:params:xml:ns:yang:controller:md:sal:binding:impl">
+ <type xmlns:prefix="urn:opendaylight:params:xml:ns:yang:controller:md:sal:binding">prefix:binding-notification-service</type>
+ <name>ref_binding-notification-broker</name>
+ </notification-service>
+ <data-broker xmlns="urn:opendaylight:params:xml:ns:yang:controller:md:sal:binding:impl">
+ <type xmlns:prefix="urn:opendaylight:params:xml:ns:yang:controller:md:sal:binding">prefix:binding-data-broker</type>
+ <name>ref_binding-data-broker</name>
+ </data-broker>
+ </module>
+ <module>
+ <type xmlns:prefix="urn:opendaylight:params:xml:ns:yang:controller:md:sal:binding:impl">prefix:runtime-generated-mapping</type>
+ <name>runtime-mapping-singleton</name>
+ </module>
+ <module>
+ <type xmlns:prefix="urn:opendaylight:params:xml:ns:yang:controller:md:sal:binding:impl">prefix:binding-notification-broker</type>
+ <name>binding-notification-broker</name>
+ </module>
+ <module>
+ <type xmlns:prefix="urn:opendaylight:params:xml:ns:yang:controller:md:sal:binding:impl">prefix:binding-data-broker</type>
+ <name>binding-data-broker</name>
+ <dom-broker xmlns="urn:opendaylight:params:xml:ns:yang:controller:md:sal:binding:impl">
+ <type xmlns:prefix="urn:opendaylight:params:xml:ns:yang:controller:md:sal:dom">prefix:dom-broker-osgi-registry</type>
+ <name>ref_dom-broker</name>
+ </dom-broker>
+ <mapping-service xmlns="urn:opendaylight:params:xml:ns:yang:controller:md:sal:binding:impl">
+ <type xmlns:prefix="urn:opendaylight:params:xml:ns:yang:controller:md:sal:binding:impl">prefix:binding-dom-mapping-service</type>
+ <name>ref_runtime-mapping-singleton</name>
+ </mapping-service>
+ </module>
+ <module>
+ <type xmlns:prefix="urn:opendaylight:params:xml:ns:yang:controller:logback:config">prefix:logback</type>
+ <name>singleton</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>
+ <type xmlns:prefix="urn:opendaylight:params:xml:ns:yang:controller:md:sal:dom:impl">prefix:schema-service-singleton</type>
+ <name>yang-schema-service</name>
+ </module>
+ <module>
+ <type xmlns:prefix="urn:opendaylight:params:xml:ns:yang:controller:md:sal:dom:impl">prefix:hash-map-data-store</type>
+ <name>hash-map-data-store</name>
+ </module>
+ <module>
+ <type xmlns:prefix="urn:opendaylight:params:xml:ns:yang:controller:md:sal:dom:impl">prefix:dom-broker-impl</type>
+ <name>dom-broker</name>
+ <data-store xmlns="urn:opendaylight:params:xml:ns:yang:controller:md:sal:dom:impl">
+ <type xmlns:prefix="urn:opendaylight:params:xml:ns:yang:controller:md:sal:dom">prefix:dom-data-store</type>
+ <name>ref_hash-map-data-store</name>
+ </data-store>
+ </module>
+ </modules>
+ <services xmlns="urn:opendaylight:params:xml:ns:yang:controller:config">
+ <service>
+ <type xmlns:prefix="urn:opendaylight:params:xml:ns:yang:controller:md:sal:dom">prefix:schema-service</type>
+ <instance>
+ <name>ref_yang-schema-service</name>
+ <provider>/modules/module[type='schema-service-singleton'][name='yang-schema-service']</provider>
+ </instance>
+ </service>
+ <service>
+ <type xmlns:prefix="urn:opendaylight:params:xml:ns:yang:controller:md:sal:dom">prefix:dom-data-store</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>
+ <type xmlns:prefix="urn:opendaylight:params:xml:ns:yang:controller:md:sal:dom">prefix:dom-broker-osgi-registry</type>
+ <instance>
+ <name>ref_dom-broker</name>
+ <provider>/modules/module[type='dom-broker-impl'][name='dom-broker']</provider>
+ </instance>
+ </service>
+ <service>
+ <type xmlns:prefix="urn:opendaylight:params:xml:ns:yang:controller:test">prefix:testing</type>
+ <instance>
+ <name>ref_id-test</name>
+ <provider>/modules/module[type='impl-identity-test'][name='id-test']</provider>
+ </instance>
+ </service>
+ <service>
+ <type xmlns:prefix="urn:opendaylight:params:xml:ns:yang:controller:md:sal:binding:impl">prefix:binding-dom-mapping-service</type>
+ <instance>
+ <name>ref_runtime-mapping-singleton</name>
+ <provider>/modules/module[type='runtime-generated-mapping'][name='runtime-mapping-singleton']</provider>
+ </instance>
+ </service>
+ <service>
+ <type xmlns:prefix="urn:opendaylight:params:xml:ns:yang:controller:md:sal:binding">prefix:binding-data-consumer-broker</type>
+ <instance>
+ <name>ref_binding-data-broker</name>
+ <provider>/modules/module[type='binding-data-broker'][name='binding-data-broker']</provider>
+ </instance>
+ </service>
+ <service>
+ <type xmlns:prefix="urn:opendaylight:params:xml:ns:yang:controller:md:sal:binding">prefix:binding-rpc-registry</type>
+ <instance>
+ <name>ref_binding-broker-impl</name>
+ <provider>/modules/module[type='binding-broker-impl'][name='binding-broker-impl']</provider>
+ </instance>
+ </service>
+ <service>
+ <type xmlns:prefix="urn:opendaylight:params:xml:ns:yang:controller:md:sal:binding">prefix:binding-notification-service</type>
+ <instance>
+ <name>ref_binding-notification-broker</name>
+ <provider>/modules/module[type='binding-notification-broker'][name='binding-notification-broker']</provider>
+ </instance>
+ </service>
+ <service>
+ <type xmlns:prefix="urn:opendaylight:params:xml:ns:yang:controller:md:sal:binding">prefix:binding-broker-osgi-registry</type>
+ <instance>
+ <name>ref_binding-broker-impl</name>
+ <provider>/modules/module[type='binding-broker-impl'][name='binding-broker-impl']</provider>
+ </instance>
+ </service>
+ <service>
+ <type xmlns:prefix="urn:opendaylight:params:xml:ns:yang:controller:md:sal:binding">prefix:binding-notification-subscription-service</type>
+ <instance>
+ <name>ref_binding-notification-broker</name>
+ <provider>/modules/module[type='binding-notification-broker'][name='binding-notification-broker']</provider>
+ </instance>
+ </service>
+ <service>
+ <type xmlns:prefix="urn:opendaylight:params:xml:ns:yang:controller:md:sal:binding">prefix:binding-data-broker</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 message-id="a" a="64" xmlns="urn:ietf:params:xml:ns:netconf:base:1.0">
+<edit-config>
+ <target>
+ <candidate/>
+ </target>
+ <test-option>
+ set
+ </test-option>
+ <default-operation>merge</default-operation>
+ <config>
+ <modules xmlns="urn:opendaylight:params:xml:ns:yang:controller:config">
+ <module>
+ <type xmlns:test-impl="urn:opendaylight:params:xml:ns:yang:controller:test:impl">
+ test-impl:impl-identity-test
+ </type>
+ <name>id-test</name>
+ <identities>
+ <afi xmlns:prefix="urn:opendaylight:params:xml:ns:yang:controller:config:test:types">prefix:test-identity1</afi>
+ <safi xmlns:prefix="urn:opendaylight:params:xml:ns:yang:controller:config:test:types">prefix:test-identity2</safi>
+ </identities>
+ <identities>
+ <afi xmlns:prefix="urn:opendaylight:params:xml:ns:yang:controller:config:test:types">prefix:test-identity2</afi>
+ <safi xmlns:prefix="urn:opendaylight:params:xml:ns:yang:controller:config:test:types">prefix:test-identity1</safi>
+ </identities>
+ <identities-container>
+ <afi xmlns:prefix="urn:opendaylight:params:xml:ns:yang:controller:config:test:types">prefix:test-identity2</afi>
+ </identities-container>
+ <afi xmlns:prefix="urn:opendaylight:params:xml:ns:yang:controller:config:test:types">prefix:test-identity1</afi>
+ </module>
+ </modules>
+
+ <services xmlns="urn:opendaylight:params:xml:ns:yang:controller:config">
+
+ </services>
+ </config>
+</edit-config>
+</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>
<parent>
<artifactId>netconf-subsystem</artifactId>
<groupId>org.opendaylight.controller</groupId>
- <version>0.2.4-SNAPSHOT</version>
+ <version>0.2.5-SNAPSHOT</version>
</parent>
<modelVersion>4.0.0</modelVersion>
<artifactId>netconf-mapping-api</artifactId>
<parent>
<artifactId>netconf-subsystem</artifactId>
<groupId>org.opendaylight.controller</groupId>
- <version>0.2.4-SNAPSHOT</version>
+ <version>0.2.5-SNAPSHOT</version>
</parent>
<modelVersion>4.0.0</modelVersion>
<artifactId>netconf-monitoring</artifactId>
<parent>
<artifactId>netconf-subsystem</artifactId>
<groupId>org.opendaylight.controller</groupId>
- <version>0.2.4-SNAPSHOT</version>
+ <version>0.2.5-SNAPSHOT</version>
<relativePath>../</relativePath>
</parent>
<modelVersion>4.0.0</modelVersion>
<parent>
<artifactId>netconf-subsystem</artifactId>
<groupId>org.opendaylight.controller</groupId>
- <version>0.2.4-SNAPSHOT</version>
+ <version>0.2.5-SNAPSHOT</version>
</parent>
<artifactId>netconf-util</artifactId>
<name>${project.artifactId}</name>
<relativePath>../commons/opendaylight</relativePath>
</parent>
- <version>0.2.4-SNAPSHOT</version>
+ <version>0.2.5-SNAPSHOT</version>
<artifactId>netconf-subsystem</artifactId>
<packaging>pom</packaging>
<name>${project.artifactId}</name>
<maven.bundle.version>2.4.0</maven.bundle.version>
<slf4j.version>1.7.2</slf4j.version>
<netconf.netty.version>4.0.10.Final</netconf.netty.version>
- <netconf.version>0.2.4-SNAPSHOT</netconf.version>
- <config.version>0.2.4-SNAPSHOT</config.version>
<salGeneratorPath>${project.build.directory}/generated-sources/sal</salGeneratorPath>
</properties>