<artifactId>junit</artifactId>
</dependency>
<!-- Add Pax Exam -->
- <dependency>
- <groupId>org.ops4j.pax.exam</groupId>
- <artifactId>pax-exam-container-native</artifactId>
- <scope>test</scope>
- </dependency>
<dependency>
<groupId>org.ops4j.pax.exam</groupId>
<artifactId>pax-exam-junit4</artifactId>
<includeTestSourceDirectory>true</includeTestSourceDirectory>
<sourceDirectory>${project.basedir}</sourceDirectory>
<includes>**\/*.java,**\/*.xml,**\/*.ini,**\/*.sh,**\/*.bat</includes>
- <excludes>**\/target\/,**\/bin\/</excludes>
+ <excludes>**\/target\/,**\/bin\/,**\/target-ide\/</excludes>
</configuration>
</plugin>
<plugin>
* Provides functionality for working with configuration registry - mainly
* creating and committing config transactions.
*/
-public interface ConfigRegistry extends LookupRegistry {
+public interface ConfigRegistry extends LookupRegistry, ServiceReferenceReadableRegistry {
/**
* Only well-known ObjectName in configuration system, under which
*/
boolean isHealthy();
+ /**
+ * @return module factory names available in the system
+ */
Set<String> getAvailableModuleNames();
+
+
/**
* Find all runtime beans
*
/**
* Represents functionality provided by configuration transaction.
*/
-public interface ConfigTransactionController extends LookupRegistry {
+public interface ConfigTransactionController extends LookupRegistry, ServiceReferenceWritableRegistry {
/**
* Create new configuration bean.
*/
String getTransactionName();
+ /**
+ * @return all known module factory names as reported by {@link org.opendaylight.controller.config.spi.ModuleFactory#getImplementationName()}
+ */
Set<String> getAvailableModuleNames();
}
*/
package org.opendaylight.controller.config.api;
-import java.util.Set;
-
import javax.management.InstanceNotFoundException;
import javax.management.ObjectName;
+import java.util.Set;
public interface LookupRegistry {
ObjectName lookupConfigBean(String moduleName, String instanceName)
throws InstanceNotFoundException;
+ /**
+ * Check that object name corresponds with existing module.
+ *
+ * @throws InstanceNotFoundException
+ * if search did not find exactly one instance
+ */
+ void checkConfigBeanExists(ObjectName objectName) throws InstanceNotFoundException;
+
+
+ /**
+ * @return qNames of all ModuleFactory instances in the system
+ */
+ Set<String> getAvailableModuleFactoryQNames();
+
}
--- /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.api;
+
+import javax.management.InstanceNotFoundException;
+import javax.management.ObjectName;
+import java.util.Map;
+import java.util.Set;
+
+public interface ServiceReferenceReadableRegistry {
+
+ /**
+ * Lookup object name by fully qualified service interface name and service reference name.
+ * @param serviceInterfaceQName service interface name
+ * @param refName service reference name supplied in
+ * {@link org.opendaylight.controller.config.api.ConfigTransactionController#saveServiceReference(String, String, javax.management.ObjectName)}
+ * @throws java.lang.IllegalArgumentException if module not found
+ */
+ ObjectName lookupConfigBeanByServiceInterfaceName(String serviceInterfaceQName, String refName);
+
+ /**
+ * Get mapping of services to reference names and module object names.
+ */
+ Map<String /* serviceInterfaceQName */, Map<String/* refName */, ObjectName>> getServiceMapping();
+
+ /**
+ * Get current mapping between reference names and module object names for given service interface name.
+ * @param serviceInterfaceQName service interface name
+ * @throws IllegalArgumentException if there is a mismatch between serviceInterfaceName and objectName
+ */
+ Map<String /* refName */, ObjectName> lookupServiceReferencesByServiceInterfaceName(String serviceInterfaceQName);
+
+ /**
+ * Find all available service interface names of a module.
+ * @param objectName module object name
+ * @throws InstanceNotFoundException if search did not find exactly one instance
+ */
+ Set<String> lookupServiceInterfaceNames(ObjectName objectName) throws InstanceNotFoundException;
+
+ /**
+ * @param namespace service interface namespace
+ * @param localName service interface local name
+ * @return fully qualified name needed by all other service reference mapping methods.
+ * @throws java.lang.IllegalArgumentException if namespace or localName is not found
+ */
+ String getServiceInterfaceName(String namespace, String localName);
+
+ /**
+ * @return ObjectName with type=Service that was created using
+ * {@link org.opendaylight.controller.config.api.ServiceReferenceWritableRegistry#saveServiceReference(String, String,
+ * javax.management.ObjectName)}
+ */
+ ObjectName getServiceReference(String serviceInterfaceQName, String refName) throws InstanceNotFoundException;
+
+ void checkServiceReferenceExists(ObjectName objectName) throws InstanceNotFoundException;
+
+}
--- /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.api;
+
+import javax.management.InstanceNotFoundException;
+import javax.management.ObjectName;
+
+public interface ServiceReferenceWritableRegistry extends ServiceReferenceReadableRegistry {
+ /**
+ * Create or update reference name to objectName. Reference name is unique per service interface name.
+ * @return created or updated object name containing service name and reference name
+ * @throws IllegalArgumentException if there is a mismatch between serviceInterfaceName and objectName
+ * @throws InstanceNotFoundException if search did not find exactly one instance
+ */
+ ObjectName saveServiceReference(String serviceInterfaceName, String refName, ObjectName moduleON) throws InstanceNotFoundException;
+
+ /**
+ * Remove service reference.
+ * @return true iif removed
+ * @throws IllegalArgumentException if service interface name is not advertised by any module
+ */
+ void removeServiceReference(String serviceInterfaceName, String refName) throws InstanceNotFoundException;
+
+ /**
+ * Remove all service references.
+ */
+ void removeAllServiceReferences();
+
+ /**
+ * Remove all service references attached to given module.
+ * @return true iif at least one reference was removed
+ */
+ boolean removeServiceReferences(ObjectName objectName) throws InstanceNotFoundException;
+}
public @interface ServiceInterfaceAnnotation {
/**
- * Specifies human readable name of this service. Each service name should
- * be globally unique. Should not contain spaces.
+ * Fully qualified name of a service that must be globally unique.
+ * When generating service interfaces from yang, this will be QName of
+ * identity extending service-type.
*/
String value();
* is called.
*/
Class<?> osgiRegistrationType();
+
+ /**
+ * Get namespace of {@link #value()}
+ */
+ String namespace();
+
+ /**
+ * Get revision of {@link #value()}
+ */
+ String revision();
+
+ /**
+ * Get local name of {@link #value()}
+ */
+ String localName();
}
*/
package org.opendaylight.controller.config.api.jmx;
+import org.opendaylight.controller.config.api.ModuleIdentifier;
+import org.opendaylight.controller.config.api.jmx.constants.ConfigRegistryConstants;
+
+import javax.annotation.concurrent.ThreadSafe;
+import javax.management.ObjectName;
import java.util.Arrays;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Map.Entry;
import java.util.Set;
-import javax.annotation.concurrent.ThreadSafe;
-import javax.management.ObjectName;
-
-import org.opendaylight.controller.config.api.ModuleIdentifier;
-import org.opendaylight.controller.config.api.jmx.constants.ConfigRegistryConstants;
-
/**
* Provides ObjectName creation. Each created ObjectName consists of domain that
* is defined as {@link #ON_DOMAIN} and at least one key-value pair. The only
* mandatory property is {@link #TYPE_KEY}. All transaction related mbeans have
* {@link #TRANSACTION_NAME_KEY} property set.
- *
*/
@ThreadSafe
public class ObjectNameUtil {
public static final String ON_DOMAIN = ConfigRegistryConstants.ON_DOMAIN;
public static final String MODULE_FACTORY_NAME_KEY = "moduleFactoryName";
+ public static final String SERVICE_QNAME_KEY = "serviceQName";
public static final String INSTANCE_NAME_KEY = "instanceName";
public static final String TYPE_KEY = ConfigRegistryConstants.TYPE_KEY;
public static final String TYPE_CONFIG_REGISTRY = ConfigRegistryConstants.TYPE_CONFIG_REGISTRY;
public static final String TYPE_CONFIG_TRANSACTION = "ConfigTransaction";
public static final String TYPE_MODULE = "Module";
+ public static final String TYPE_SERVICE_REFERENCE = "ServiceReference";
public static final String TYPE_RUNTIME_BEAN = "RuntimeBean";
-
public static final String TRANSACTION_NAME_KEY = "TransactionName";
+ public static final String REF_NAME_KEY = "RefName";
+ private static final String REPLACED_QUOTATION_MARK = "\\?";
public static ObjectName createON(String on) {
try {
return ConfigRegistryConstants.createON(name, key, value);
}
- public static ObjectName createON(String name, Map<String, String> attribs) {
+ public static ObjectName createON(String domain, Map<String, String> attribs) {
Hashtable<String, String> table = new Hashtable<>(attribs);
try {
- return new ObjectName(name, table);
+ return new ObjectName(domain, table);
} catch (Exception e) {
throw new RuntimeException(e);
}
}
public static ObjectName createTransactionModuleON(String transactionName,
- ModuleIdentifier moduleIdentifier) {
+ ModuleIdentifier moduleIdentifier) {
return createTransactionModuleON(transactionName,
moduleIdentifier.getFactoryName(),
moduleIdentifier.getInstanceName());
}
public static ObjectName createTransactionModuleON(String transactionName,
- String moduleName, String instanceName) {
- Map<String, String> onParams = createModuleON(moduleName, instanceName);
+ String moduleName, String instanceName) {
+ Map<String, String> onParams = createModuleMap(moduleName, instanceName);
onParams.put(TRANSACTION_NAME_KEY, transactionName);
return createON(ON_DOMAIN, onParams);
}
public static ObjectName createTransactionModuleON(String transactionName,
- ObjectName on) {
+ ObjectName on) {
return createTransactionModuleON(transactionName, getFactoryName(on),
getInstanceName(on));
}
moduleIdentifier.getInstanceName());
}
+ public static ObjectName createReadOnlyServiceON(String serviceQName, String refName) {
+ Map<String, String> onParams = createServiceMap(serviceQName, refName);
+ return createON(ON_DOMAIN, onParams);
+ }
+
+ public static ObjectName createTransactionServiceON(String transactionName, String serviceQName, String refName) {
+ Map<String, String> onParams = createServiceON(transactionName, serviceQName, refName);
+ return createON(ON_DOMAIN, onParams);
+ }
+
+ 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;
+ }
+
+ // ObjectName supports quotation and ignores tokens like =, but fails to ignore ? sign.
+ // It must be replaced with another character that hopefully does not collide
+ // with actual value.
+ private static String unquoteAndUnescape(ObjectName objectName, String quoted) {
+ if (quoted == null) {
+ throw new IllegalArgumentException("Cannot find " + SERVICE_QNAME_KEY + " in " + objectName);
+ }
+ if (quoted.startsWith("\"") == false || quoted.endsWith("\"") == false) {
+ throw new IllegalArgumentException("Quotes not found in " + objectName);
+ }
+ String substring = quoted.substring(1);
+ substring = substring.substring(0, substring.length() - 1);
+ substring = substring.replace(REPLACED_QUOTATION_MARK, "?");
+ return substring;
+ }
+
+ private static String quoteAndEscapeValue(String serviceQName) {
+ return "\"" + serviceQName.replace("?", REPLACED_QUOTATION_MARK) + "\"";
+ }
+
+ public static String getReferenceName(ObjectName objectName) {
+ checkType(objectName, TYPE_SERVICE_REFERENCE);
+ return objectName.getKeyProperty(REF_NAME_KEY);
+ }
+
+ private static Map<String, String> createServiceON(String transactionName, String serviceQName,
+ String refName) {
+ Map<String, String> result = new HashMap<>(createServiceMap(serviceQName, refName));
+ result.put(TRANSACTION_NAME_KEY, transactionName);
+ return result;
+ }
+
+ private static Map<String, String> createServiceMap(String serviceQName,
+ String refName) {
+ Map<String, String> onParams = new HashMap<>();
+ onParams.put(TYPE_KEY, TYPE_SERVICE_REFERENCE);
+ onParams.put(SERVICE_QNAME_KEY, quoteAndEscapeValue(serviceQName));
+ onParams.put(REF_NAME_KEY, refName);
+ return onParams;
+ }
+
+
public static ObjectName createReadOnlyModuleON(String moduleName,
- String instanceName) {
- Map<String, String> onParams = createModuleON(moduleName, instanceName);
+ String instanceName) {
+ Map<String, String> onParams = createModuleMap(moduleName, instanceName);
return createON(ON_DOMAIN, onParams);
}
- private static Map<String, String> createModuleON(String moduleName,
- String instanceName) {
+ private static Map<String, String> createModuleMap(String moduleName,
+ String instanceName) {
Map<String, String> onParams = new HashMap<>();
onParams.put(TYPE_KEY, TYPE_MODULE);
onParams.put(MODULE_FACTORY_NAME_KEY, moduleName);
}
public static String getFactoryName(ObjectName objectName) {
+ checkTypeOneOf(objectName, TYPE_MODULE, TYPE_RUNTIME_BEAN);
return objectName.getKeyProperty(MODULE_FACTORY_NAME_KEY);
}
public static String getInstanceName(ObjectName objectName) {
+ checkTypeOneOf(objectName, TYPE_MODULE, TYPE_RUNTIME_BEAN);
return objectName.getKeyProperty(INSTANCE_NAME_KEY);
}
return objectName.getKeyProperty(TRANSACTION_NAME_KEY);
}
- public static ObjectName withoutTransactionName(ObjectName on) {
- if (getTransactionName(on) == null) {
+ /**
+ * Sanitize on: keep only mandatory attributes of module + metadata.
+ */
+ public static ObjectName withoutTransactionName(ObjectName inputON) {
+ checkTypeOneOf(inputON, TYPE_MODULE, TYPE_SERVICE_REFERENCE);
+ if (getTransactionName(inputON) == null) {
throw new IllegalArgumentException(
- "Expected ObjectName with transaction:" + on);
+ "Expected ObjectName with transaction:" + inputON);
}
- if (ON_DOMAIN.equals(on.getDomain()) == false) {
+ if (ON_DOMAIN.equals(inputON.getDomain()) == false) {
throw new IllegalArgumentException("Expected different domain: "
- + on);
+ + inputON);
+ }
+ Map<String, String> outputProperties;
+ if (inputON.getKeyProperty(TYPE_KEY).equals(TYPE_MODULE)) {
+ String moduleName = getFactoryName(inputON);
+ String instanceName = getInstanceName(inputON);
+ outputProperties = new HashMap<>(createModuleMap(moduleName, instanceName));
+ } else {
+ String serviceQName = getServiceQName(inputON);
+ String refName = getReferenceName(inputON);
+ outputProperties = new HashMap<>(createServiceMap(serviceQName, refName));
}
- String moduleName = getFactoryName(on);
- String instanceName = getInstanceName(on);
- return createReadOnlyModuleON(moduleName, instanceName);
+ Map<String, String> allProperties = getAdditionalProperties(inputON);
+ for (Entry<String, String> entry : allProperties.entrySet()) {
+ if (entry.getKey().startsWith("X-")) {
+ outputProperties.put(entry.getKey(), entry.getValue());
+ }
+ }
+ return createON(ON_DOMAIN, outputProperties);
+ }
+
+ public static ObjectName withTransactionName(ObjectName inputON, String transactionName) {
+ Map<String, String> additionalProperties = getAdditionalProperties(inputON);
+ additionalProperties.put(TRANSACTION_NAME_KEY, transactionName);
+ return createON(inputON.getDomain(), additionalProperties);
+
}
private static void assertDoesNotContain(
}
public static ObjectName createRuntimeBeanName(String moduleName,
- String instanceName, Map<String, String> additionalProperties) {
+ String instanceName, Map<String, String> additionalProperties) {
// check that there is no overwriting of default attributes
assertDoesNotContain(additionalProperties, MODULE_FACTORY_NAME_KEY);
assertDoesNotContain(additionalProperties, INSTANCE_NAME_KEY);
}
}
+ public static void checkTypeOneOf(ObjectName objectName, String ... types) {
+ for(String type: types) {
+ if (type.equals(objectName.getKeyProperty(TYPE_KEY))) {
+ return;
+ }
+ }
+ throw new IllegalArgumentException("Wrong type, expected one of " + Arrays.asList(types)
+ + ", got " + objectName);
+ }
+
public static ObjectName createModulePattern(String moduleName,
- String instanceName) {
+ String instanceName) {
if (moduleName == null)
moduleName = "*";
if (instanceName == null)
}
public static ObjectName createModulePattern(String ifcName,
- String instanceName, String transactionName) {
+ String instanceName, String transactionName) {
return ObjectNameUtil.createON(ObjectNameUtil.ON_DOMAIN
+ ":type=Module," + ObjectNameUtil.MODULE_FACTORY_NAME_KEY
+ "=" + ifcName + "," + ObjectNameUtil.INSTANCE_NAME_KEY + "="
}
public static ObjectName createRuntimeBeanPattern(String moduleName,
- String instanceName) {
+ String instanceName) {
return ObjectNameUtil.createON(ObjectNameUtil.ON_DOMAIN + ":"
+ ObjectNameUtil.TYPE_KEY + "="
+ ObjectNameUtil.TYPE_RUNTIME_BEAN + ","
}
public static ModuleIdentifier fromON(ObjectName objectName,
- String expectedType) {
+ String expectedType) {
checkType(objectName, expectedType);
String factoryName = getFactoryName(objectName);
if (factoryName == null)
return new ModuleIdentifier(factoryName, instanceName);
}
+ public static boolean isServiceReference(ObjectName objectName) {
+ return TYPE_SERVICE_REFERENCE.equals(objectName.getKeyProperty(TYPE_KEY));
+ }
}
boolean isModuleImplementingServiceInterface(
Class<? extends AbstractServiceInterface> serviceInterface);
+ Set<Class<? extends AbstractServiceInterface>> getImplementedServiceIntefaces();
+
/**
* Called when ModuleFactory is registered to config manager.
* Useful for populating the registry with pre-existing state. Since
--- /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;
+
+import org.opendaylight.controller.config.api.ServiceReferenceReadableRegistry;
+
+public interface CloseableServiceReferenceReadableRegistry extends AutoCloseable, ServiceReferenceReadableRegistry {
+
+
+ void close();
+
+}
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.ServiceReferenceWritableRegistry;
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.osgi.BeanToOsgiServiceManager;
import org.opendaylight.controller.config.manager.impl.osgi.BeanToOsgiServiceManager.OsgiRegistration;
import org.opendaylight.controller.config.manager.impl.util.LookupBeansUtil;
+import org.opendaylight.controller.config.manager.impl.util.ModuleQNameUtil;
import org.opendaylight.controller.config.spi.Module;
import org.opendaylight.controller.config.spi.ModuleFactory;
import org.osgi.framework.BundleContext;
private final ModuleFactoriesResolver resolver;
private final MBeanServer configMBeanServer;
- @GuardedBy("this")
- private final BundleContext bundleContext;
-
@GuardedBy("this")
private long version = 0;
@GuardedBy("this")
// internal jmx server shared by all transactions
private final MBeanServer transactionsMBeanServer;
+ // Used for finding new factory instances for default module functionality
@GuardedBy("this")
private List<ModuleFactory> lastListOfFactories = Collections.emptyList();
+ @GuardedBy("this") // switched in every 2ndPC
+ private CloseableServiceReferenceReadableRegistry readableSRRegistry = ServiceReferenceRegistryImpl.createInitialSRLookupRegistry();
+
// constructor
public ConfigRegistryImpl(ModuleFactoriesResolver resolver,
- BundleContext bundleContext, MBeanServer configMBeanServer) {
- this(resolver, bundleContext, configMBeanServer,
+ MBeanServer configMBeanServer) {
+ this(resolver, configMBeanServer,
new BaseJMXRegistrator(configMBeanServer));
}
// constructor
public ConfigRegistryImpl(ModuleFactoriesResolver resolver,
- BundleContext bundleContext, MBeanServer configMBeanServer,
+ MBeanServer configMBeanServer,
BaseJMXRegistrator baseJMXRegistrator) {
this.resolver = resolver;
this.beanToOsgiServiceManager = new BeanToOsgiServiceManager();
- this.bundleContext = bundleContext;
this.configMBeanServer = configMBeanServer;
this.baseJMXRegistrator = baseJMXRegistrator;
this.registryMBeanServer = MBeanServerFactory
private synchronized ConfigTransactionControllerInternal beginConfigInternal(boolean blankTransaction) {
versionCounter++;
- String transactionName = "ConfigTransaction-" + version + "-" + versionCounter;
- TransactionJMXRegistrator transactionRegistrator = baseJMXRegistrator
- .createTransactionJMXRegistrator(transactionName);
- Map<String, Map.Entry<ModuleFactory, BundleContext>> allCurrentFactories = Collections.unmodifiableMap(resolver.getAllFactories());
+ final String transactionName = "ConfigTransaction-" + version + "-" + versionCounter;
+
+ TransactionJMXRegistratorFactory factory = new TransactionJMXRegistratorFactory() {
+ @Override
+ public TransactionJMXRegistrator create() {
+ return baseJMXRegistrator.createTransactionJMXRegistrator(transactionName);
+ }
+ };
+
+ Map<String, Map.Entry<ModuleFactory, BundleContext>> allCurrentFactories = Collections.unmodifiableMap(
+ resolver.getAllFactories());
+ ConfigTransactionLookupRegistry txLookupRegistry = new ConfigTransactionLookupRegistry(new TransactionIdentifier(
+ transactionName), factory, allCurrentFactories);
+ ServiceReferenceWritableRegistry writableRegistry = ServiceReferenceRegistryImpl.createSRWritableRegistry(
+ readableSRRegistry, txLookupRegistry, allCurrentFactories);
+
ConfigTransactionControllerInternal transactionController = new ConfigTransactionControllerImpl(
- transactionName, transactionRegistrator, version,
- versionCounter, allCurrentFactories, transactionsMBeanServer, configMBeanServer, blankTransaction);
+ txLookupRegistry, version,
+ versionCounter, allCurrentFactories, transactionsMBeanServer,
+ configMBeanServer, blankTransaction, writableRegistry);
try {
- transactionRegistrator.registerMBean(transactionController, transactionController.getControllerObjectName());
+ txLookupRegistry.registerMBean(transactionController, transactionController.getControllerObjectName());
} catch (InstanceAlreadyExistsException e) {
throw new IllegalStateException(e);
}
-
transactionController.copyExistingModulesAndProcessFactoryDiff(currentConfig.getEntries(), lastListOfFactories);
-
transactionsHolder.add(transactionName, transactionController);
return transactionController;
}
OsgiRegistration osgiRegistration = null;
if (entry.hasOldModule()) {
ModuleInternalInfo oldInternalInfo = entry.getOldInternalInfo();
- DynamicReadableWrapper oldReadableConfigBean = oldInternalInfo
- .getReadableModule();
+ DynamicReadableWrapper oldReadableConfigBean = oldInternalInfo.getReadableModule();
currentConfig.remove(entry.getIdentifier());
// test if old instance == new instance
// update version
version = configTransactionController.getVersion();
+
+ // switch readable Service Reference Registry
+ this.readableSRRegistry.close();
+ this.readableSRRegistry = ServiceReferenceRegistryImpl.createSRReadableRegistry(
+ configTransactionController.getWritableRegistry(), this, baseJMXRegistrator);
+
return new CommitStatus(newInstances, reusedInstances,
recreatedInstances);
}
return baseJMXRegistrator.queryNames(namePattern, null);
}
+ @Override
+ public void checkConfigBeanExists(ObjectName objectName) throws InstanceNotFoundException {
+ ObjectNameUtil.checkDomain(objectName);
+ ObjectNameUtil.checkType(objectName, ObjectNameUtil.TYPE_MODULE);
+ String transactionName = ObjectNameUtil.getTransactionName(objectName);
+ if (transactionName != null) {
+ throw new IllegalArgumentException("Transaction attribute not supported in registry, wrong ObjectName: " + objectName);
+ }
+ // make sure exactly one match is found:
+ LookupBeansUtil.lookupConfigBean(this, ObjectNameUtil.getFactoryName(objectName), ObjectNameUtil.getInstanceName(objectName));
+ }
+
+ // service reference functionality:
+ @Override
+ public synchronized ObjectName lookupConfigBeanByServiceInterfaceName(String serviceInterfaceQName, String refName) {
+ return readableSRRegistry.lookupConfigBeanByServiceInterfaceName(serviceInterfaceQName, refName);
+ }
+
+ @Override
+ public synchronized Map<String, Map<String, ObjectName>> getServiceMapping() {
+ return readableSRRegistry.getServiceMapping();
+ }
+
+ @Override
+ public synchronized Map<String, ObjectName> lookupServiceReferencesByServiceInterfaceName(String serviceInterfaceQName) {
+ return readableSRRegistry.lookupServiceReferencesByServiceInterfaceName(serviceInterfaceQName);
+ }
+
+ @Override
+ public synchronized Set<String> lookupServiceInterfaceNames(ObjectName objectName) throws InstanceNotFoundException {
+ return readableSRRegistry.lookupServiceInterfaceNames(objectName);
+ }
+
+ @Override
+ public synchronized String getServiceInterfaceName(String namespace, String localName) {
+ return readableSRRegistry.getServiceInterfaceName(namespace, localName);
+ }
+
+ @Override
+ public void checkServiceReferenceExists(ObjectName objectName) throws InstanceNotFoundException {
+ readableSRRegistry.checkServiceReferenceExists(objectName);
+ }
+
+ @Override
+ public ObjectName getServiceReference(String serviceInterfaceQName, String refName) throws InstanceNotFoundException {
+ return readableSRRegistry.getServiceReference(serviceInterfaceQName, refName);
+ }
+
+ @Override
+ public Set<String> getAvailableModuleFactoryQNames() {
+ return ModuleQNameUtil.getQNames(resolver.getAllFactories());
+ }
+
+ @Override
+ public String toString() {
+ return "ConfigRegistryImpl{" +
+ "versionCounter=" + versionCounter +
+ ", version=" + version +
+ '}';
+ }
}
/**
}
private void add(ModuleInternalInfo configInfo) {
- ModuleInternalInfo oldValue = currentConfig.put(configInfo.getName(),
+ ModuleInternalInfo oldValue = currentConfig.put(configInfo.getIdentifier(),
configInfo);
if (oldValue != null) {
throw new IllegalStateException(
"Cannot overwrite module with same name:"
- + configInfo.getName() + ":" + configInfo);
+ + configInfo.getIdentifier() + ":" + configInfo);
}
}
Collections.sort(result);
return result;
}
+
+
}
/**
import org.opendaylight.controller.config.api.DependencyResolver;
import org.opendaylight.controller.config.api.ModuleIdentifier;
+import org.opendaylight.controller.config.api.ServiceReferenceWritableRegistry;
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.dynamicmbean.ReadOnlyAtomicBoolean;
import org.opendaylight.controller.config.manager.impl.dynamicmbean.ReadOnlyAtomicBoolean.ReadOnlyAtomicBooleanImpl;
import org.opendaylight.controller.config.manager.impl.factoriesresolver.HierarchicalConfigMBeanFactoriesHolder;
-import org.opendaylight.controller.config.manager.impl.jmx.TransactionJMXRegistrator;
import org.opendaylight.controller.config.manager.impl.jmx.TransactionModuleJMXRegistrator;
import org.opendaylight.controller.config.manager.impl.jmx.TransactionModuleJMXRegistrator.TransactionModuleJMXRegistration;
-import org.opendaylight.controller.config.manager.impl.util.LookupBeansUtil;
import org.opendaylight.controller.config.spi.Module;
import org.opendaylight.controller.config.spi.ModuleFactory;
import org.opendaylight.yangtools.concepts.Identifiable;
import javax.management.InstanceNotFoundException;
import javax.management.MBeanServer;
import javax.management.ObjectName;
+import java.util.ArrayList;
+import java.util.Collection;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Set;
-import java.util.ArrayList;
-import java.util.Collection;
import java.util.concurrent.atomic.AtomicBoolean;
import static java.lang.String.format;
/**
* This is a JMX bean representing current transaction. It contains
- * {@link #transactionIdentifier}, unique version and parent version for
+ * transaction identifier, unique version and parent version for
* optimistic locking.
*/
class ConfigTransactionControllerImpl implements
Identifiable<TransactionIdentifier>{
private static final Logger logger = LoggerFactory.getLogger(ConfigTransactionControllerImpl.class);
- private final TransactionIdentifier transactionIdentifier;
+ private final ConfigTransactionLookupRegistry txLookupRegistry;
private final ObjectName controllerON;
- private final TransactionJMXRegistrator transactionRegistrator;
- private final TransactionModuleJMXRegistrator txModuleJMXRegistrator;
+
private final long parentVersion, currentVersion;
private final HierarchicalConfigMBeanFactoriesHolder factoriesHolder;
private final DependencyResolverManager dependencyResolverManager;
private final boolean blankTransaction;
- public ConfigTransactionControllerImpl(String transactionName,
- TransactionJMXRegistrator transactionRegistrator,
+ @GuardedBy("this")
+ private final ServiceReferenceWritableRegistry writableSRRegistry;
+
+ public ConfigTransactionControllerImpl(ConfigTransactionLookupRegistry txLookupRegistry,
long parentVersion, long currentVersion,
Map<String, Map.Entry<ModuleFactory, BundleContext>> currentlyRegisteredFactories,
MBeanServer transactionsMBeanServer, MBeanServer configMBeanServer,
- boolean blankTransaction) {
-
- this.transactionIdentifier = new TransactionIdentifier(transactionName);
- this.controllerON = ObjectNameUtil
- .createTransactionControllerON(transactionName);
- this.transactionRegistrator = transactionRegistrator;
- txModuleJMXRegistrator = transactionRegistrator
- .createTransactionModuleJMXRegistrator();
+ boolean blankTransaction, ServiceReferenceWritableRegistry writableSRRegistry) {
+
+ this.txLookupRegistry = txLookupRegistry;
+ String transactionName = txLookupRegistry.getTransactionIdentifier().getName();
+ this.controllerON = ObjectNameUtil.createTransactionControllerON(transactionName);
this.parentVersion = parentVersion;
this.currentVersion = currentVersion;
this.currentlyRegisteredFactories = currentlyRegisteredFactories;
this.factoriesHolder = new HierarchicalConfigMBeanFactoriesHolder(currentlyRegisteredFactories);
this.transactionStatus = new TransactionStatus();
- this.dependencyResolverManager = new DependencyResolverManager(transactionName, transactionStatus);
+ this.dependencyResolverManager = new DependencyResolverManager(transactionName, transactionStatus, writableSRRegistry);
this.transactionsMBeanServer = transactionsMBeanServer;
this.configMBeanServer = configMBeanServer;
this.blankTransaction = blankTransaction;
+ this.writableSRRegistry = writableSRRegistry;
}
@Override
throws InstanceAlreadyExistsException {
transactionStatus.checkNotCommitStarted();
transactionStatus.checkNotAborted();
- ModuleIdentifier moduleIdentifier = oldConfigBeanInfo.getName();
+ ModuleIdentifier moduleIdentifier = oldConfigBeanInfo.getIdentifier();
dependencyResolverManager.assertNotExists(moduleIdentifier);
ModuleFactory moduleFactory = factoriesHolder
.findByModuleName(moduleIdentifier.getFactoryName());
Module module;
- DependencyResolver dependencyResolver = dependencyResolverManager
- .getOrCreate(moduleIdentifier);
+ DependencyResolver dependencyResolver = dependencyResolverManager.getOrCreate(moduleIdentifier);
try {
BundleContext bc = getModuleFactoryBundleContext(moduleFactory.getImplementationName());
module = moduleFactory.createModule(
+ moduleIdentifier + ", got " + dependencyResolver.getIdentifier());
}
DynamicMBean writableDynamicWrapper = new DynamicWritableWrapper(
- module, moduleIdentifier, transactionIdentifier,
+ module, moduleIdentifier, getTransactionIdentifier(),
readOnlyAtomicBoolean, transactionsMBeanServer,
configMBeanServer);
ObjectName writableON = ObjectNameUtil.createTransactionModuleON(
- transactionIdentifier.getName(), moduleIdentifier);
+ getTransactionIdentifier().getName(), moduleIdentifier);
// put wrapper to jmx
- TransactionModuleJMXRegistration transactionModuleJMXRegistration = txModuleJMXRegistrator
+ TransactionModuleJMXRegistration transactionModuleJMXRegistration = getTxModuleJMXRegistrator()
.registerMBean(writableDynamicWrapper, writableON);
ModuleInternalTransactionalInfo moduleInternalTransactionalInfo = new ModuleInternalTransactionalInfo(
moduleIdentifier, module, moduleFactory,
}
@Override
- public synchronized void destroyModule(ObjectName objectName)
- throws InstanceNotFoundException {
+ public synchronized void destroyModule(ObjectName objectName) throws InstanceNotFoundException {
+ checkTransactionName(objectName);
+ ObjectNameUtil.checkDomain(objectName);
+ ModuleIdentifier moduleIdentifier = ObjectNameUtil.fromON(objectName,
+ ObjectNameUtil.TYPE_MODULE);
+ destroyModule(moduleIdentifier);
+ }
+
+ private void checkTransactionName(ObjectName objectName) {
String foundTransactionName = ObjectNameUtil
.getTransactionName(objectName);
- if (transactionIdentifier.getName().equals(foundTransactionName) == false) {
+ if (getTransactionIdentifier().getName().equals(foundTransactionName) == false) {
throw new IllegalArgumentException("Wrong transaction name "
+ objectName);
}
- ObjectNameUtil.checkDomain(objectName);
- ModuleIdentifier moduleIdentifier = ObjectNameUtil.fromON(objectName,
- ObjectNameUtil.TYPE_MODULE);
- destroyModule(moduleIdentifier);
}
private synchronized void destroyModule(ModuleIdentifier moduleIdentifier) {
logger.warn("Warning: removing default bean. This will be forbidden in next version of config-subsystem");
}
}
+ // first remove refNames, it checks for objectname existence
+ try {
+ writableSRRegistry.removeServiceReferences(
+ 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);
+ }
+
ModuleInternalTransactionalInfo removedTInfo = dependencyResolverManager.destroyModule(moduleIdentifier);
// remove from jmx
removedTInfo.getTransactionModuleJMXRegistration().close();
private void validate_noLocks() throws ValidationException {
transactionStatus.checkNotAborted();
- logger.info("Validating transaction {}", transactionIdentifier);
+ logger.info("Validating transaction {}", getTransactionIdentifier());
// call validate()
List<ValidationException> collectedExceptions = new ArrayList<>();
for (Entry<ModuleIdentifier, Module> entry : dependencyResolverManager
throw ValidationException
.createFromCollectedValidationExceptions(collectedExceptions);
}
- logger.info("Validated transaction {}", transactionIdentifier);
+ logger.info("Validated transaction {}", getTransactionIdentifier());
}
/**
+ "to obtain a lock");
}
- logger.info("Committing transaction {}", transactionIdentifier);
+ logger.info("Committing transaction {}", getTransactionIdentifier());
// call getInstance()
for (Entry<ModuleIdentifier, Module> entry : dependencyResolverManager
ModuleIdentifier name = entry.getKey();
try {
logger.debug("About to commit {} in transaction {}",
- name, transactionIdentifier);
+ name, getTransactionIdentifier());
module.getInstance();
} catch (Exception e) {
logger.error("Commit failed on {} in transaction {}", name,
- transactionIdentifier, e);
+ getTransactionIdentifier(), e);
internalAbort();
throw new RuntimeException(
format("Error - getInstance() failed for %s in transaction %s",
- name, transactionIdentifier), e);
+ name, getTransactionIdentifier()), e);
}
}
// count dependency order
- logger.info("Committed configuration {}", transactionIdentifier);
+ logger.info("Committed configuration {}", getTransactionIdentifier());
transactionStatus.setCommitted();
// unregister this and all modules from jmx
close();
close();
}
- private void close() {
- transactionRegistrator.close();
+ public void close() {
+ //FIXME: should not close object that was retrieved in constructor, a wrapper object should do that perhaps
+ txLookupRegistry.close();
}
@Override
@Override
public String getTransactionName() {
- return transactionIdentifier.getName();
+ return getTransactionIdentifier().getName();
}
/**
*/
@Override
public Set<ObjectName> lookupConfigBeans() {
- return lookupConfigBeans("*", "*");
+ return txLookupRegistry.lookupConfigBeans();
}
/**
*/
@Override
public Set<ObjectName> lookupConfigBeans(String moduleName) {
- return lookupConfigBeans(moduleName, "*");
+ return txLookupRegistry.lookupConfigBeans(moduleName);
}
/**
@Override
public ObjectName lookupConfigBean(String moduleName, String instanceName)
throws InstanceNotFoundException {
- return LookupBeansUtil.lookupConfigBean(this, moduleName, instanceName);
+ return txLookupRegistry.lookupConfigBean(moduleName, instanceName);
}
/**
* {@inheritDoc}
*/
@Override
- public Set<ObjectName> lookupConfigBeans(String moduleName,
- String instanceName) {
- ObjectName namePattern = ObjectNameUtil.createModulePattern(moduleName,
- instanceName, transactionIdentifier.getName());
- return txModuleJMXRegistrator.queryNames(namePattern, null);
+ public Set<ObjectName> lookupConfigBeans(String moduleName, String instanceName) {
+ return txLookupRegistry.lookupConfigBeans(moduleName, instanceName);
}
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public void checkConfigBeanExists(ObjectName objectName) throws InstanceNotFoundException {
+ txLookupRegistry.checkConfigBeanExists(objectName);
+ }
+ // --
+
+ /**
+ * {@inheritDoc}
+ */
@Override
public Set<String> getAvailableModuleNames() {
return factoriesHolder.getModuleNames();
// @VisibleForTesting
TransactionModuleJMXRegistrator getTxModuleJMXRegistrator() {
- return txModuleJMXRegistrator;
+ return txLookupRegistry.getTxModuleJMXRegistrator();
}
public TransactionIdentifier getName() {
- return transactionIdentifier;
+ return getTransactionIdentifier();
}
@Override
@Override
public TransactionIdentifier getIdentifier() {
- return transactionIdentifier;
+ return getTransactionIdentifier();
}
@Override
}
return factoryBundleContextEntry.getValue();
}
+
+ // service reference functionality:
+
+
+ @Override
+ public synchronized ObjectName lookupConfigBeanByServiceInterfaceName(String serviceInterfaceQName, String refName) {
+ return writableSRRegistry.lookupConfigBeanByServiceInterfaceName(serviceInterfaceQName, refName);
+ }
+
+ @Override
+ public synchronized Map<String, Map<String, ObjectName>> getServiceMapping() {
+ return writableSRRegistry.getServiceMapping();
+ }
+
+ @Override
+ public synchronized Map<String, ObjectName> lookupServiceReferencesByServiceInterfaceName(String serviceInterfaceQName) {
+ return writableSRRegistry.lookupServiceReferencesByServiceInterfaceName(serviceInterfaceQName);
+ }
+
+ @Override
+ public synchronized Set<String> lookupServiceInterfaceNames(ObjectName objectName) throws InstanceNotFoundException {
+ return writableSRRegistry.lookupServiceInterfaceNames(objectName);
+ }
+
+ @Override
+ public synchronized String getServiceInterfaceName(String namespace, String localName) {
+ return writableSRRegistry.getServiceInterfaceName(namespace, localName);
+ }
+
+ @Override
+ public synchronized ObjectName saveServiceReference(String serviceInterfaceName, String refName, ObjectName moduleON) throws InstanceNotFoundException {
+ return writableSRRegistry.saveServiceReference(serviceInterfaceName, refName, moduleON);
+ }
+
+ @Override
+ public synchronized void removeServiceReference(String serviceInterfaceName, String refName) throws InstanceNotFoundException {
+ writableSRRegistry.removeServiceReference(serviceInterfaceName, refName);
+ }
+
+ @Override
+ public synchronized void removeAllServiceReferences() {
+ writableSRRegistry.removeAllServiceReferences();
+ }
+
+ @Override
+ public boolean removeServiceReferences(ObjectName objectName) throws InstanceNotFoundException {
+ return writableSRRegistry.removeServiceReferences(objectName);
+ }
+
+ @Override
+ public ServiceReferenceWritableRegistry getWritableRegistry() {
+ return writableSRRegistry;
+ }
+
+ public TransactionIdentifier getTransactionIdentifier() {
+ return txLookupRegistry.getTransactionIdentifier();
+ }
+
+ @Override
+ public Set<String> getAvailableModuleFactoryQNames() {
+ return txLookupRegistry.getAvailableModuleFactoryQNames();
+ }
+
+ @Override
+ public void checkServiceReferenceExists(ObjectName objectName) throws InstanceNotFoundException {
+ writableSRRegistry.checkServiceReferenceExists(objectName);
+ }
+
+ @Override
+ public ObjectName getServiceReference(String serviceInterfaceQName, String refName) throws InstanceNotFoundException {
+ return writableSRRegistry.getServiceReference(serviceInterfaceQName, refName);
+ }
}
import javax.management.ObjectName;
import org.opendaylight.controller.config.api.ModuleIdentifier;
+import org.opendaylight.controller.config.api.ServiceReferenceWritableRegistry;
import org.opendaylight.controller.config.api.ValidationException;
import org.opendaylight.controller.config.spi.ModuleFactory;
import org.osgi.framework.BundleContext;
List<ModuleFactory> getCurrentlyRegisteredFactories();
BundleContext getModuleFactoryBundleContext(String factoryName);
+
+ ServiceReferenceWritableRegistry getWritableRegistry();
+
}
--- /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;
+
+import org.opendaylight.controller.config.api.LookupRegistry;
+import org.opendaylight.controller.config.api.jmx.ObjectNameUtil;
+import org.opendaylight.controller.config.manager.impl.jmx.TransactionJMXRegistrator;
+import org.opendaylight.controller.config.manager.impl.jmx.TransactionModuleJMXRegistrator;
+import org.opendaylight.controller.config.manager.impl.util.LookupBeansUtil;
+import org.opendaylight.controller.config.manager.impl.util.ModuleQNameUtil;
+import org.opendaylight.controller.config.spi.ModuleFactory;
+import org.osgi.framework.BundleContext;
+
+import javax.management.InstanceAlreadyExistsException;
+import javax.management.InstanceNotFoundException;
+import javax.management.ObjectName;
+import java.io.Closeable;
+import java.util.Map;
+import java.util.Map.Entry;
+import java.util.Set;
+
+/**
+ * Responsible for creating TransactionJMXRegistrator, registering transaction and all its beans,
+ * lookup of beans, closing of TransactionJMXRegistrator.
+ */
+class ConfigTransactionLookupRegistry implements LookupRegistry, Closeable {
+ private final TransactionJMXRegistrator transactionJMXRegistrator;
+ private final TransactionIdentifier transactionIdentifier;
+ private final TransactionModuleJMXRegistrator txModuleJMXRegistrator;
+ private final Map<String, Map.Entry<ModuleFactory, BundleContext>> allCurrentFactories;
+
+ ConfigTransactionLookupRegistry(TransactionIdentifier transactionIdentifier,
+ TransactionJMXRegistratorFactory factory, Map<String, Entry<ModuleFactory, BundleContext>> allCurrentFactories) {
+ this.transactionIdentifier = transactionIdentifier;
+ this.transactionJMXRegistrator = factory.create();
+ this.txModuleJMXRegistrator = transactionJMXRegistrator.createTransactionModuleJMXRegistrator();
+ this.allCurrentFactories = allCurrentFactories;
+ }
+
+ private void checkTransactionName(ObjectName objectName) {
+ String foundTransactionName = ObjectNameUtil
+ .getTransactionName(objectName);
+ if (transactionIdentifier.getName().equals(foundTransactionName) == false) {
+ throw new IllegalArgumentException("Wrong transaction name "
+ + objectName);
+ }
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public Set<ObjectName> lookupConfigBeans() {
+ return lookupConfigBeans("*", "*");
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public Set<ObjectName> lookupConfigBeans(String moduleName) {
+ return lookupConfigBeans(moduleName, "*");
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public ObjectName lookupConfigBean(String moduleName, String instanceName)
+ throws InstanceNotFoundException {
+ return LookupBeansUtil.lookupConfigBean(this, moduleName, instanceName);
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public Set<ObjectName> lookupConfigBeans(String moduleName,
+ String instanceName) {
+ ObjectName namePattern = ObjectNameUtil.createModulePattern(moduleName,
+ instanceName, transactionIdentifier.getName());
+ return txModuleJMXRegistrator.queryNames(namePattern, null);
+ }
+
+ @Override
+ public void checkConfigBeanExists(ObjectName objectName) throws InstanceNotFoundException {
+ ObjectNameUtil.checkDomain(objectName);
+ ObjectNameUtil.checkType(objectName, ObjectNameUtil.TYPE_MODULE);
+ checkTransactionName(objectName);
+ // make sure exactly one match is found:
+ LookupBeansUtil.lookupConfigBean(this, ObjectNameUtil.getFactoryName(objectName), ObjectNameUtil.getInstanceName(objectName));
+ }
+
+ TransactionIdentifier getTransactionIdentifier() {
+ return transactionIdentifier;
+ }
+
+ TransactionModuleJMXRegistrator getTxModuleJMXRegistrator() {
+ return txModuleJMXRegistrator;
+ }
+
+ public void close() {
+ transactionJMXRegistrator.close();
+ }
+
+ public void registerMBean(ConfigTransactionControllerInternal transactionController, ObjectName controllerObjectName) throws InstanceAlreadyExistsException {
+ transactionJMXRegistrator.registerMBean(transactionController, controllerObjectName);
+ }
+
+ @Override
+ public Set<String> getAvailableModuleFactoryQNames() {
+ return ModuleQNameUtil.getQNames(allCurrentFactories);
+ }
+
+
+ @Override
+ public String toString() {
+ return "ConfigTransactionLookupRegistry{" +
+ "transactionIdentifier=" + transactionIdentifier +
+ '}';
+ }
+}
+
+interface TransactionJMXRegistratorFactory {
+ TransactionJMXRegistrator create();
+}
return osgiRegistration;
}
- @Deprecated
- public ModuleIdentifier getName() {
- return name;
- }
-
/**
* Get index representing dependency ordering within a transaction.
*/
}
public DestroyedModule toDestroyedModule() {
- return new DestroyedModule(getName(),
+ return new DestroyedModule(getIdentifier(),
getReadableModule().getInstance(), getModuleJMXRegistrator(),
getOsgiRegistration(), getOrderingIdx());
}
--- /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;
+
+import org.opendaylight.controller.config.api.LookupRegistry;
+import org.opendaylight.controller.config.api.ModuleIdentifier;
+import org.opendaylight.controller.config.api.ServiceReferenceReadableRegistry;
+import org.opendaylight.controller.config.api.ServiceReferenceWritableRegistry;
+import org.opendaylight.controller.config.api.annotations.ServiceInterfaceAnnotation;
+import org.opendaylight.controller.config.api.jmx.ObjectNameUtil;
+import org.opendaylight.controller.config.manager.impl.jmx.BaseJMXRegistrator;
+import org.opendaylight.controller.config.manager.impl.jmx.ServiceReference;
+import org.opendaylight.controller.config.manager.impl.jmx.ServiceReferenceMXBeanImpl;
+import org.opendaylight.controller.config.manager.impl.jmx.ServiceReferenceRegistrator;
+import org.opendaylight.controller.config.manager.impl.jmx.ServiceReferenceRegistrator.ServiceReferenceJMXRegistration;
+import org.opendaylight.controller.config.manager.impl.jmx.ServiceReferenceRegistrator.ServiceReferenceTransactionRegistratorFactory;
+import org.opendaylight.controller.config.manager.impl.jmx.ServiceReferenceRegistrator.ServiceReferenceTransactionRegistratorFactoryImpl;
+import org.opendaylight.controller.config.manager.impl.util.InterfacesHelper;
+import org.opendaylight.controller.config.spi.ModuleFactory;
+import org.osgi.framework.BundleContext;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import javax.management.InstanceAlreadyExistsException;
+import javax.management.InstanceNotFoundException;
+import javax.management.ObjectName;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.Map;
+import java.util.Map.Entry;
+import java.util.Set;
+
+public class ServiceReferenceRegistryImpl implements CloseableServiceReferenceReadableRegistry, ServiceReferenceWritableRegistry {
+ private static final Logger logger = LoggerFactory.getLogger(ServiceReferenceRegistryImpl.class);
+
+ private final Map<String, ModuleFactory> factories;
+ private final Map<String, Set<String>> factoryNamesToQNames;
+ // validator of incoming ObjectNames - throws InstanceNotFoundException if not found either in registry or transaction
+ private final LookupRegistry lookupRegistry;
+ private final ServiceReferenceRegistrator serviceReferenceRegistrator;
+ // helper method for getting QName of SI from namespace + local name
+ private final Map<String /* namespace */, Map<String /* local name */, ServiceInterfaceAnnotation>> namespacesToAnnotations;
+ // all Service Interface qNames for sanity checking
+ private final Set<String /* qName */> allQNames;
+
+ // actual reference database
+ private final Map<ServiceReference, ModuleIdentifier> refNames = new HashMap<>();
+ private final boolean writable;
+ private final Map<ServiceReference, Entry<ServiceReferenceMXBeanImpl, ServiceReferenceJMXRegistration>> mBeans = new HashMap<>();
+
+ /**
+ * Static constructor for config registry. Since only transaction can write to this registry, it will
+ * return blank state.
+ */
+ public static CloseableServiceReferenceReadableRegistry createInitialSRLookupRegistry() {
+ // since this is initial state, just throw exception:
+ LookupRegistry lookupRegistry = new LookupRegistry() {
+ @Override
+ public Set<ObjectName> lookupConfigBeans() {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public Set<ObjectName> lookupConfigBeans(String moduleName) {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public Set<ObjectName> lookupConfigBeans(String moduleName, String instanceName) {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public ObjectName lookupConfigBean(String moduleName, String instanceName) throws InstanceNotFoundException {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public void checkConfigBeanExists(ObjectName objectName) throws InstanceNotFoundException {
+ throw new InstanceNotFoundException("Cannot find " + objectName + " - Tried to use mocking registry");
+ }
+
+ @Override
+ public Set<String> getAvailableModuleFactoryQNames() {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public String toString() {
+ return "initial";
+ }
+ };
+ ServiceReferenceTransactionRegistratorFactory serviceReferenceRegistratorFactory = new ServiceReferenceTransactionRegistratorFactory(){
+ @Override
+ public ServiceReferenceRegistrator create() {
+ return new ServiceReferenceRegistrator() {
+ @Override
+ public String getNullableTransactionName() {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public ServiceReferenceJMXRegistration registerMBean(ServiceReferenceMXBeanImpl object, ObjectName on) throws InstanceAlreadyExistsException {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public void close() {
+
+ }
+ };
+ }
+ };
+ return new ServiceReferenceRegistryImpl(Collections.<String, ModuleFactory>emptyMap(), lookupRegistry,
+ serviceReferenceRegistratorFactory, false);
+ }
+
+ /**
+ * Static constructor for transaction controller. Take current state as seen by config registry, allow writing new data.
+ */
+ public static ServiceReferenceWritableRegistry createSRWritableRegistry(ServiceReferenceReadableRegistry oldReadableRegistry,
+ ConfigTransactionLookupRegistry txLookupRegistry,
+ Map<String, Map.Entry<ModuleFactory, BundleContext>> currentlyRegisteredFactories) {
+
+ if (txLookupRegistry == null) {
+ throw new IllegalArgumentException("txLookupRegistry is null");
+ }
+ ServiceReferenceRegistryImpl old = (ServiceReferenceRegistryImpl) oldReadableRegistry;
+ Map<String, ModuleFactory> factories = extractFactoriesMap(currentlyRegisteredFactories);
+ ServiceReferenceTransactionRegistratorFactory serviceReferenceRegistratorFactory = new ServiceReferenceTransactionRegistratorFactoryImpl(
+ txLookupRegistry.getTxModuleJMXRegistrator(), txLookupRegistry.getTxModuleJMXRegistrator().getTransactionName());
+ ServiceReferenceRegistryImpl newRegistry = new ServiceReferenceRegistryImpl(factories, txLookupRegistry,
+ serviceReferenceRegistratorFactory, true);
+ copy(old, newRegistry, txLookupRegistry.getTransactionIdentifier().getName());
+ return newRegistry;
+ }
+
+ /**
+ * Copy back state to config registry after commit.
+ */
+ public static CloseableServiceReferenceReadableRegistry createSRReadableRegistry(ServiceReferenceWritableRegistry oldWritableRegistry,
+ LookupRegistry lookupRegistry, BaseJMXRegistrator baseJMXRegistrator) {
+ ServiceReferenceRegistryImpl old = (ServiceReferenceRegistryImpl) oldWritableRegistry;
+
+ // even if factories do change, nothing in the mapping can change between transactions
+ ServiceReferenceTransactionRegistratorFactory serviceReferenceRegistratorFactory = new ServiceReferenceTransactionRegistratorFactoryImpl(baseJMXRegistrator);
+ ServiceReferenceRegistryImpl newRegistry = new ServiceReferenceRegistryImpl(old.factories, lookupRegistry,
+ serviceReferenceRegistratorFactory, false);
+ copy(old, newRegistry, null);
+ return newRegistry;
+ }
+
+ /**
+ * Fill refNames and mBeans maps from old instance
+ */
+ private static void copy(ServiceReferenceRegistryImpl old, ServiceReferenceRegistryImpl newRegistry, String nullableDstTransactionName) {
+ for (Entry<ServiceReference, Entry<ServiceReferenceMXBeanImpl, ServiceReferenceJMXRegistration>> refNameEntry : old.mBeans.entrySet()) {
+ ObjectName currentImplementation;
+ ObjectName currentImplementationSrc = refNameEntry.getValue().getKey().getCurrentImplementation();
+ if (nullableDstTransactionName != null) {
+ currentImplementation = ObjectNameUtil.withTransactionName(currentImplementationSrc, nullableDstTransactionName);
+ } else {
+ currentImplementation = ObjectNameUtil.withoutTransactionName(currentImplementationSrc);
+ }
+ try {
+ boolean skipChecks = true;
+ newRegistry.saveServiceReference(refNameEntry.getKey(), currentImplementation, skipChecks);
+ } catch (InstanceNotFoundException e) {
+ logger.error("Cannot save service reference({}, {})", refNameEntry.getKey(), currentImplementation);
+ throw new IllegalStateException("Possible code error", e);
+ }
+ }
+ }
+
+ private static Map<String, ModuleFactory> extractFactoriesMap(Map<String, Map.Entry<ModuleFactory, BundleContext>> currentlyRegisteredFactories) {
+ Map<String, ModuleFactory> result = new HashMap<>();
+ for (Entry<String, Entry<ModuleFactory, BundleContext>> entry : currentlyRegisteredFactories.entrySet()) {
+ result.put(entry.getKey(), entry.getValue().getKey());
+ }
+ return result;
+ }
+
+ private ServiceReferenceRegistryImpl(Map<String, ModuleFactory> factories, LookupRegistry lookupRegistry,
+ ServiceReferenceTransactionRegistratorFactory serviceReferenceRegistratorFactory,
+ boolean writable) {
+ this.factories = factories;
+ this.writable = writable;
+ this.lookupRegistry = lookupRegistry;
+
+ this.serviceReferenceRegistrator = serviceReferenceRegistratorFactory.create();
+
+ Map<String, Set<String /* QName */>> factoryNamesToQNames = new HashMap<>();
+ Set<ServiceInterfaceAnnotation> allAnnotations = new HashSet<>();
+ Set<String /* qName */> allQNames = new HashSet<>();
+ for (Entry<String, ModuleFactory> entry : factories.entrySet()) {
+ if (entry.getKey().equals(entry.getValue().getImplementationName()) == false) {
+ logger.error("Possible error in code: Mismatch between supplied and actual name of {}", entry);
+ throw new IllegalArgumentException("Possible error in code: Mismatch between supplied and actual name of " + entry);
+ }
+ Set<ServiceInterfaceAnnotation> siAnnotations = InterfacesHelper.getServiceInterfaceAnnotations(entry.getValue());
+ Set<String> qNames = new HashSet<>();
+ for (ServiceInterfaceAnnotation sia: siAnnotations) {
+ qNames.add(sia.value());
+ }
+ allAnnotations.addAll(siAnnotations);
+ allQNames.addAll(qNames);
+ factoryNamesToQNames.put(entry.getKey(), Collections.unmodifiableSet(qNames));
+ }
+ this.factoryNamesToQNames = Collections.unmodifiableMap(factoryNamesToQNames);
+ this.allQNames = Collections.unmodifiableSet(allQNames);
+ // fill namespacesToAnnotations
+ Map<String /* namespace */, Map<String /* localName */, ServiceInterfaceAnnotation>> namespacesToAnnotations =
+ new HashMap<>();
+ for (ServiceInterfaceAnnotation sia : allAnnotations) {
+ Map<String, ServiceInterfaceAnnotation> ofNamespace = namespacesToAnnotations.get(sia.namespace());
+ if (ofNamespace == null) {
+ ofNamespace = new HashMap<>();
+ namespacesToAnnotations.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);
+ throw new IllegalArgumentException("Conflict between local names in " + sia.namespace() + " : " + sia.localName());
+ }
+ ofNamespace.put(sia.localName(), sia);
+ }
+ this.namespacesToAnnotations = Collections.unmodifiableMap(namespacesToAnnotations);
+ // copy refNames
+ logger.trace("factoryNamesToQNames:{}", this.factoryNamesToQNames);
+ }
+
+
+ @Override
+ public synchronized Set<String> lookupServiceInterfaceNames(ObjectName objectName) throws InstanceNotFoundException {
+ lookupRegistry.checkConfigBeanExists(objectName);
+
+ String factoryName = ObjectNameUtil.getFactoryName(objectName);
+ Set<String> serviceInterfaceAnnotations = factoryNamesToQNames.get(factoryName);
+ if (serviceInterfaceAnnotations == null) {
+ logger.error("Possible error in code: cannot find factory annotations of '{}' extracted from ON {} in {}",
+ factoryName, objectName, factoryNamesToQNames);
+ throw new IllegalArgumentException("Cannot find factory with name " + factoryName);
+ }
+ return serviceInterfaceAnnotations;
+ }
+
+ @Override
+ public synchronized String getServiceInterfaceName(String namespace, String localName) {
+ Map<String /* localName */, ServiceInterfaceAnnotation> ofNamespace = namespacesToAnnotations.get(namespace);
+ if (ofNamespace == null) {
+ logger.error("Cannot find namespace {} in {}", namespace, namespacesToAnnotations);
+ throw new IllegalArgumentException("Cannot find namespace " + namespace);
+ }
+ ServiceInterfaceAnnotation sia = ofNamespace.get(localName);
+ if (sia == null) {
+ logger.error("Cannot find local name {} in namespace {}, found only {}", localName, namespace, ofNamespace);
+ throw new IllegalArgumentException("Cannot find local name " + localName + " in namespace " + namespace);
+ }
+ return sia.value();
+ }
+
+ // reading:
+
+ @Override
+ public synchronized Map<String /* serviceInterfaceName */, Map<String/* refName */, ObjectName>> getServiceMapping() {
+ Map<String /* serviceInterfaceName */, Map<String/* refName */, ObjectName>> result = new HashMap<>();
+ for (Entry<ServiceReference, ModuleIdentifier> entry: refNames.entrySet()) {
+ String qName = entry.getKey().getServiceInterfaceName();
+ Map<String /* refName */, ObjectName> innerMap = result.get(qName);
+ if (innerMap == null) {
+ innerMap = new HashMap<>();
+ result.put(qName, innerMap);
+ }
+ innerMap.put(entry.getKey().getRefName(), getObjectName(entry.getValue()));
+ }
+ return result;
+ }
+
+ private ObjectName getObjectName(ModuleIdentifier moduleIdentifier) {
+ ObjectName on;
+ try {
+ on = lookupRegistry.lookupConfigBean(moduleIdentifier.getFactoryName(), moduleIdentifier.getInstanceName());
+ } catch (InstanceNotFoundException e) {
+ logger.error("Cannot find instance {}", moduleIdentifier);
+ throw new IllegalStateException("Cannot find instance " + moduleIdentifier, e);
+ }
+ return on;
+ }
+
+ @Override
+ public synchronized ObjectName lookupConfigBeanByServiceInterfaceName(String serviceInterfaceQName, String refName) {
+ ServiceReference serviceReference = new ServiceReference(serviceInterfaceQName, refName);
+ ModuleIdentifier moduleIdentifier = refNames.get(serviceReference);
+ if (moduleIdentifier == null) {
+ logger.error("Cannot find qname {} and refName {} in {}", serviceInterfaceQName, refName, refName);
+ throw new IllegalArgumentException("Cannot find " + serviceReference);
+ }
+ return getObjectName(moduleIdentifier);
+ }
+
+ @Override
+ public synchronized Map<String /* refName */, ObjectName> lookupServiceReferencesByServiceInterfaceName(String serviceInterfaceQName) {
+ Map<String, Map<String, ObjectName>> serviceMapping = getServiceMapping();
+ Map<String, ObjectName> innerMap = serviceMapping.get(serviceInterfaceQName);
+ if (innerMap == null) {
+ logger.error("Cannot find qname {} in {}", serviceInterfaceQName, refNames);
+ throw new IllegalArgumentException("Cannot find " + serviceInterfaceQName);
+ }
+ return innerMap;
+ }
+
+ @Override
+ public synchronized ObjectName getServiceReference(String serviceInterfaceQName, String refName) throws InstanceNotFoundException {
+ ServiceReference serviceReference = new ServiceReference(serviceInterfaceQName, refName);
+ if (mBeans.containsKey(serviceReference) == false) {
+ throw new InstanceNotFoundException("Cannot find " + serviceReference);
+ }
+ return getServiceON(serviceReference);
+ }
+
+ @Override
+ public synchronized void checkServiceReferenceExists(ObjectName objectName) throws InstanceNotFoundException {
+ String actualTransactionName = ObjectNameUtil.getTransactionName(objectName);
+ String expectedTransactionName = serviceReferenceRegistrator.getNullableTransactionName();
+ if (writable & actualTransactionName == null || (writable && actualTransactionName.equals(expectedTransactionName) == false)) {
+ throw new IllegalArgumentException("Mismatched transaction name in " + objectName);
+ }
+ String serviceQName = ObjectNameUtil.getServiceQName(objectName);
+ String referenceName = ObjectNameUtil.getReferenceName(objectName);
+ ServiceReference serviceReference = new ServiceReference(serviceQName, referenceName);
+ if (refNames.containsKey(serviceReference) == false) {
+ logger.warn("Cannot find {} in {}", serviceReference, refNames);
+ throw new InstanceNotFoundException("Service reference not found:" + objectName);
+ }
+ }
+
+ // writing:
+
+ private void assertWritable() {
+ if (writable == false) {
+ throw new IllegalStateException("Cannot write to readable registry");
+ }
+ }
+
+ @Override
+ public synchronized ObjectName saveServiceReference(String serviceInterfaceName, String refName, ObjectName moduleON) throws InstanceNotFoundException {
+ assertWritable();
+ ServiceReference serviceReference = new ServiceReference(serviceInterfaceName, refName);
+ return saveServiceReference(serviceReference, moduleON);
+ }
+
+ private synchronized ObjectName saveServiceReference(ServiceReference serviceReference, ObjectName moduleON)
+ throws InstanceNotFoundException{
+ return saveServiceReference(serviceReference, moduleON, false);
+ }
+
+ private synchronized ObjectName saveServiceReference(ServiceReference serviceReference, ObjectName moduleON,
+ boolean skipChecks) throws InstanceNotFoundException {
+
+ // make sure it is found
+ if (skipChecks == false) {
+ lookupRegistry.checkConfigBeanExists(moduleON);
+ }
+ String factoryName = ObjectNameUtil.getFactoryName(moduleON);
+ String instanceName = ObjectNameUtil.getInstanceName(moduleON);
+ ModuleIdentifier moduleIdentifier = new ModuleIdentifier(factoryName, instanceName);
+
+ // check that service interface name exist
+ Set<String> serviceInterfaceQNames = factoryNamesToQNames.get(moduleIdentifier.getFactoryName());
+ if (serviceInterfaceQNames == null) {
+ logger.error("Possible error in code: cannot find factoryName {} in {}, {}", moduleIdentifier.getFactoryName(),
+ factoryNamesToQNames, moduleIdentifier);
+ throw new IllegalStateException("Possible error in code: cannot find annotations of existing factory " + moduleIdentifier.getFactoryName());
+ }
+ // supplied serviceInterfaceName must exist in this collection
+ if (serviceInterfaceQNames.contains(serviceReference.getServiceInterfaceName()) == false) {
+ logger.error("Cannot find qName {} with factory name {}, found {}", serviceReference.getServiceInterfaceName(), moduleIdentifier.getFactoryName(), serviceInterfaceQNames);
+ throw new IllegalArgumentException("Cannot find service interface " + serviceReference.getServiceInterfaceName() + " within factory " + moduleIdentifier.getFactoryName());
+ }
+
+
+ // create service reference object name, put to mBeans
+ ObjectName result = getServiceON(serviceReference);
+ Entry<ServiceReferenceMXBeanImpl, ServiceReferenceJMXRegistration> mxBeanEntry = mBeans.get(serviceReference);
+ if (mxBeanEntry == null) {
+ // create dummy mx bean
+ ServiceReferenceMXBeanImpl dummyMXBean = new ServiceReferenceMXBeanImpl(moduleON);
+ ServiceReferenceJMXRegistration dummyMXBeanRegistration;
+ try {
+ dummyMXBeanRegistration = serviceReferenceRegistrator.registerMBean(dummyMXBean, result);
+ } catch (InstanceAlreadyExistsException e) {
+ throw new IllegalStateException("Possible error in code. Cannot register " + result, e);
+ }
+ mBeans.put(serviceReference, createMXBeanEntry(dummyMXBean, dummyMXBeanRegistration));
+ } else {
+ // update
+ mxBeanEntry.getKey().setCurrentImplementation(moduleON);
+ }
+ // save to refNames
+ refNames.put(serviceReference, moduleIdentifier);
+ return result;
+ }
+
+ private Entry<ServiceReferenceMXBeanImpl, ServiceReferenceJMXRegistration> createMXBeanEntry(
+ final ServiceReferenceMXBeanImpl mxBean, final ServiceReferenceJMXRegistration registration) {
+ return new Entry<ServiceReferenceMXBeanImpl, ServiceReferenceJMXRegistration>() {
+ @Override
+ public ServiceReferenceMXBeanImpl getKey() {
+ return mxBean;
+ }
+
+ @Override
+ public ServiceReferenceJMXRegistration getValue() {
+ return registration;
+ }
+
+ @Override
+ public ServiceReferenceJMXRegistration setValue(ServiceReferenceJMXRegistration value) {
+ throw new UnsupportedOperationException();
+ }
+ };
+ }
+
+ private ObjectName getServiceON(ServiceReference serviceReference) {
+ if (writable) {
+ return ObjectNameUtil.createTransactionServiceON(serviceReferenceRegistrator.getNullableTransactionName(),
+ serviceReference.getServiceInterfaceName(), serviceReference.getRefName());
+ } else {
+ return ObjectNameUtil.createReadOnlyServiceON(serviceReference.getServiceInterfaceName(), serviceReference.getRefName());
+ }
+ }
+
+ @Override
+ public synchronized void removeServiceReference(String serviceInterfaceName, String refName) throws InstanceNotFoundException{
+ ServiceReference serviceReference = new ServiceReference(serviceInterfaceName, refName);
+ removeServiceReference(serviceReference);
+ }
+
+ private synchronized void removeServiceReference(ServiceReference serviceReference) throws InstanceNotFoundException {
+ logger.debug("Removing service reference {} from {}", serviceReference, this);
+ assertWritable();
+ // is the qName known?
+ if (allQNames.contains(serviceReference.getServiceInterfaceName()) == false) {
+ logger.error("Cannot find qname {} in {}", serviceReference.getServiceInterfaceName(), allQNames);
+ throw new IllegalArgumentException("Cannot find service interface " + serviceReference.getServiceInterfaceName());
+ }
+ ModuleIdentifier removed = refNames.remove(serviceReference);
+ if (removed == null){
+ throw new InstanceNotFoundException("Cannot find " + serviceReference.getServiceInterfaceName());
+ }
+ Entry<ServiceReferenceMXBeanImpl, ServiceReferenceJMXRegistration> entry = mBeans.remove(serviceReference);
+ if (entry == null) {
+ throw new IllegalStateException("Possible code error: cannot remove from mBeans: " + serviceReference);
+ }
+ entry.getValue().close();
+ }
+
+ @Override
+ public synchronized void removeAllServiceReferences() {
+ assertWritable();
+ for (ServiceReference serviceReference: mBeans.keySet()) {
+ try {
+ removeServiceReference(serviceReference);
+ } catch (InstanceNotFoundException e) {
+ throw new IllegalStateException("Possible error in code", e);
+ }
+ }
+ }
+
+ @Override
+ public synchronized boolean removeServiceReferences(ObjectName moduleObjectName) throws InstanceNotFoundException {
+ assertWritable();
+ Set<ServiceReference> serviceReferencesLinkingTo = findServiceReferencesLinkingTo(moduleObjectName);
+ for (ServiceReference sr : serviceReferencesLinkingTo) {
+ removeServiceReference(sr);
+ }
+ return serviceReferencesLinkingTo.isEmpty() == false;
+ }
+
+ private synchronized Set<ServiceReference> findServiceReferencesLinkingTo(ObjectName moduleObjectName) throws InstanceNotFoundException {
+ lookupRegistry.checkConfigBeanExists(moduleObjectName);
+ String factoryName = ObjectNameUtil.getFactoryName(moduleObjectName);
+ // check that service interface name exist
+ Set<String> serviceInterfaceQNames = factoryNamesToQNames.get(factoryName);
+ if (serviceInterfaceQNames == null) {
+ logger.error("Possible error in code: cannot find factoryName {} in {}, object name {}", factoryName, factoryNamesToQNames, moduleObjectName);
+ throw new IllegalStateException("Possible error in code: cannot find annotations of existing factory " + factoryName);
+ }
+ String instanceName = ObjectNameUtil.getInstanceName(moduleObjectName);
+ ModuleIdentifier moduleIdentifier = new ModuleIdentifier(factoryName, instanceName);
+ Set<ServiceReference> result = new HashSet<>();
+ for (Entry<ServiceReference, ModuleIdentifier> entry : refNames.entrySet()) {
+ if (entry.getValue().equals(moduleIdentifier)) {
+ result.add(entry.getKey());
+ }
+ }
+ return result;
+ }
+
+
+ @Override
+ public String toString() {
+ return "ServiceReferenceRegistryImpl{" +
+ "lookupRegistry=" + lookupRegistry +
+ "refNames=" + refNames +
+ ", factoryNamesToQNames=" + factoryNamesToQNames +
+ '}';
+ }
+
+ @Override
+ public void close() {
+ serviceReferenceRegistrator.close();
+ }
+}
import org.opendaylight.controller.config.api.JmxAttribute;
import org.opendaylight.controller.config.api.JmxAttributeValidationException;
import org.opendaylight.controller.config.api.ModuleIdentifier;
+import org.opendaylight.controller.config.api.ServiceReferenceReadableRegistry;
import org.opendaylight.controller.config.api.annotations.AbstractServiceInterface;
import org.opendaylight.controller.config.api.jmx.ObjectNameUtil;
import org.opendaylight.controller.config.manager.impl.TransactionStatus;
private final TransactionStatus transactionStatus;
@GuardedBy("this")
private final Set<ModuleIdentifier> dependencies = new HashSet<>();
+ private final ServiceReferenceReadableRegistry readableRegistry;
DependencyResolverImpl(ModuleIdentifier currentModule,
- TransactionStatus transactionStatus, ModulesHolder modulesHolder) {
+ TransactionStatus transactionStatus, ModulesHolder modulesHolder,
+ ServiceReferenceReadableRegistry readableRegistry) {
+
this.name = currentModule;
this.transactionStatus = transactionStatus;
this.modulesHolder = modulesHolder;
+ this.readableRegistry = readableRegistry;
}
/**
* {@inheritDoc}
*/
+ //TODO: check for cycles
@Override
public void validateDependency(
Class<? extends AbstractServiceInterface> expectedServiceInterface,
- ObjectName dependentModuleReadOnlyON, JmxAttribute jmxAttribute) {
+ ObjectName dependentReadOnlyON, JmxAttribute jmxAttribute) {
transactionStatus.checkNotCommitted();
if (expectedServiceInterface == null) {
if (jmxAttribute == null)
throw new NullPointerException("Parameter 'jmxAttribute' is null");
- JmxAttributeValidationException.checkNotNull(dependentModuleReadOnlyON,
+ JmxAttributeValidationException.checkNotNull(dependentReadOnlyON,
"is null, " + "expected dependency implementing "
+ expectedServiceInterface, jmxAttribute);
+
+
// check that objectName belongs to this transaction - this should be
// stripped
// in DynamicWritableWrapper
boolean hasTransaction = ObjectNameUtil
- .getTransactionName(dependentModuleReadOnlyON) != null;
+ .getTransactionName(dependentReadOnlyON) != null;
JmxAttributeValidationException.checkCondition(
hasTransaction == false,
format("ObjectName should not contain "
+ "transaction name. %s set to %s. ", jmxAttribute,
- dependentModuleReadOnlyON), jmxAttribute);
+ dependentReadOnlyON), jmxAttribute);
+
+ dependentReadOnlyON = translateServiceRefIfPossible(dependentReadOnlyON);
- ModuleIdentifier moduleIdentifier = ObjectNameUtil.fromON(dependentModuleReadOnlyON, ObjectNameUtil
+ ModuleIdentifier moduleIdentifier = ObjectNameUtil.fromON(dependentReadOnlyON, ObjectNameUtil
.TYPE_MODULE);
ModuleFactory foundFactory = modulesHolder.findModuleFactory(moduleIdentifier, jmxAttribute);
+ "Module name is %s : %s, expected service interface %s, dependent module ON %s , "
+ "attribute %s",
foundFactory.getImplementationName(), foundFactory,
- expectedServiceInterface, dependentModuleReadOnlyON,
+ expectedServiceInterface, dependentReadOnlyON,
jmxAttribute);
throw new JmxAttributeValidationException(message, jmxAttribute);
}
}
}
+ // transalate from serviceref to module ON
+ private ObjectName translateServiceRefIfPossible(ObjectName dependentReadOnlyON) {
+ if (ObjectNameUtil.isServiceReference(dependentReadOnlyON)) {
+ String serviceQName = ObjectNameUtil.getServiceQName(dependentReadOnlyON);
+ String refName = ObjectNameUtil.getReferenceName(dependentReadOnlyON);
+ dependentReadOnlyON = ObjectNameUtil.withoutTransactionName( // strip again of transaction name
+ readableRegistry.lookupConfigBeanByServiceInterfaceName(serviceQName, refName));
+ }
+ return dependentReadOnlyON;
+ }
+
/**
* {@inheritDoc}
*/
+ //TODO: check for cycles
@Override
- public <T> T resolveInstance(Class<T> expectedType, ObjectName dependentON,
+ public <T> T resolveInstance(Class<T> expectedType, ObjectName dependentReadOnlyON,
JmxAttribute jmxAttribute) {
- if (expectedType == null || dependentON == null || jmxAttribute == null) {
+ if (expectedType == null || dependentReadOnlyON == null || jmxAttribute == null) {
throw new IllegalArgumentException(format(
"Null parameters not allowed, got {} {} {}", expectedType,
- dependentON, jmxAttribute));
+ dependentReadOnlyON, jmxAttribute));
}
-
+ dependentReadOnlyON = translateServiceRefIfPossible(dependentReadOnlyON);
transactionStatus.checkCommitStarted();
transactionStatus.checkNotCommitted();
ModuleIdentifier dependentModuleIdentifier = ObjectNameUtil.fromON(
- dependentON, ObjectNameUtil.TYPE_MODULE);
+ dependentReadOnlyON, ObjectNameUtil.TYPE_MODULE);
Module module = modulesHolder.findModule(dependentModuleIdentifier,
jmxAttribute);
synchronized (this) {
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.ServiceReferenceReadableRegistry;
import org.opendaylight.controller.config.manager.impl.CommitInfo;
import org.opendaylight.controller.config.manager.impl.ModuleInternalTransactionalInfo;
import org.opendaylight.controller.config.manager.impl.TransactionStatus;
private final Map<ModuleIdentifier, DependencyResolverImpl> moduleIdentifiersToDependencyResolverMap = new HashMap<>();
private final ModulesHolder modulesHolder;
private final TransactionStatus transactionStatus;
+ private final ServiceReferenceReadableRegistry readableRegistry;
public DependencyResolverManager(String transactionName,
- TransactionStatus transactionStatus) {
+ TransactionStatus transactionStatus, ServiceReferenceReadableRegistry readableRegistry) {
this.modulesHolder = new ModulesHolder(transactionName);
this.transactionStatus = transactionStatus;
+ this.readableRegistry = readableRegistry;
}
@Override
}
public synchronized DependencyResolverImpl getOrCreate(ModuleIdentifier name) {
- DependencyResolverImpl dependencyResolver = moduleIdentifiersToDependencyResolverMap
- .get(name);
+ DependencyResolverImpl dependencyResolver = moduleIdentifiersToDependencyResolverMap.get(name);
if (dependencyResolver == null) {
transactionStatus.checkNotCommitted();
- dependencyResolver = new DependencyResolverImpl(name,
- transactionStatus, modulesHolder);
- moduleIdentifiersToDependencyResolverMap.put(name,
- dependencyResolver);
+ dependencyResolver = new DependencyResolverImpl(name, transactionStatus, modulesHolder, readableRegistry);
+ moduleIdentifiersToDependencyResolverMap.put(name, dependencyResolver);
}
return dependencyResolver;
}
*/
package org.opendaylight.controller.config.manager.impl.dynamicmbean;
-import static java.lang.String.format;
-
-import java.lang.reflect.Method;
-import java.util.ArrayList;
-import java.util.Arrays;
-import java.util.HashMap;
-import java.util.HashSet;
-import java.util.List;
-import java.util.Map;
-import java.util.Set;
+import org.opendaylight.controller.config.api.ModuleIdentifier;
+import org.opendaylight.controller.config.api.annotations.Description;
+import org.opendaylight.controller.config.api.annotations.RequireInterface;
+import org.opendaylight.controller.config.api.jmx.ObjectNameUtil;
+import org.opendaylight.controller.config.manager.impl.util.InterfacesHelper;
+import org.opendaylight.controller.config.spi.Module;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
import javax.management.Attribute;
import javax.management.AttributeList;
import javax.management.NotificationListener;
import javax.management.ObjectName;
import javax.management.ReflectionException;
+import java.lang.reflect.Array;
+import java.lang.reflect.Method;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
-import org.opendaylight.controller.config.api.ModuleIdentifier;
-import org.opendaylight.controller.config.api.annotations.Description;
-import org.opendaylight.controller.config.api.annotations.RequireInterface;
-import org.opendaylight.controller.config.api.jmx.ObjectNameUtil;
-import org.opendaylight.controller.config.manager.impl.util.InterfacesHelper;
-import org.opendaylight.controller.config.spi.Module;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
+import static java.lang.String.format;
/**
* Contains common code for readable/rw dynamic mbean wrappers. Routes all
} catch (InstanceNotFoundException e) {
new MBeanException(e);
}
+
if (obj instanceof ObjectName) {
AttributeHolder attributeHolder = attributeHolderMap
.get(attributeName);
}
return obj;
}
+
+
+ if(isDependencyListAttr(attributeName, obj)) {
+ obj = fixDependencyListAttribute(obj);
+ }
+
return obj;
+ }
+
+ private Object fixDependencyListAttribute(Object attribute) {
+ 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)
+ throw new IllegalArgumentException("Unexpected attribute type, should be an ObjectName, but was " + on.getClass());
+ on = fixObjectName((ObjectName) on);
+
+ Array.set(attribute, i, on);
+ }
+
+ return attribute;
+ }
+
+ private boolean isDependencyListAttr(String attributeName, Object attribute) {
+ if (attributeHolderMap.containsKey(attributeName) == false)
+ return false;
+
+ AttributeHolder attributeHolder = attributeHolderMap.get(attributeName);
+ boolean isDepList = true;
+ isDepList &= attributeHolder.getRequireInterfaceOrNull() != null;
+ isDepList &= attribute instanceof ObjectName[];
+ return isDepList;
}
protected ObjectName fixObjectName(ObjectName on) {
*/
package org.opendaylight.controller.config.manager.impl.dynamicmbean;
-import java.lang.reflect.Method;
-import java.util.HashSet;
-import java.util.List;
-import java.util.Set;
+import org.opendaylight.controller.config.api.annotations.Description;
+import org.opendaylight.controller.config.api.annotations.RequireInterface;
import javax.annotation.Nullable;
import javax.annotation.concurrent.Immutable;
import javax.management.MBeanAttributeInfo;
import javax.management.ObjectName;
-
-import org.opendaylight.controller.config.api.annotations.Description;
-import org.opendaylight.controller.config.api.annotations.RequireInterface;
+import java.lang.reflect.Method;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Set;
@Immutable
class AttributeHolder {
private final RequireInterface requireInterfaceAnnotation;
private final String attributeType;
+ public static final Set<Class<?>> PERMITTED_PARAMETER_TYPES_FOR_DEPENDENCY_SETTER = new HashSet<>();
+
+ static {
+ PERMITTED_PARAMETER_TYPES_FOR_DEPENDENCY_SETTER.add(ObjectName.class);
+ PERMITTED_PARAMETER_TYPES_FOR_DEPENDENCY_SETTER.add(ObjectName[].class);
+ PERMITTED_PARAMETER_TYPES_FOR_DEPENDENCY_SETTER.add(List.class);
+ }
+
public AttributeHolder(String name, Object object, String returnType,
boolean writable,
@Nullable RequireInterface requireInterfaceAnnotation,
static RequireInterface findRequireInterfaceAnnotation(final Method setter,
Set<Class<?>> inspectedInterfaces) {
- // only allow setX(ObjectName y) or setX(ObjectName[] y) to continue
- if (setter.getParameterTypes().length != 1
- || (setter.getParameterTypes()[0].equals(ObjectName.class) == false && setter
- .getParameterTypes()[0].equals(ObjectName[].class) == false)) {
+ // only allow setX(ObjectName y) or setX(ObjectName[] y) or setX(List<ObjectName> y) to continue
+
+ if (setter.getParameterTypes().length > 1)
+ return null;
+ if(PERMITTED_PARAMETER_TYPES_FOR_DEPENDENCY_SETTER.contains(setter.getParameterTypes()[0]) == false)
return null;
- }
List<RequireInterface> foundRequireInterfaces = AnnotationsHelper
.findMethodAnnotationInSuperClassesAndIfcs(setter, RequireInterface.class, inspectedInterfaces);
*/
package org.opendaylight.controller.config.manager.impl.dynamicmbean;
-import java.lang.reflect.Method;
+import org.opendaylight.controller.config.api.ModuleIdentifier;
+import org.opendaylight.controller.config.api.ValidationException;
+import org.opendaylight.controller.config.api.jmx.ObjectNameUtil;
+import org.opendaylight.controller.config.manager.impl.TransactionIdentifier;
+import org.opendaylight.controller.config.spi.Module;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
import javax.annotation.concurrent.ThreadSafe;
import javax.management.Attribute;
import javax.management.MBeanServer;
import javax.management.ObjectName;
import javax.management.ReflectionException;
-
-import org.opendaylight.controller.config.api.ModuleIdentifier;
-import org.opendaylight.controller.config.api.ValidationException;
-import org.opendaylight.controller.config.api.jmx.ObjectNameUtil;
-import org.opendaylight.controller.config.manager.impl.TransactionIdentifier;
-import org.opendaylight.controller.config.spi.Module;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
+import java.lang.reflect.Method;
/**
* Wraps {@link org.opendaylight.controller.config.spi.Module} instance in a
try {
if (attribute.getValue() instanceof ObjectName) {
- AttributeHolder attributeHolder = attributeHolderMap
- .get(attribute.getName());
- if (attributeHolder.getRequireInterfaceOrNull() != null) {
- attribute = new Attribute(attribute.getName(),
- fixObjectName((ObjectName) attribute.getValue()));
- } else {
- attribute = new Attribute(attribute.getName(),
- attribute.getValue());
- }
+ attribute = fixDependencyAttribute(attribute);
+ } else if(attribute.getValue() instanceof ObjectName[]) {
+ attribute = fixDependencyListAttribute(attribute);
}
+
internalServer.setAttribute(objectNameInternal, attribute);
} catch (InstanceNotFoundException e) {
throw new MBeanException(e);
}
+ private Attribute fixDependencyListAttribute(Attribute attribute) {
+ AttributeHolder attributeHolder = attributeHolderMap
+ .get(attribute.getName());
+ if (attributeHolder.getRequireInterfaceOrNull() != null) {
+ attribute = new Attribute(attribute.getName(),
+ fixObjectNames((ObjectName[]) attribute.getValue()));
+ }
+ return attribute;
+ }
+
+ private Attribute fixDependencyAttribute(Attribute attribute) {
+ AttributeHolder attributeHolder = attributeHolderMap
+ .get(attribute.getName());
+ if (attributeHolder.getRequireInterfaceOrNull() != null) {
+ attribute = new Attribute(attribute.getName(),
+ fixObjectName((ObjectName) attribute.getValue()));
+ } else {
+ attribute = new Attribute(attribute.getName(),
+ attribute.getValue());
+ }
+ return attribute;
+ }
+
+ private ObjectName[] fixObjectNames(ObjectName[] dependencies) {
+ int i = 0;
+
+ for (ObjectName dependencyOn : dependencies) {
+ dependencies[i++] = fixObjectName(dependencyOn);
+ }
+
+ return dependencies;
+ }
+
@Override
public AttributeList setAttributes(AttributeList attributes) {
AttributeList result = new AttributeList();
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
+import java.util.Map.Entry;
import java.util.Set;
import java.util.List;
import java.util.Map;
return moduleFactories;
}
+ public Map<String, Entry<ModuleFactory, BundleContext>> getModuleNamesToConfigBeanFactories() {
+ return moduleNamesToConfigBeanFactories;
+ }
}
import javax.management.QueryExp;
import java.util.Set;
-public class BaseJMXRegistrator implements AutoCloseable {
+public class BaseJMXRegistrator implements AutoCloseable, NestableJMXRegistrator {
private final InternalJMXRegistrator internalJMXRegistrator;
return internalJMXRegistrator.getRegisteredObjectNames();
}
+ @Override
+ public InternalJMXRegistrator createChild() {
+ return internalJMXRegistrator.createChild();
+ }
+
@Override
public void close() {
internalJMXRegistrator.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.netconf.ssh.authentication;
+package org.opendaylight.controller.config.manager.impl.jmx;
-import ch.ethz.ssh2.signature.RSAPrivateKey;
+public interface NestableJMXRegistrator {
-public interface KeyStoreHandler {
- public RSAPrivateKey getPrivateKey();
+ InternalJMXRegistrator createChild();
}
--- /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.jmx;
+
+public class ServiceReference {
+ private final String serviceInterfaceName, refName;
+
+ public ServiceReference(String serviceInterfaceName, String refName) {
+ this.serviceInterfaceName = serviceInterfaceName;
+ this.refName = refName;
+ }
+
+ public String getServiceInterfaceName() {
+ return serviceInterfaceName;
+ }
+
+ public String getRefName() {
+ return refName;
+ }
+
+ @Override
+ public boolean equals(Object o) {
+ 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;
+
+ return true;
+ }
+
+ @Override
+ public int hashCode() {
+ int result = serviceInterfaceName.hashCode();
+ result = 31 * result + refName.hashCode();
+ return result;
+ }
+}
--- /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.jmx;
+
+import javax.management.ObjectName;
+
+public interface ServiceReferenceMXBean {
+
+ ObjectName getCurrentImplementation();
+
+}
--- /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.jmx;
+
+import javax.management.ObjectName;
+
+public class ServiceReferenceMXBeanImpl implements ServiceReferenceMXBean {
+ private ObjectName currentImplementation;
+
+ public ServiceReferenceMXBeanImpl(ObjectName currentImplementation) {
+ this.currentImplementation = currentImplementation;
+ }
+
+ @Override
+ public ObjectName getCurrentImplementation() {
+ return currentImplementation;
+ }
+
+ public void setCurrentImplementation(ObjectName currentImplementation) {
+ this.currentImplementation = currentImplementation;
+ }
+}
--- /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.jmx;
+
+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;
+
+public interface ServiceReferenceRegistrator extends AutoCloseable {
+
+ public String getNullableTransactionName();
+
+ ServiceReferenceJMXRegistration registerMBean(ServiceReferenceMXBeanImpl object,
+ ObjectName on) throws InstanceAlreadyExistsException;
+
+ @Override
+ void close();
+
+ public static class ServiceReferenceJMXRegistration implements AutoCloseable {
+ private final InternalJMXRegistration registration;
+
+ ServiceReferenceJMXRegistration(InternalJMXRegistration registration) {
+ this.registration = registration;
+ }
+
+ @Override
+ public void close() {
+ registration.close();
+ }
+ }
+
+ public static interface ServiceReferenceTransactionRegistratorFactory {
+ public ServiceReferenceRegistrator create();
+ }
+
+ public static class ServiceReferenceRegistratorImpl implements ServiceReferenceRegistrator {
+ private final InternalJMXRegistrator currentJMXRegistrator;
+ private final String nullableTransactionName;
+
+ public ServiceReferenceRegistratorImpl(NestableJMXRegistrator parentRegistrator, String nullableTransactionName){
+ currentJMXRegistrator = parentRegistrator.createChild();
+ this.nullableTransactionName = nullableTransactionName;
+ }
+
+ public String getNullableTransactionName() {
+ return nullableTransactionName;
+ }
+
+
+ public ServiceReferenceJMXRegistration registerMBean(ServiceReferenceMXBeanImpl object,
+ ObjectName on) throws InstanceAlreadyExistsException {
+ String actualTransactionName = ObjectNameUtil.getTransactionName(on);
+ boolean broken = false;
+ broken |= (nullableTransactionName == null) != (actualTransactionName == null);
+ broken |= (nullableTransactionName != null) && nullableTransactionName.equals(actualTransactionName) == false;
+ if (broken) {
+ throw new IllegalArgumentException("Transaction name mismatch between expected "
+ + nullableTransactionName + ", got " + actualTransactionName + " in " + on);
+ }
+ if (ObjectNameUtil.isServiceReference(on) == false) {
+ throw new IllegalArgumentException("Invalid type of " + on);
+ }
+ return new ServiceReferenceJMXRegistration(currentJMXRegistrator.registerMBean(object, on));
+ }
+
+
+ @Override
+ public void close() {
+ currentJMXRegistrator.close();
+ }
+ public static interface ServiceReferenceTransactionRegistratorFactory {
+ public ServiceReferenceRegistrator create();
+ }
+ }
+
+
+ public static class ServiceReferenceTransactionRegistratorFactoryImpl implements ServiceReferenceTransactionRegistratorFactory {
+ private final NestableJMXRegistrator parentRegistrator;
+ private final String nullableTransactionName;
+
+ public ServiceReferenceTransactionRegistratorFactoryImpl(TransactionModuleJMXRegistrator parentRegistrator,
+ String nullableTransactionName) {
+ this.parentRegistrator = parentRegistrator;
+ this.nullableTransactionName = nullableTransactionName;
+ }
+
+ public ServiceReferenceTransactionRegistratorFactoryImpl(BaseJMXRegistrator baseJMXRegistrator) {
+ this.parentRegistrator = baseJMXRegistrator;
+ this.nullableTransactionName = null;
+ }
+
+ public ServiceReferenceRegistrator create() {
+ return new ServiceReferenceRegistratorImpl(parentRegistrator, nullableTransactionName);
+ }
+ }
+}
}
@Override
- public void close() {
+ public void close() { // closes also all child TransactionModuleJMXRegistrator instances
childJMXRegistrator.close();
}
}
import org.opendaylight.controller.config.api.jmx.ObjectNameUtil;
import org.opendaylight.controller.config.manager.impl.jmx.InternalJMXRegistrator.InternalJMXRegistration;
-public class TransactionModuleJMXRegistrator implements Closeable {
- private final InternalJMXRegistrator childJMXRegistrator;
+public class TransactionModuleJMXRegistrator implements Closeable, NestableJMXRegistrator {
+ private final InternalJMXRegistrator currentJMXRegistrator;
private final String transactionName;
public TransactionModuleJMXRegistrator(
InternalJMXRegistrator internalJMXRegistrator,
String transactionName) {
- this.childJMXRegistrator = internalJMXRegistrator.createChild();
+ this.currentJMXRegistrator = internalJMXRegistrator.createChild();
this.transactionName = transactionName;
}
public TransactionModuleJMXRegistration registerMBean(Object object,
ObjectName on) throws InstanceAlreadyExistsException {
- if (!transactionName.equals(ObjectNameUtil.getTransactionName(on)))
- throw new IllegalArgumentException(
- "Transaction name mismatch between expected "
+ if (transactionName.equals(ObjectNameUtil.getTransactionName(on)) == false) {
+ throw new IllegalArgumentException("Transaction name mismatch between expected "
+ transactionName + " " + "and " + on);
- ObjectNameUtil.checkType(on, ObjectNameUtil.TYPE_MODULE);
+ }
+ ObjectNameUtil.checkTypeOneOf(on, ObjectNameUtil.TYPE_MODULE);
return new TransactionModuleJMXRegistration(
- childJMXRegistrator.registerMBean(object, on));
+ currentJMXRegistrator.registerMBean(object, on));
}
public Set<ObjectName> queryNames(ObjectName name, QueryExp query) {
- return childJMXRegistrator.queryNames(name, query);
+ return currentJMXRegistrator.queryNames(name, query);
}
@Override
public void close() {
- childJMXRegistrator.close();
+ currentJMXRegistrator.close();
+ }
+
+ public String getTransactionName() {
+ return transactionName;
+ }
+
+ public InternalJMXRegistrator createChild() {
+ return currentJMXRegistrator.createChild();
}
}
new BundleContextBackedModuleFactoriesResolver(context);
MBeanServer configMBeanServer = ManagementFactory.getPlatformMBeanServer();
configRegistry = new ConfigRegistryImpl(
- bundleContextBackedModuleFactoriesResolver, context,
- configMBeanServer);
+ bundleContextBackedModuleFactoriesResolver, configMBeanServer);
// register config registry to OSGi
configRegistryServiceRegistration = context.registerService(ConfigRegistryImpl.class, configRegistry, null);
*/
package org.opendaylight.controller.config.manager.impl.util;
+import org.opendaylight.controller.config.api.annotations.AbstractServiceInterface;
+import org.opendaylight.controller.config.api.annotations.ServiceInterfaceAnnotation;
+import org.opendaylight.controller.config.spi.Module;
+import org.opendaylight.controller.config.spi.ModuleFactory;
+
+import javax.management.JMX;
import java.util.Arrays;
+import java.util.Collections;
import java.util.HashSet;
import java.util.Iterator;
import java.util.Set;
-import javax.management.JMX;
-
-import org.opendaylight.controller.config.api.annotations.AbstractServiceInterface;
-import org.opendaylight.controller.config.api.annotations.ServiceInterfaceAnnotation;
-import org.opendaylight.controller.config.spi.Module;
-
public class InterfacesHelper {
public static Set<Class<?>> getAllInterfaces(Class<?> clazz) {
// get parent class
clazz = clazz.getSuperclass();
}
+ return getAllSuperInterfaces(toBeInspected);
+
+ }
+
+ private static Set<Class<?>> getAllSuperInterfaces(Set<Class<?>> ifcs) {
+ ifcs = new HashSet<>(ifcs); // create copy to modify
// each interface can extend other interfaces
- Set<Class<?>> inspected = new HashSet<>();
- while (toBeInspected.size() > 0) {
- Iterator<Class<?>> iterator = toBeInspected.iterator();
+ Set<Class<?>> result = new HashSet<>();
+ while (ifcs.size() > 0) {
+ Iterator<Class<?>> iterator = ifcs.iterator();
Class<?> ifc = iterator.next();
iterator.remove();
- toBeInspected.addAll(Arrays.asList(ifc.getInterfaces()));
- inspected.add(ifc);
+ if (ifc.isInterface() == false) {
+ throw new IllegalArgumentException(ifc + " should be an interface");
+ }
+ ifcs.addAll(Arrays.asList(ifc.getInterfaces()));
+ result.add(ifc);
}
- return inspected;
+ return result;
}
/**
return result;
}
+ public static Set<Class<? extends AbstractServiceInterface>> getAllAbstractServiceClasses(Class<? extends Module> configBeanClass) {
+
+ Set<Class<? extends AbstractServiceInterface>> foundGeneratedSIClasses = new HashSet<>();
+ for (Class<?> clazz : getAllInterfaces(configBeanClass)) {
+ if (AbstractServiceInterface.class.isAssignableFrom(clazz) && AbstractServiceInterface.class.equals(clazz) == false) {
+ foundGeneratedSIClasses.add((Class<? extends AbstractServiceInterface>) clazz);
+ }
+ }
+ return getAllAbstractServiceInterfaceClasses(foundGeneratedSIClasses);
+ }
+
+
/**
* Get OSGi registration types under which config bean instance should be
* registered. This is specified in
return result;
}
+
+ public static Set<ServiceInterfaceAnnotation> getServiceInterfaceAnnotations(ModuleFactory factory) {
+ Set<Class<? extends AbstractServiceInterface>> implementedServiceIntefaces = Collections.unmodifiableSet(factory.getImplementedServiceIntefaces());
+ return getServiceInterfaceAnnotations(implementedServiceIntefaces);
+ }
+
+ private static Set<ServiceInterfaceAnnotation> getServiceInterfaceAnnotations(Set<Class<? extends AbstractServiceInterface>> implementedServiceIntefaces) {
+ Set<Class<? extends AbstractServiceInterface>> inspected = getAllAbstractServiceInterfaceClasses(implementedServiceIntefaces);
+ Set<ServiceInterfaceAnnotation> result = new HashSet<>();
+ // SIs can form hierarchies, inspect superclass until it does not extend AbstractSI
+ for (Class<?> clazz : inspected) {
+ ServiceInterfaceAnnotation annotation = clazz.getAnnotation(ServiceInterfaceAnnotation.class);
+ if (annotation != null) {
+ result.add(annotation);
+ }
+ }
+ return result;
+ }
+
+ static Set<Class<? extends AbstractServiceInterface>> getAllAbstractServiceInterfaceClasses(
+ Set<Class<? extends AbstractServiceInterface>> directlyImplementedAbstractSIs) {
+
+ Set<Class<?>> allInterfaces = getAllSuperInterfaces((Set) directlyImplementedAbstractSIs);
+ Set<Class<? extends AbstractServiceInterface>> result = new HashSet<>();
+ for(Class<?> ifc: allInterfaces){
+ if (AbstractServiceInterface.class.isAssignableFrom(ifc) &&
+ ifc.equals(AbstractServiceInterface.class) == false) {
+ result.add((Class<? extends AbstractServiceInterface>) ifc);
+ }
+
+ }
+ return result;
+ }
}
--- /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.util;
+
+import org.opendaylight.controller.config.spi.ModuleFactory;
+import org.opendaylight.yangtools.yang.binding.annotations.ModuleQName;
+import org.osgi.framework.BundleContext;
+
+import java.util.HashSet;
+import java.util.Map;
+import java.util.Map.Entry;
+import java.util.Set;
+
+public class ModuleQNameUtil {
+
+ public static Set<String> getQNames(Map<String, Entry<ModuleFactory, BundleContext>> resolved) {
+ Set<String> result = new HashSet<>();
+ for (Entry<ModuleFactory, BundleContext> entry : resolved.values()) {
+ Class<?> inspected = entry.getKey().getClass();
+ if (inspected.isInterface()) {
+ throw new IllegalArgumentException("Unexpected interface " + inspected);
+ }
+ ModuleQName annotation = null;
+ while(annotation == null && inspected != null) {
+ annotation = inspected.getAnnotation(ModuleQName.class);
+ inspected = inspected.getSuperclass();
+ }
+ if (annotation != null) {
+ // FIXME
+ String qName = "(" + annotation.namespace() + "?revision=" + annotation.revision() + ")" + annotation.name();
+ result.add(qName);
+ }
+ }
+ return result;
+ }
+
+}
factory, factory);
configRegistry = new ConfigRegistryImpl(resolver,
- context, ManagementFactory.getPlatformMBeanServer());
+ ManagementFactory.getPlatformMBeanServer());
configRegistry.beginConfig();
fail();
*/
package org.opendaylight.controller.config.manager.impl;
+import com.google.common.base.Preconditions;
+import com.google.common.collect.Maps;
+import junit.framework.Assert;
import org.junit.After;
import org.mockito.Matchers;
+import org.mockito.invocation.InvocationOnMock;
+import org.mockito.stubbing.Answer;
import org.opendaylight.controller.config.api.jmx.CommitStatus;
import org.opendaylight.controller.config.manager.impl.factoriesresolver.ModuleFactoriesResolver;
import org.opendaylight.controller.config.manager.impl.jmx.BaseJMXRegistrator;
import org.opendaylight.controller.config.manager.impl.jmx.ConfigRegistryJMXRegistrator;
import org.opendaylight.controller.config.manager.impl.jmx.InternalJMXRegistrator;
+import org.opendaylight.controller.config.manager.testingservices.scheduledthreadpool.TestingScheduledThreadPoolImpl;
+import org.opendaylight.controller.config.manager.testingservices.threadpool.TestingFixedThreadPool;
import org.opendaylight.controller.config.spi.Module;
import org.opendaylight.controller.config.util.ConfigRegistryJMXClient;
import org.opendaylight.controller.config.util.ConfigTransactionJMXClient;
import javax.management.MBeanServer;
import javax.management.ObjectName;
import java.io.Closeable;
+import java.io.InputStream;
import java.lang.management.ManagementFactory;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.Collections;
import java.util.Dictionary;
+import java.util.List;
+import java.util.Map;
import java.util.Set;
import static org.junit.Assert.assertEquals;
import static org.mockito.Matchers.any;
+import static org.mockito.Mockito.doAnswer;
import static org.mockito.Mockito.doNothing;
-import static org.mockito.Mockito.doReturn;
import static org.mockito.Mockito.mock;
/**
protected BundleContext mockedContext = mock(BundleContext.class);
protected ServiceRegistration<?> mockedServiceRegistration;
+ protected Map<Class, BundleContextServiceRegistrationHandler> getBundleContextServiceRegistrationHandlers() {
+ return Maps.newHashMap();
+ }
+
// this method should be called in @Before
protected void initConfigTransactionManagerImpl(
ModuleFactoriesResolver resolver) {
configRegistryJMXRegistrator = new ConfigRegistryJMXRegistrator(
platformMBeanServer);
- this.mockedServiceRegistration = mock(ServiceRegistration.class);
- doNothing().when(mockedServiceRegistration).unregister();
- doReturn(mockedServiceRegistration).when(mockedContext).registerService(
- Matchers.any(String[].class), any(Closeable.class),
- any(Dictionary.class));
+ initBundleContext();
internalJmxRegistrator = new InternalJMXRegistrator(platformMBeanServer);
baseJmxRegistrator = new BaseJMXRegistrator(internalJmxRegistrator);
- configRegistry = new ConfigRegistryImpl(resolver, mockedContext,
+ configRegistry = new ConfigRegistryImpl(resolver,
platformMBeanServer, baseJmxRegistrator);
+
try {
configRegistryJMXRegistrator.registerToJMX(configRegistry);
} catch (InstanceAlreadyExistsException e) {
configRegistryClient = new ConfigRegistryJMXClient(platformMBeanServer);
}
+ private void initBundleContext() {
+ this.mockedServiceRegistration = mock(ServiceRegistration.class);
+ doNothing().when(mockedServiceRegistration).unregister();
+
+ RegisterServiceAnswer answer = new RegisterServiceAnswer();
+
+ doAnswer(answer).when(mockedContext).registerService(Matchers.any(String[].class),
+ any(Closeable.class), Matchers.<Dictionary<String, ?>>any());
+ doAnswer(answer).when(mockedContext).registerService(Matchers.<Class<Closeable>>any(), any(Closeable.class),
+ Matchers.<Dictionary<String, ?>>any());
+ }
+
+
+ public Collection<InputStream> getFilesAsInputStreams(List<String> paths) {
+ final Collection<InputStream> resources = new ArrayList<>();
+ List<String> failedToFind = new ArrayList<>();
+ for (String path : paths) {
+ InputStream resourceAsStream = getClass().getResourceAsStream(path);
+ if (resourceAsStream == null) {
+ failedToFind.add(path);
+ } else {
+ resources.add(resourceAsStream);
+ }
+ }
+ Assert.assertEquals("Some files were not found", Collections.<String>emptyList(), failedToFind);
+
+ return resources;
+ }
+
@After
public final void cleanUpConfigTransactionManagerImpl() {
configRegistryJMXRegistrator.close();
configRegistry.close();
+ TestingFixedThreadPool.cleanUp();
+ TestingScheduledThreadPoolImpl.cleanUp();
}
/**
protected void assertStatus(CommitStatus status, int expectedNewInstances,
int expectedRecreatedInstances, int expectedReusedInstances) {
- assertEquals(expectedNewInstances, status.getNewInstances().size());
- assertEquals(expectedRecreatedInstances, status.getRecreatedInstances()
+ assertEquals("New instances mismatch in " + status, expectedNewInstances, status.getNewInstances().size());
+ assertEquals("Recreated instances mismatch in " + status, expectedRecreatedInstances, status.getRecreatedInstances()
.size());
- assertEquals(expectedReusedInstances, status.getReusedInstances()
+ assertEquals("Reused instances mismatch in " + status, expectedReusedInstances, status.getReusedInstances()
.size());
}
Class<? extends Module> configBeanClass, String implementationName) {
return new ClassBasedModuleFactory(implementationName, configBeanClass);
}
+
+
+ public static interface BundleContextServiceRegistrationHandler {
+
+ void handleServiceRegistration(Object serviceInstance);
+
+ }
+
+ private class RegisterServiceAnswer implements Answer {
+ @Override
+ public Object answer(InvocationOnMock invocation) throws Throwable {
+ Object[] args = invocation.getArguments();
+
+ Preconditions.checkArgument(args.length == 3);
+
+ Preconditions.checkArgument(args[0] instanceof Class);
+ Class<?> serviceType = (Class<?>) args[0];
+ Object serviceInstance = args[1];
+
+ BundleContextServiceRegistrationHandler serviceRegistrationHandler = getBundleContextServiceRegistrationHandlers()
+ .get(serviceType);
+
+ Preconditions.checkArgument(serviceType.isAssignableFrom(serviceInstance.getClass()));
+
+ if (serviceRegistrationHandler != null) {
+ serviceRegistrationHandler.handleServiceRegistration(serviceType.cast(serviceInstance));
+ }
+
+ return mockedServiceRegistration;
+ }
+ }
}
+++ /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;
-
-import org.junit.After;
-import org.junit.Before;
-import org.opendaylight.controller.config.manager.impl.factoriesresolver.ModuleFactoriesResolver;
-import org.opendaylight.controller.config.util.JolokiaHelper;
-import org.opendaylight.controller.config.util.jolokia.ConfigRegistryJolokiaClient;
-
-public class AbstractConfigWithJolokiaTest extends AbstractConfigTest {
- protected String jolokiaURL;
- protected ConfigRegistryJolokiaClient configRegistryJolokiaClient;
-
- @Before
- public void initJolokia() {
- jolokiaURL = JolokiaHelper.startTestingJolokia();
- }
-
- // this method should be called in @Before
- @Override
- protected void initConfigTransactionManagerImpl(
- ModuleFactoriesResolver resolver) {
- super.initConfigTransactionManagerImpl(resolver);
- configRegistryJolokiaClient = new ConfigRegistryJolokiaClient(
- jolokiaURL);
- }
-
- @After
- public void cleanUpJolokia() {
- JolokiaHelper.stopJolokia();
- }
-}
import org.opendaylight.controller.config.api.DynamicMBeanWithInstance;
import org.opendaylight.controller.config.api.ModuleIdentifier;
import org.opendaylight.controller.config.api.annotations.AbstractServiceInterface;
+import org.opendaylight.controller.config.manager.impl.util.InterfacesHelper;
import org.opendaylight.controller.config.spi.Module;
import org.opendaylight.controller.config.spi.ModuleFactory;
import org.osgi.framework.BundleContext;
public Set<Module> getDefaultModules(DependencyResolverFactory dependencyResolverFactory, BundleContext bundleContext) {
return new HashSet<Module>();
}
+
+ @Override
+ public Set<Class<? extends AbstractServiceInterface>> getImplementedServiceIntefaces() {
+ return InterfacesHelper.getAllAbstractServiceClasses(configBeanClass);
+ }
}
@Before
public void setUp() throws Exception {
- configRegistryImpl = new ConfigRegistryImpl(null, null,
+ configRegistryImpl = new ConfigRegistryImpl(null,
ManagementFactory.getPlatformMBeanServer());
Field field = configRegistryImpl.getClass().getDeclaredField(
"baseJMXRegistrator");
import org.junit.After;
import org.junit.Before;
import org.junit.Test;
+import org.opendaylight.controller.config.api.ServiceReferenceWritableRegistry;
import org.opendaylight.controller.config.api.jmx.ObjectNameUtil;
import org.opendaylight.controller.config.manager.impl.jmx.BaseJMXRegistrator;
import org.opendaylight.controller.config.manager.impl.jmx.TransactionJMXRegistrator;
ManagementFactory.getPlatformMBeanServer());
transactionsMBeanServer = MBeanServerFactory.createMBeanServer();
Map<String, Map.Entry<ModuleFactory, BundleContext>> currentlyRegisteredFactories = new HashMap<>();
- TransactionJMXRegistrator jmxRegistrator123 = baseJMXRegistrator
- .createTransactionJMXRegistrator(transactionName123);
+
+ ConfigTransactionLookupRegistry txLookupRegistry = new ConfigTransactionLookupRegistry(new TransactionIdentifier(transactionName123), new TransactionJMXRegistratorFactory() {
+ @Override
+ public TransactionJMXRegistrator create() {
+ return baseJMXRegistrator.createTransactionJMXRegistrator(transactionName123);
+ }
+ }, currentlyRegisteredFactories);
+
+ ServiceReferenceWritableRegistry writableRegistry = ServiceReferenceRegistryImpl.createSRWritableRegistry(
+ ServiceReferenceRegistryImpl.createInitialSRLookupRegistry(), txLookupRegistry, currentlyRegisteredFactories);
+
testedTxController = new ConfigTransactionControllerImpl(
- transactionName123, jmxRegistrator123, 1, 1,
+ txLookupRegistry, 1, 1,
currentlyRegisteredFactories, transactionsMBeanServer,
- ManagementFactory.getPlatformMBeanServer(), false);
+ ManagementFactory.getPlatformMBeanServer(), false, writableRegistry);
TransactionModuleJMXRegistrator transactionModuleJMXRegistrator123 = testedTxController
.getTxModuleJMXRegistrator();
transactionModuleJMXRegistrator123.registerMBean(
*/
package org.opendaylight.controller.config.manager.impl;
-import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertTrue;
-import static org.junit.Assert.fail;
-import static org.mockito.Mockito.mock;
-
-import javax.management.InstanceAlreadyExistsException;
-
import org.junit.Before;
import org.junit.Test;
-import org.opendaylight.controller.config.api.jmx.ObjectNameUtil;
-import org.opendaylight.controller.config.api.jmx.constants.ConfigRegistryConstants;
import org.opendaylight.controller.config.manager.impl.factoriesresolver.HardcodedModuleFactoriesResolver;
import org.opendaylight.controller.config.util.ConfigTransactionJMXClient;
-import org.opendaylight.controller.config.util.jolokia.ConfigTransactionJolokiaClient;
+
+import javax.management.InstanceAlreadyExistsException;
+
+import static org.junit.Assert.assertTrue;
+import static org.junit.Assert.fail;
+import static org.mockito.Mockito.mock;
public class ConfigTransactionManagerImplTest extends
- AbstractConfigWithJolokiaTest {
+ AbstractConfigTest {
@Before
public void setUp() {
transaction.commit();
}
- @Test
- public void testRemoteCallsUsingJolokia() throws Exception {
-
- ConfigTransactionJolokiaClient transactionClient = configRegistryJolokiaClient
- .createTransaction();
-
- assertEquals("ConfigTransaction-0-1",
- ObjectNameUtil.getTransactionName(transactionClient
- .getTransactionON()));
-
- assertEquals(
- ConfigRegistryConstants.ON_DOMAIN
- + ":TransactionName=ConfigTransaction-0-1,type=ConfigTransaction",
- transactionClient.getTransactionON().getCanonicalName());
-
- // commit
- transactionClient.commit();
-
- }
}
--- /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;
+
+import com.google.common.collect.ImmutableMap;
+import org.junit.Before;
+import org.junit.Test;
+import org.opendaylight.controller.config.api.jmx.ObjectNameUtil;
+import org.opendaylight.controller.config.manager.impl.factoriesresolver.HardcodedModuleFactoriesResolver;
+import org.opendaylight.controller.config.manager.impl.jmx.ServiceReferenceMXBean;
+import org.opendaylight.controller.config.manager.testingservices.parallelapsp.TestingParallelAPSPModuleFactory;
+import org.opendaylight.controller.config.manager.testingservices.parallelapsp.test.AbstractParallelAPSPTest;
+import org.opendaylight.controller.config.manager.testingservices.scheduledthreadpool.TestingScheduledThreadPoolModuleFactory;
+import org.opendaylight.controller.config.manager.testingservices.seviceinterface.TestingThreadPoolServiceInterface;
+import org.opendaylight.controller.config.manager.testingservices.threadpool.TestingFixedThreadPoolModuleFactory;
+import org.opendaylight.controller.config.util.ConfigTransactionJMXClient;
+
+import javax.management.Attribute;
+import javax.management.AttributeNotFoundException;
+import javax.management.InstanceNotFoundException;
+import javax.management.JMX;
+import javax.management.MBeanException;
+import javax.management.ObjectName;
+import javax.management.ReflectionException;
+
+import java.util.Map;
+import java.util.Set;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertTrue;
+import static org.opendaylight.controller.config.api.jmx.ObjectNameUtil.withoutTransactionName;
+
+public class ServiceReferenceRegistryImplTest extends AbstractParallelAPSPTest {
+
+
+ @Before
+ public void setUp() {
+ super.initConfigTransactionManagerImpl(new HardcodedModuleFactoriesResolver(
+ new TestingFixedThreadPoolModuleFactory(),
+ new TestingParallelAPSPModuleFactory(),
+ new TestingScheduledThreadPoolModuleFactory()));
+ }
+
+ @Override
+ protected String getThreadPoolImplementationName() {
+ return TestingFixedThreadPoolModuleFactory.NAME;
+ }
+
+ @Test
+ public void test() throws Exception {
+ ConfigTransactionJMXClient transaction1 = configRegistryClient.createTransaction();
+ // create fixed1
+ int fixedNrOfThreads = 20, scheduledNrOfThreads = 30;
+
+ ObjectName fixedTPTransactionON = transaction1.createModule(getThreadPoolImplementationName(), fixed1);
+ platformMBeanServer.setAttribute(fixedTPTransactionON, new Attribute("ThreadCount", fixedNrOfThreads));
+
+ ObjectName scheduledTPTransactionON = transaction1.createModule(
+ TestingScheduledThreadPoolModuleFactory.NAME, "scheduled1");
+ platformMBeanServer.setAttribute(scheduledTPTransactionON, new Attribute("ThreadCount",
+ scheduledNrOfThreads));
+
+ String refName = "ref";
+ ObjectName serviceReference = transaction1.saveServiceReference(TestingThreadPoolServiceInterface.QNAME, refName,
+ fixedTPTransactionON);
+ // create apsp-parallel
+ createParallelAPSP(transaction1, serviceReference);
+ transaction1.commit();
+ // check fixed1 is used
+ ServiceReferenceMXBean serviceReferenceMXBean = JMX.newMXBeanProxy(platformMBeanServer,
+ withoutTransactionName(serviceReference), ServiceReferenceMXBean.class);
+ assertEquals(withoutTransactionName(fixedTPTransactionON), serviceReferenceMXBean.getCurrentImplementation());
+ checkApspThreadCount(fixedNrOfThreads);
+
+ // switch reference to scheduled
+ ConfigTransactionJMXClient transaction2 = configRegistryClient.createTransaction();
+ transaction2.saveServiceReference(TestingThreadPoolServiceInterface.QNAME, refName,
+ ObjectNameUtil.withTransactionName(scheduledTPTransactionON, transaction2.getTransactionName()));
+ transaction2.commit();
+ // check scheduled is used
+ checkApspThreadCount(scheduledNrOfThreads);
+ // check that dummy MXBean points to scheduled
+ assertEquals(withoutTransactionName(scheduledTPTransactionON), serviceReferenceMXBean.getCurrentImplementation());
+
+ // empty transaction
+ configRegistryClient.createTransaction().commit();
+
+ // get service mapping
+ Map<String,Map<String,ObjectName>> serviceMapping = configRegistryClient.getServiceMapping();
+ Map<String,Map<String,ObjectName>> expectedMapping = ImmutableMap.of(TestingThreadPoolServiceInterface.QNAME,
+ (Map<String, ObjectName>)ImmutableMap.of(refName, withoutTransactionName(scheduledTPTransactionON)));
+ assertEquals(expectedMapping, serviceMapping);
+
+ // destroy all
+ ConfigTransactionJMXClient transaction4 = configRegistryClient.createTransaction();
+ Set<ObjectName> objectNames = transaction4.lookupConfigBeans();
+ for(ObjectName on: objectNames) {
+ transaction4.destroyModule(on);
+ }
+ transaction4.commit();
+
+ serviceMapping = configRegistryClient.getServiceMapping();
+ assertTrue(serviceMapping.isEmpty());
+ }
+
+ private void checkApspThreadCount(int fixedNrOfThreads) throws MBeanException, AttributeNotFoundException,
+ InstanceNotFoundException, ReflectionException {
+ ObjectName apspON = ObjectNameUtil.createReadOnlyModuleON(TestingParallelAPSPModuleFactory.NAME, apsp1);
+ assertEquals(fixedNrOfThreads, platformMBeanServer.getAttribute(apspON, "MaxNumberOfThreads"));
+ }
+}
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.TransactionStatus;
@Before
public void setUp() {
transactionStatus = mock(TransactionStatus.class);
- tested = new DependencyResolverManager("txName", transactionStatus);
+ ServiceReferenceReadableRegistry mockedRegistry = mock(ServiceReferenceReadableRegistry.class);
+ tested = new DependencyResolverManager("txName", transactionStatus, mockedRegistry);
doNothing().when(transactionStatus).checkCommitStarted();
doNothing().when(transactionStatus).checkNotCommitted();
}
static final String SIMPLE = "simple";
static final String SUBCLASS2 = "subclass2";
- @ServiceInterfaceAnnotation(value = SIMPLE, osgiRegistrationType = Executor.class)
+ @ServiceInterfaceAnnotation(value = SIMPLE, osgiRegistrationType = Executor.class,
+ namespace = "ns", revision = "rev", localName = SIMPLE)
static interface SimpleSI extends AbstractServiceInterface {
}
}
- @ServiceInterfaceAnnotation(value = SUBCLASS2, osgiRegistrationType = ExecutorService.class)
+ @ServiceInterfaceAnnotation(value = SUBCLASS2, osgiRegistrationType = ExecutorService.class,
+ namespace = "ns", revision = "rev", localName = SUBCLASS2)
+
static interface SubSI2 extends SubSI {
}
import static org.junit.Assert.assertEquals;
+import java.util.HashSet;
import java.util.Set;
import javax.management.MXBean;
import org.junit.Test;
+import org.opendaylight.controller.config.api.annotations.AbstractServiceInterface;
+import org.opendaylight.controller.config.manager.testingservices.seviceinterface.TestingScheduledThreadPoolServiceInterface;
+import org.opendaylight.controller.config.manager.testingservices.seviceinterface.TestingThreadPoolServiceInterface;
import org.opendaylight.controller.config.spi.Module;
import org.opendaylight.yangtools.concepts.Identifiable;
assertEquals(expected, InterfacesHelper.getMXInterfaces(SubClass.class));
}
+ @Test
+ public void testGetAllAbstractServiceInterfaceClasses(){
+ Class<? extends AbstractServiceInterface> clazz = TestingScheduledThreadPoolServiceInterface.class;
+ Set<Class<? extends AbstractServiceInterface>> input = new HashSet<>();
+ input.add(clazz);
+ Set<Class<? extends AbstractServiceInterface>> result = InterfacesHelper.getAllAbstractServiceInterfaceClasses(input);
+
+ Set<Class<?>> expected = Sets.newHashSet((Class<?>) TestingScheduledThreadPoolServiceInterface.class,
+ TestingThreadPoolServiceInterface.class
+ );
+ assertEquals(expected, result);
+ }
+
}
*/
package org.opendaylight.controller.config.manager.impl.util;
-import java.util.Set;
-
-import javax.management.ObjectName;
-
+import com.google.common.base.Throwables;
+import com.google.common.collect.Sets;
import org.junit.After;
import org.junit.Before;
+import org.junit.Test;
+import org.opendaylight.controller.config.api.jmx.ObjectNameUtil;
import org.opendaylight.controller.config.manager.impl.AbstractLockedPlatformMBeanServerTest;
-import com.google.common.base.Throwables;
-import com.google.common.collect.Sets;
+import javax.management.ObjectName;
+import java.util.Set;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
public class ObjectNameUtilTest extends AbstractLockedPlatformMBeanServerTest {
private Set<ObjectName> unregisterONs;
}
}
if (lastException != null) {
- Throwables.propagate(lastException);
+ throw Throwables.propagate(lastException);
}
}
+
+ @Test
+ public void testQuotation() throws Exception {
+ String serviceQName = "(namespace?revision=r)qname";
+ String refName = "refName";
+ String transaction = "transaction";
+ ObjectName serviceReferenceON = ObjectNameUtil.createTransactionServiceON(transaction, serviceQName, refName);
+ assertFalse(serviceReferenceON.isPattern());
+ assertEquals(serviceQName, ObjectNameUtil.getServiceQName(serviceReferenceON));
+ assertEquals(refName, ObjectNameUtil.getReferenceName(serviceReferenceON));
+ assertEquals(transaction, ObjectNameUtil.getTransactionName(serviceReferenceON));
+
+ serviceReferenceON = ObjectNameUtil.createReadOnlyServiceON(serviceQName, refName);
+ assertFalse(serviceReferenceON.isPattern());
+ assertEquals(serviceQName, ObjectNameUtil.getServiceQName(serviceReferenceON));
+ assertEquals(refName, ObjectNameUtil.getReferenceName(serviceReferenceON));
+ assertEquals(null, ObjectNameUtil.getTransactionName(serviceReferenceON));
+
+ }
}
import org.opendaylight.controller.config.api.annotations.ServiceInterfaceAnnotation;
-@ServiceInterfaceAnnotation(value = TestingParallelAPSPConfigMXBean.NAME, osgiRegistrationType = TestingAPSP.class)
+@ServiceInterfaceAnnotation(value = TestingParallelAPSPConfigMXBean.NAME, osgiRegistrationType = TestingAPSP.class,
+namespace = "namespace", revision = "rev", localName = TestingParallelAPSPConfigMXBean.NAME)
public interface TestingParallelAPSPConfigMXBean {
static final String NAME = "apsp";
if (oldInstance != null) {
// changing thread pool is not supported
- boolean reuse = threadPoolInstance.equals(oldInstance
- .getThreadPool());
+ boolean reuse = threadPoolInstance == oldInstance.getThreadPool();
if (reuse) {
logger.debug("Reusing old instance");
instance = oldInstance;
import javax.annotation.concurrent.ThreadSafe;
import javax.management.ObjectName;
+import java.util.Collections;
import java.util.HashSet;
import java.util.Set;
public Set<Module> getDefaultModules(DependencyResolverFactory dependencyResolverFactory, BundleContext context) {
return new HashSet<Module>();
}
+
+ @Override
+ public Set<Class<? extends AbstractServiceInterface>> getImplementedServiceIntefaces() {
+ return Collections.emptySet();
+ }
}
*/
package org.opendaylight.controller.config.manager.testingservices.parallelapsp.test;
-import javax.management.InstanceAlreadyExistsException;
-import javax.management.ObjectName;
-
-import org.opendaylight.controller.config.manager.impl.AbstractConfigWithJolokiaTest;
+import org.opendaylight.controller.config.manager.impl.AbstractConfigTest;
import org.opendaylight.controller.config.manager.testingservices.parallelapsp.TestingParallelAPSPConfigMXBean;
import org.opendaylight.controller.config.manager.testingservices.parallelapsp.TestingParallelAPSPModuleFactory;
import org.opendaylight.controller.config.manager.testingservices.threadpool.TestingFixedThreadPoolConfigMXBean;
import org.opendaylight.controller.config.util.ConfigTransactionJMXClient;
-abstract class AbstractParallelAPSPTest extends AbstractConfigWithJolokiaTest {
+import javax.management.InstanceAlreadyExistsException;
+import javax.management.ObjectName;
+
+public abstract class AbstractParallelAPSPTest extends AbstractConfigTest {
protected final String fixed1 = "fixed1";
protected final String apsp1 = "apsp-parallel";
- abstract String getThreadPoolImplementationName();
+ protected abstract String getThreadPoolImplementationName();
protected ObjectName createParallelAPSP(
ConfigTransactionJMXClient transaction, ObjectName threadPoolON)
protected ObjectName createFixed1(ConfigTransactionJMXClient transaction,
int numberOfThreads) throws InstanceAlreadyExistsException {
+
ObjectName name = transaction.createModule(
getThreadPoolImplementationName(), fixed1);
*/
package org.opendaylight.controller.config.manager.testingservices.parallelapsp.test;
-import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertThat;
-import static org.junit.Assert.assertTrue;
-import static org.junit.Assert.fail;
-import static org.junit.internal.matchers.StringContains.containsString;
-
-import java.util.Map;
-
-import javax.management.ObjectName;
-
-import org.json.simple.JSONObject;
import org.junit.After;
import org.junit.Before;
import org.junit.Test;
import org.opendaylight.controller.config.manager.testingservices.threadpool.TestingFixedThreadPoolConfigMXBean;
import org.opendaylight.controller.config.manager.testingservices.threadpool.TestingFixedThreadPoolModuleFactory;
import org.opendaylight.controller.config.util.ConfigTransactionJMXClient;
-import org.opendaylight.controller.config.util.jolokia.ConfigTransactionJolokiaClient;
+
+import javax.management.ObjectName;
+import java.util.Map;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertThat;
+import static org.junit.Assert.assertTrue;
+import static org.junit.Assert.fail;
+import static org.junit.internal.matchers.StringContains.containsString;
public class DependentWiringTest extends AbstractParallelAPSPTest {
private final String fixed1 = "fixed1";
}
@Override
- String getThreadPoolImplementationName() {
+ protected String getThreadPoolImplementationName() {
return TestingFixedThreadPoolModuleFactory.NAME;
}
parallelAPSPRuntimeProxy.getMaxNumberOfThreads());
}
-
- @Test
- public void testUsingJolokia() throws Exception {
-
- ConfigTransactionJolokiaClient transactionClient = configRegistryJolokiaClient
- .createTransaction();
- // fixed1
- ObjectName fixed1ON = transactionClient.createModule(
- getThreadPoolImplementationName(), fixed1);
- transactionClient.setAttribute(fixed1ON, "ThreadCount",
- TestingParallelAPSPImpl.MINIMAL_NUMBER_OF_THREADS);
-
- // apsp-parallel with syntetic attrib
- String threadPoolString = "ThreadPool";
- ObjectName apsp1ON = transactionClient.createModule(
- TestingParallelAPSPModuleFactory.NAME, apsp1);
- transactionClient.setAttribute(apsp1ON, threadPoolString, fixed1ON);
- // check
- assertEquals(ObjectNameUtil.withoutTransactionName(fixed1ON),
- transactionClient.getAttributeON(apsp1ON, threadPoolString));
- transactionClient.setAttribute(apsp1ON, "SomeParam", "ahoj");
-
- // commit
- transactionClient.commit();
- // check thread pool
- assertEquals(1, TestingFixedThreadPool.allExecutors.size());
- // check platform MBeanServer
- ObjectName apspReadOnlyON = ObjectNameUtil
- .withoutTransactionName(apsp1ON);
- JSONObject threadPoolONJson = (JSONObject) configRegistryJolokiaClient
- .getAttribute(apspReadOnlyON, threadPoolString);
- ObjectName fixed1ReadOnlyON = ObjectNameUtil
- .withoutTransactionName(fixed1ON);
- assertEquals(fixed1ReadOnlyON, ObjectNameUtil.createON(threadPoolONJson
- .get("objectName").toString()));
- assertEquals(fixed1ReadOnlyON,
- configRegistryJolokiaClient.getAttributeON(apspReadOnlyON,
- threadPoolString));
-
- }
}
}
@Override
- String getThreadPoolImplementationName() {
+ protected String getThreadPoolImplementationName() {
return threadPoolImplementationName;
}
public boolean isRecreate();
public void setRecreate(boolean recreate);
+
+ public void setThreadCount(int threadCount);
+
}
@Nullable
private final TestingScheduledThreadPoolImpl oldInstance;
- private final int threadCount = 10;
+ private int threadCount = 10;
private TestingScheduledThreadPoolImpl instance;
private RootRuntimeBeanRegistrator runtimeBeanRegistrator;
private boolean recreate;
return threadCount;
}
+ @Override
+ public void setThreadCount(int threadCount) {
+ this.threadCount = threadCount;
+ }
+
@Override
public Closeable getInstance() {
assertNotNull(runtimeBeanRegistrator);
*/
package org.opendaylight.controller.config.manager.testingservices.scheduledthreadpool;
+import com.google.common.collect.Sets;
import org.opendaylight.controller.config.api.DependencyResolver;
import org.opendaylight.controller.config.api.DependencyResolverFactory;
import org.opendaylight.controller.config.api.DynamicMBeanWithInstance;
import org.opendaylight.controller.config.spi.ModuleFactory;
import org.osgi.framework.BundleContext;
-import java.util.Arrays;
+import java.util.Collections;
import java.util.HashSet;
-import java.util.List;
import java.util.Set;
public class TestingScheduledThreadPoolModuleFactory implements ModuleFactory {
public static final String NAME = "scheduled";
- private static List<Class<? extends TestingThreadPoolServiceInterface>> ifc = Arrays
- .asList(TestingScheduledThreadPoolServiceInterface.class, TestingThreadPoolServiceInterface.class);
+ private static Set<Class<? extends AbstractServiceInterface>> ifc = Collections.unmodifiableSet(Sets.newHashSet(
+ (Class<? extends AbstractServiceInterface>) TestingScheduledThreadPoolServiceInterface.class,
+ TestingThreadPoolServiceInterface.class));
@Override
public boolean isModuleImplementingServiceInterface(
public Set<Module> getDefaultModules(DependencyResolverFactory dependencyResolverFactory, BundleContext bundleContext) {
return new HashSet<Module>();
}
+
+ @Override
+ public Set<Class<? extends AbstractServiceInterface>> getImplementedServiceIntefaces() {
+ return ifc;
+ }
+
+
}
import org.opendaylight.controller.config.api.annotations.ServiceInterfaceAnnotation;
import org.opendaylight.controller.config.manager.testingservices.threadpool.TestingModifiableThreadPoolIfc;
-@ServiceInterfaceAnnotation(value = "modifiable-threadpool", osgiRegistrationType = TestingModifiableThreadPoolIfc.class)
+@ServiceInterfaceAnnotation(value = "fqn:modifiable-threadpool", osgiRegistrationType = TestingModifiableThreadPoolIfc.class,
+ namespace = "foo", revision = "bar", localName = "modifiable-threadpool")
public interface ModifiableThreadPoolServiceInterface extends
TestingThreadPoolServiceInterface {
}
import org.opendaylight.controller.config.api.annotations.ServiceInterfaceAnnotation;
import org.opendaylight.controller.config.manager.testingservices.scheduledthreadpool.TestingScheduledThreadPoolIfc;
-@ServiceInterfaceAnnotation(value = "threadpool-scheduled", osgiRegistrationType = TestingScheduledThreadPoolIfc.class)
+@ServiceInterfaceAnnotation(value = "threadpool-scheduled", osgiRegistrationType = TestingScheduledThreadPoolIfc.class,
+ namespace = "ns", revision = "rev", localName = "threadpool-scheduled")
public interface TestingScheduledThreadPoolServiceInterface extends
TestingThreadPoolServiceInterface {
}
import org.opendaylight.controller.config.api.annotations.ServiceInterfaceAnnotation;
import org.opendaylight.controller.config.manager.testingservices.threadpool.TestingThreadPoolIfc;
-@ServiceInterfaceAnnotation(value = "testing-threadpool", osgiRegistrationType = TestingThreadPoolIfc.class)
+@ServiceInterfaceAnnotation(value = TestingThreadPoolServiceInterface.QNAME, osgiRegistrationType = TestingThreadPoolIfc.class,
+ namespace = "ns", revision = "foo", localName = "testing-threadpool")
public interface TestingThreadPoolServiceInterface extends
AbstractServiceInterface {
+ public static final String QNAME = "(ns?revision=foo)testing-threadpool";
}
--- /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.testingservices.threadpool;
+
+import org.opendaylight.yangtools.yang.binding.annotations.ModuleQName;
+
+@ModuleQName(namespace = "namespace", revision = "revision", name = "name")
+public abstract class AbstractTestingFixedThreadPoolModuleFactory {
+}
*/
package org.opendaylight.controller.config.manager.testingservices.threadpool;
+import com.google.common.collect.Sets;
import org.opendaylight.controller.config.api.DependencyResolver;
import org.opendaylight.controller.config.api.DependencyResolverFactory;
import org.opendaylight.controller.config.api.DynamicMBeanWithInstance;
import org.opendaylight.controller.config.spi.ModuleFactory;
import org.osgi.framework.BundleContext;
-import java.util.Arrays;
+import java.util.Collections;
import java.util.HashSet;
-import java.util.List;
import java.util.Set;
-public class TestingFixedThreadPoolModuleFactory implements ModuleFactory {
+public class TestingFixedThreadPoolModuleFactory extends AbstractTestingFixedThreadPoolModuleFactory implements ModuleFactory {
public static final String NAME = "fixed";
- private static List<Class<? extends TestingThreadPoolServiceInterface>> ifc = Arrays
- .asList(ModifiableThreadPoolServiceInterface.class, TestingThreadPoolServiceInterface.class);
+
+ private static Set<Class<? extends AbstractServiceInterface>> ifc = Collections.unmodifiableSet(Sets.newHashSet(
+ (Class<? extends AbstractServiceInterface>) ModifiableThreadPoolServiceInterface.class,
+ TestingThreadPoolServiceInterface.class));
@Override
public String getImplementationName() {
public Set<Module> getDefaultModules(DependencyResolverFactory dependencyResolverFactory, BundleContext bundleContext) {
return new HashSet<Module>();
}
+
+ @Override
+ public Set<Class<? extends AbstractServiceInterface>> getImplementedServiceIntefaces() {
+ return ifc;
+ }
}
*/
package org.opendaylight.controller.config.manager.testingservices.threadpool.test;
-import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertFalse;
-import static org.junit.Assert.assertNotNull;
-import static org.junit.Assert.assertThat;
-import static org.junit.Assert.assertTrue;
-import static org.junit.Assert.fail;
-import static org.junit.matchers.JUnitMatchers.containsString;
-
-import java.util.Arrays;
-import java.util.Collections;
-import java.util.List;
-import java.util.Map;
-import java.util.concurrent.ThreadPoolExecutor;
-
-import javax.management.DynamicMBean;
-import javax.management.InstanceAlreadyExistsException;
-import javax.management.InstanceNotFoundException;
-import javax.management.MBeanException;
-import javax.management.ObjectName;
-import javax.management.ReflectionException;
-import javax.management.RuntimeMBeanException;
-
+import com.google.common.collect.Sets;
import org.junit.After;
import org.junit.Before;
import org.junit.Test;
import org.opendaylight.controller.config.api.ValidationException.ExceptionMessageWithStackTrace;
import org.opendaylight.controller.config.api.jmx.CommitStatus;
import org.opendaylight.controller.config.api.jmx.ObjectNameUtil;
-import org.opendaylight.controller.config.manager.impl.AbstractConfigWithJolokiaTest;
+import org.opendaylight.controller.config.manager.impl.AbstractConfigTest;
import org.opendaylight.controller.config.manager.impl.factoriesresolver.HardcodedModuleFactoriesResolver;
import org.opendaylight.controller.config.manager.testingservices.threadpool.TestingFixedThreadPool;
import org.opendaylight.controller.config.manager.testingservices.threadpool.TestingFixedThreadPoolConfigMXBean;
import org.opendaylight.controller.config.manager.testingservices.threadpool.TestingFixedThreadPoolModuleFactory;
import org.opendaylight.controller.config.util.ConfigTransactionClient;
import org.opendaylight.controller.config.util.ConfigTransactionJMXClient;
-import org.opendaylight.controller.config.util.jolokia.ConfigTransactionJolokiaClient;
+
+import javax.management.DynamicMBean;
+import javax.management.InstanceAlreadyExistsException;
+import javax.management.InstanceNotFoundException;
+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;
+import java.util.Map;
+import java.util.Set;
+import java.util.concurrent.ThreadPoolExecutor;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertTrue;
+import static org.junit.Assert.fail;
/**
* Tests basic functionality of configuration registry:
* Only one bean is being configured - {@link TestingThreadPoolIfc} which has no
* dependencies.
*/
-public class SimpleConfigurationTest extends AbstractConfigWithJolokiaTest {
+public class SimpleConfigurationTest extends AbstractConfigTest {
private final int numberOfThreads = 5;
private final int numberOfThreads2 = 10;
private static final String fixed1 = "fixed1";
testValidation(transaction);
}
- @Test
- public void testValidationUsingJolokiaClient() throws Exception {
- ConfigTransactionClient transaction = configRegistryJolokiaClient
- .createTransaction();
- testValidation(transaction);
- }
private void testValidation(ConfigTransactionClient transaction)
throws InstanceAlreadyExistsException, ReflectionException,
}
}
- @Test
- public void testOptimisticLock_ConfigTransactionJolokiaClient()
- throws Exception {
- ConfigTransactionJolokiaClient transaction1 = configRegistryJolokiaClient
- .createTransaction();
- ConfigTransactionJolokiaClient transaction2 = configRegistryJolokiaClient
- .createTransaction();
- transaction2.assertVersion(0, 2);
- transaction2.commit();
- try {
- transaction1.commit();
- fail();
- } catch (ConflictingVersionException e) {
- assertEquals(
- "Optimistic lock failed. Expected parent version 2, was 0",
- e.getMessage());
- }
- }
@Test
- public void testOptimisticLock_ConfigRegistryJolokiaClient()
- throws Exception {
- ConfigTransactionJolokiaClient transaction1 = configRegistryJolokiaClient
- .createTransaction();
- ConfigTransactionJolokiaClient transaction2 = configRegistryJolokiaClient
- .createTransaction();
- transaction2.assertVersion(0, 2);
- transaction2.commit();
- try {
- configRegistryJolokiaClient.commitConfig(transaction1
- .getObjectName());
- fail();
- } catch (ConflictingVersionException e) {
- assertEquals(
- "Optimistic lock failed. Expected parent version 2, was 0",
- e.getMessage());
- }
- }
-
- @Test
- public void testUsingJolokia() throws Exception {
- ConfigTransactionJolokiaClient transactionClient = configRegistryJolokiaClient
- .createTransaction();
-
- ObjectName name = transactionClient.createModule(
- TestingFixedThreadPoolModuleFactory.NAME, fixed1);
-
- try {
- transactionClient.validateConfig();
- fail();
- } catch (ValidationException e) {
- assertThat(
- e.getMessage(),
- containsString("Parameter 'threadCount' must be greater than 0"));
- }
-
- transactionClient.setAttribute(name, "ThreadCount", numberOfThreads);
- // commit
- CommitStatus commitStatus = transactionClient.commit();
- CommitStatus expected = new CommitStatus(Arrays.asList(ObjectNameUtil
- .withoutTransactionName(name)), emptyONs, emptyONs);
- assertEquals(expected, commitStatus);
+ public void testQNames() {
+ Set<String> availableModuleFactoryQNames = configRegistryClient.getAvailableModuleFactoryQNames();
+ String expected = "(namespace?revision=revision)name";
+ assertEquals(Sets.newHashSet(expected), availableModuleFactoryQNames);
}
}
}
private void checkFileConsistency(){
- checkState(inCapabilities, "File {} is missing delimiters in this order: {}", fileNameForReporting,
+ checkState(inCapabilities, "File %s is missing delimiters in this order: %s", fileNameForReporting,
Arrays.asList(DirectoryPersister.MODULES_START,
DirectoryPersister.SERVICES_START,
DirectoryPersister.CAPABILITIES_START));
--- /dev/null
+<?xml version="1.0" encoding="UTF-8"?>
+<project xmlns="http://maven.apache.org/POM/4.0.0"
+ xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+ xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+ <modelVersion>4.0.0</modelVersion>
+ <parent>
+ <artifactId>config-subsystem</artifactId>
+ <groupId>org.opendaylight.controller</groupId>
+ <version>0.2.3-SNAPSHOT</version>
+ <relativePath>..</relativePath>
+ </parent>
+ <artifactId>config-persister-directory-xml-adapter</artifactId>
+ <name>${project.artifactId}</name>
+ <packaging>bundle</packaging>
+
+ <dependencies>
+ <!-- compile dependencies -->
+ <dependency>
+ <groupId>${project.groupId}</groupId>
+ <artifactId>config-persister-api</artifactId>
+ </dependency>
+ <dependency>
+ <groupId>org.apache.commons</groupId>
+ <artifactId>commons-lang3</artifactId>
+ </dependency>
+ <dependency>
+ <groupId>com.google.guava</groupId>
+ <artifactId>guava</artifactId>
+ </dependency>
+ <dependency>
+ <groupId>org.opendaylight.controller</groupId>
+ <artifactId>config-persister-file-xml-adapter</artifactId>
+ <version>${config.version}</version>
+ </dependency>
+
+ <dependency>
+ <groupId>org.eclipse.persistence</groupId>
+ <artifactId>org.eclipse.persistence.moxy</artifactId>
+ </dependency>
+ <dependency>
+ <groupId>org.eclipse.persistence</groupId>
+ <artifactId>org.eclipse.persistence.core</artifactId>
+ </dependency>
+
+ <dependency>
+ <groupId>org.slf4j</groupId>
+ <artifactId>slf4j-api</artifactId>
+ </dependency>
+ <dependency>
+ <groupId>commons-io</groupId>
+ <artifactId>commons-io</artifactId>
+ </dependency>
+
+ <!-- test dependencies -->
+ <dependency>
+ <groupId>org.opendaylight.bgpcep</groupId>
+ <artifactId>mockito-configuration</artifactId>
+ <scope>test</scope>
+ </dependency>
+
+ </dependencies>
+
+ <build>
+ <plugins>
+ <!-- workaround for creating version according to OSGi specification (major.minor.micro[.qualifier] -->
+ <plugin>
+ <groupId>org.codehaus.groovy.maven</groupId>
+ <artifactId>gmaven-plugin</artifactId>
+ <executions>
+ <execution>
+ <phase>generate-sources</phase>
+ <goals>
+ <goal>execute</goal>
+ </goals>
+ <configuration>
+ <source>
+ System.setProperty("osgiversion", "${project.version}".replace('-', '.'))
+ </source>
+ </configuration>
+ </execution>
+ </executions>
+ </plugin>
+ <plugin>
+ <groupId>org.apache.felix</groupId>
+ <artifactId>maven-bundle-plugin</artifactId>
+ <configuration>
+ <instructions>
+ <Fragment-Host>${project.groupId}.config-persister-impl;bundle-version=${osgiversion}
+ </Fragment-Host>
+ <Provide-Capability>org.opendaylight.controller.config.persister.storage.adapter
+ </Provide-Capability>
+ <Import-Package>
+ com.google.common.base,
+ com.google.common.io,
+ org.apache.commons.io,
+ org.opendaylight.controller.config.persist.api,
+ org.slf4j,
+ com.google.common.collect,
+ javax.xml.bind,
+ javax.xml.bind.annotation,
+ javax.xml.transform,
+ javax.xml.transform.stream,
+ org.eclipse.persistence.jaxb,
+ org.apache.commons.lang3
+ </Import-Package>
+ <Private-Package>
+ org.opendaylight.controller.config.persist.storage.file.xml.model,
+ </Private-Package>
+ </instructions>
+ </configuration>
+ </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.config.persist.storage.directory.xml;
+
+import org.opendaylight.controller.config.persist.api.ConfigSnapshotHolder;
+import org.opendaylight.controller.config.persist.api.Persister;
+import org.opendaylight.controller.config.persist.storage.file.xml.model.ConfigSnapshot;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import javax.xml.bind.JAXBContext;
+import javax.xml.bind.JAXBException;
+import javax.xml.bind.Unmarshaller;
+import java.io.File;
+import java.io.IOException;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.List;
+import java.util.SortedSet;
+
+import static com.google.common.base.Preconditions.checkArgument;
+
+public class XmlDirectoryPersister implements Persister {
+ private static final Logger logger = LoggerFactory.getLogger(XmlDirectoryPersister.class);
+
+ private final File storage;
+
+ public XmlDirectoryPersister(File storage) {
+ checkArgument(storage.exists() && storage.isDirectory(), "Storage directory does not exist: " + storage);
+ this.storage = storage;
+ }
+
+ @Override
+ public void persistConfig(ConfigSnapshotHolder holder) throws IOException {
+ throw new UnsupportedOperationException("This adapter is read only. Please set readonly=true on " + getClass());
+ }
+
+ @Override
+ public List<ConfigSnapshotHolder> loadLastConfigs() throws IOException {
+ File[] filesArray = storage.listFiles();
+ if (filesArray == null || filesArray.length == 0) {
+ return Collections.emptyList();
+ }
+ List<File> sortedFiles = new ArrayList<>(Arrays.asList(filesArray));
+ Collections.sort(sortedFiles);
+ // combine all found files
+ logger.debug("Reading files in following order: {}", sortedFiles);
+
+ List<ConfigSnapshotHolder> result = new ArrayList<>();
+ for (File file : sortedFiles) {
+ logger.trace("Adding file '{}' to combined result", file);
+ ConfigSnapshotHolder h = fromXmlSnapshot(file);
+ result.add(h);
+ }
+ return result;
+ }
+
+ private ConfigSnapshotHolder fromXmlSnapshot(File file) {
+ try {
+ JAXBContext jaxbContext = JAXBContext.newInstance(ConfigSnapshot.class);
+ Unmarshaller um = jaxbContext.createUnmarshaller();
+
+ return asHolder((ConfigSnapshot) um.unmarshal(file));
+ } catch (JAXBException e) {
+ logger.warn("Unable to restore configuration snapshot from {}", file, e);
+ throw new IllegalStateException("Unable to restore configuration snapshot from " + file, e);
+ }
+ }
+
+ private ConfigSnapshotHolder asHolder(final ConfigSnapshot unmarshalled) {
+ return new ConfigSnapshotHolder() {
+ @Override
+ public String getConfigSnapshot() {
+ return unmarshalled.getConfigSnapshot();
+ }
+
+ @Override
+ public SortedSet<String> getCapabilities() {
+ return unmarshalled.getCapabilities();
+ }
+
+ @Override
+ public String toString() {
+ return unmarshalled.toString();
+ }
+ };
+ }
+
+
+ @Override
+ public void close() {
+
+ }
+
+ @Override
+ public String toString() {
+ final StringBuffer sb = new StringBuffer("XmlDirectoryPersister{");
+ sb.append("storage=").append(storage);
+ sb.append('}');
+ return sb.toString();
+ }
+}
\ No newline at end of file
--- /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.persist.storage.directory.xml;
+
+import com.google.common.base.Preconditions;
+import org.opendaylight.controller.config.persist.api.Persister;
+import org.opendaylight.controller.config.persist.api.PropertiesProvider;
+import org.opendaylight.controller.config.persist.api.StorageAdapter;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import java.io.File;
+
+/**
+ * StorageAdapter that retrieves initial configuration from a directory. If multiple files are present, snapshot and
+ * required capabilities will be merged together. Writing to this persister is not supported.
+ */
+public class XmlDirectoryStorageAdapter implements StorageAdapter {
+ private static final Logger logger = LoggerFactory.getLogger(XmlDirectoryStorageAdapter.class);
+
+ public static final String DIRECTORY_STORAGE_PROP = "directoryStorage";
+
+
+ @Override
+ public Persister instantiate(PropertiesProvider propertiesProvider) {
+ String fileStorageProperty = propertiesProvider.getProperty(DIRECTORY_STORAGE_PROP);
+ Preconditions.checkNotNull(fileStorageProperty, "Unable to find " + propertiesProvider.getFullKeyForReporting(DIRECTORY_STORAGE_PROP));
+ File storage = new File(fileStorageProperty);
+ logger.debug("Using {}", storage);
+ return new XmlDirectoryPersister(storage);
+ }
+
+}
--- /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.persist.storage.directory.xml;
+
+import org.junit.Test;
+import org.opendaylight.controller.config.persist.api.ConfigSnapshotHolder;
+
+import java.io.File;
+import java.util.Collections;
+import java.util.List;
+import java.util.SortedSet;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertTrue;
+import static org.junit.Assert.fail;
+
+public class DirectoryStorageAdapterTest {
+ XmlDirectoryPersister tested;
+
+ @Test
+ public void testEmptyDirectory() throws Exception {
+ File folder = new File("target/emptyFolder");
+ folder.mkdir();
+ tested = new XmlDirectoryPersister((folder));
+ assertEquals(Collections.<ConfigSnapshotHolder>emptyList(), tested.loadLastConfigs());
+
+ try {
+ tested.persistConfig(new ConfigSnapshotHolder() {
+ @Override
+ public String getConfigSnapshot() {
+ throw new RuntimeException();
+ }
+
+ @Override
+ public SortedSet<String> getCapabilities() {
+ throw new RuntimeException();
+ }
+ });
+ fail();
+ } catch (UnsupportedOperationException e) {
+
+ }
+ }
+
+ private File getFolder(String folderName) {
+ File result = new File(("src/test/resources/" +
+ folderName).replace("/", File.separator));
+ assertTrue(result + " is not a directory", result.isDirectory());
+ return result;
+ }
+
+ @Test
+ public void testOneFile() throws Exception {
+ File folder = getFolder("oneFile");
+ tested = new XmlDirectoryPersister((folder));
+ List<ConfigSnapshotHolder> results = tested.loadLastConfigs();
+ assertEquals(1, results.size());
+ ConfigSnapshotHolder result = results.get(0);
+ assertResult(result, "<config>1</config>", "cap1&rev", "cap2", "capa a");
+ }
+
+ private void assertResult(ConfigSnapshotHolder result, String s, String... caps) {
+ assertEquals(s, result.getConfigSnapshot().replaceAll("\\s", ""));
+ int i = 0;
+ for (String capFromSnapshot : result.getCapabilities()) {
+ assertEquals(capFromSnapshot, caps[i++]);
+ }
+ }
+
+ @Test
+ public void testTwoFiles() throws Exception {
+ File folder = getFolder("twoFiles");
+ tested = new XmlDirectoryPersister((folder));
+ List<ConfigSnapshotHolder> results = tested.loadLastConfigs();
+ assertEquals(2, results.size());
+
+ assertResult(results.get(0), "<config>1</config>", "cap1-a", "cap2-a", "capa a-a");
+ assertResult(results.get(1), "<config>2</config>", "cap1-b", "cap2-b", "capa a-b");
+
+ }
+
+}
--- /dev/null
+<snapshot>
+ <required-capabilities>
+ <capability>cap1&rev</capability>
+ <capability>cap2</capability>
+ <capability>capa a</capability>
+ </required-capabilities>
+ <configuration>
+ <config>1</config>
+ </configuration>
+</snapshot>
\ No newline at end of file
--- /dev/null
+<snapshot>
+ <required-capabilities>
+ <capability>cap1-a</capability>
+ <capability>cap2-a</capability>
+ <capability>capa a-a</capability>
+ </required-capabilities>
+ <configuration>
+ <config>1</config>
+ </configuration>
+</snapshot>
\ No newline at end of file
--- /dev/null
+<snapshot>
+ <required-capabilities>
+ <capability>cap1-b</capability>
+ <capability>cap2-b</capability>
+ <capability>capa a-b</capability>
+ </required-capabilities>
+ <configuration>
+ <config>2</config>
+ </configuration>
+</snapshot>
\ No newline at end of file
--- /dev/null
+<?xml version="1.0" encoding="UTF-8"?>
+<project xmlns="http://maven.apache.org/POM/4.0.0"
+ xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+ xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+ <modelVersion>4.0.0</modelVersion>
+ <parent>
+ <artifactId>config-subsystem</artifactId>
+ <groupId>org.opendaylight.controller</groupId>
+ <version>0.2.3-SNAPSHOT</version>
+ <relativePath>..</relativePath>
+ </parent>
+ <artifactId>config-persister-file-xml-adapter</artifactId>
+ <name>${project.artifactId}</name>
+ <packaging>bundle</packaging>
+
+ <dependencies>
+ <!-- compile dependencies -->
+ <dependency>
+ <groupId>${project.groupId}</groupId>
+ <artifactId>config-persister-api</artifactId>
+ </dependency>
+ <dependency>
+ <groupId>org.apache.commons</groupId>
+ <artifactId>commons-lang3</artifactId>
+ </dependency>
+ <dependency>
+ <groupId>com.google.guava</groupId>
+ <artifactId>guava</artifactId>
+ </dependency>
+ <dependency>
+ <groupId>org.slf4j</groupId>
+ <artifactId>slf4j-api</artifactId>
+ </dependency>
+
+ <dependency>
+ <groupId>org.eclipse.persistence</groupId>
+ <artifactId>org.eclipse.persistence.moxy</artifactId>
+ </dependency>
+ <dependency>
+ <groupId>org.eclipse.persistence</groupId>
+ <artifactId>org.eclipse.persistence.core</artifactId>
+ </dependency>
+
+ <!-- test dependencies -->
+ <dependency>
+ <groupId>org.opendaylight.bgpcep</groupId>
+ <artifactId>mockito-configuration</artifactId>
+ <scope>test</scope>
+ </dependency>
+ </dependencies>
+
+ <build>
+ <plugins>
+ <!-- workaround for creating version according to OSGi specification (major.minor.micro[.qualifier] -->
+ <plugin>
+ <groupId>org.codehaus.groovy.maven</groupId>
+ <artifactId>gmaven-plugin</artifactId>
+ <executions>
+ <execution>
+ <phase>generate-sources</phase>
+ <goals>
+ <goal>execute</goal>
+ </goals>
+ <configuration>
+ <source>
+ System.setProperty("osgiversion", "${project.version}".replace('-', '.'))
+ </source>
+ </configuration>
+ </execution>
+ </executions>
+ </plugin>
+ <plugin>
+ <groupId>org.apache.felix</groupId>
+ <artifactId>maven-bundle-plugin</artifactId>
+ <configuration>
+ <instructions>
+ <Fragment-Host>${project.groupId}.config-persister-impl;bundle-version=${osgiversion}
+ </Fragment-Host>
+ <Provide-Capability>org.opendaylight.controller.config.persister.storage.adapter
+ </Provide-Capability>
+ </instructions>
+ </configuration>
+ </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.config.persist.storage.file.xml;
+
+import com.google.common.annotations.VisibleForTesting;
+import com.google.common.base.Optional;
+import com.google.common.base.Preconditions;
+import com.google.common.collect.Lists;
+import org.opendaylight.controller.config.persist.api.ConfigSnapshotHolder;
+import org.opendaylight.controller.config.persist.api.Persister;
+import org.opendaylight.controller.config.persist.api.PropertiesProvider;
+import org.opendaylight.controller.config.persist.api.StorageAdapter;
+import org.opendaylight.controller.config.persist.storage.file.xml.model.Config;
+import org.opendaylight.controller.config.persist.storage.file.xml.model.ConfigSnapshot;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import java.io.File;
+import java.io.IOException;
+import java.util.Collections;
+import java.util.List;
+import java.util.SortedSet;
+
+/**
+ * StorageAdapter that stores configuration in an xml file.
+ */
+public class XmlFileStorageAdapter implements StorageAdapter, Persister {
+ private static final Logger logger = LoggerFactory.getLogger(XmlFileStorageAdapter.class);
+
+ public static final String FILE_STORAGE_PROP = "fileStorage";
+ public static final String NUMBER_OF_BACKUPS = "numberOfBackups";
+
+ private static Integer numberOfStoredBackups;
+ private File storage;
+
+ @Override
+ public Persister instantiate(PropertiesProvider propertiesProvider) {
+ File storage = extractStorageFileFromProperties(propertiesProvider);
+ logger.debug("Using file {}", storage.getAbsolutePath());
+ // Create file if it does not exist
+ File parentFile = storage.getAbsoluteFile().getParentFile();
+ if (parentFile.exists() == false) {
+ logger.debug("Creating parent folders {}", parentFile);
+ parentFile.mkdirs();
+ }
+ if (storage.exists() == false) {
+ logger.debug("Storage file does not exist, creating empty file");
+ try {
+ boolean result = storage.createNewFile();
+ if (result == false)
+ throw new RuntimeException("Unable to create storage file " + storage);
+ } catch (IOException e) {
+ throw new RuntimeException("Unable to create storage file " + storage, e);
+ }
+ }
+ if (numberOfStoredBackups == 0) {
+ throw new RuntimeException(NUMBER_OF_BACKUPS
+ + " property should be either set to positive value, or ommited. Can not be set to 0.");
+ }
+ setFileStorage(storage);
+ return this;
+ }
+
+ @VisibleForTesting
+ public void setFileStorage(File storage) {
+ this.storage = storage;
+ }
+
+ @VisibleForTesting
+ public void setNumberOfBackups(Integer numberOfBackups) {
+ numberOfStoredBackups = numberOfBackups;
+ }
+
+ private static File extractStorageFileFromProperties(PropertiesProvider propertiesProvider) {
+ String fileStorageProperty = propertiesProvider.getProperty(FILE_STORAGE_PROP);
+ Preconditions.checkNotNull(fileStorageProperty, "Unable to find " + propertiesProvider.getFullKeyForReporting(FILE_STORAGE_PROP));
+ File result = new File(fileStorageProperty);
+ String numberOfBackupsAsString = propertiesProvider.getProperty(NUMBER_OF_BACKUPS);
+ if (numberOfBackupsAsString != null) {
+ numberOfStoredBackups = Integer.valueOf(numberOfBackupsAsString);
+ } else {
+ numberOfStoredBackups = Integer.MAX_VALUE;
+ }
+ logger.trace("Property {} set to {}", NUMBER_OF_BACKUPS, numberOfStoredBackups);
+ return result;
+ }
+
+ @Override
+ public void persistConfig(ConfigSnapshotHolder holder) throws IOException {
+ Preconditions.checkNotNull(storage, "Storage file is null");
+
+ Config cfg = Config.fromXml(storage);
+ cfg.addConfigSnapshot(ConfigSnapshot.fromConfigSnapshot(holder), numberOfStoredBackups);
+ cfg.toXml(storage);
+ }
+
+ @Override
+ public List<ConfigSnapshotHolder> loadLastConfigs() throws IOException {
+ Preconditions.checkNotNull(storage, "Storage file is null");
+
+ if (!storage.exists()) {
+ return Collections.emptyList();
+ }
+
+ Optional<ConfigSnapshot> lastSnapshot = Config.fromXml(storage).getLastSnapshot();
+
+ if (lastSnapshot.isPresent())
+ return Lists.newArrayList(toConfigSnapshot(lastSnapshot.get()));
+ else
+ return Collections.emptyList();
+ }
+
+
+ public ConfigSnapshotHolder toConfigSnapshot(final ConfigSnapshot configSnapshot) {
+ return new ConfigSnapshotHolder() {
+ @Override
+ public String getConfigSnapshot() {
+ return configSnapshot.getConfigSnapshot();
+ }
+
+ @Override
+ public SortedSet<String> getCapabilities() {
+ return configSnapshot.getCapabilities();
+ }
+
+ @Override
+ public String toString() {
+ return configSnapshot.toString();
+ }
+ };
+ }
+
+ @Override
+ public void close() {
+
+ }
+
+ @Override
+ public String toString() {
+ return "XmlFileStorageAdapter [storage=" + storage + "]";
+ }
+
+}
--- /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.persist.storage.file.xml.model;
+
+import javax.xml.bind.ValidationEventHandler;
+import javax.xml.bind.annotation.DomHandler;
+import javax.xml.transform.Source;
+import javax.xml.transform.stream.StreamResult;
+import javax.xml.transform.stream.StreamSource;
+import java.io.StringReader;
+import java.io.StringWriter;
+
+class CapabilityHandler implements DomHandler<String, StreamResult> {
+
+ private static final String START_TAG = "<capability>";
+ private static final String END_TAG = "</capability>";
+
+ private StringWriter xmlWriter = new StringWriter();
+
+ public StreamResult createUnmarshaller(ValidationEventHandler errorHandler) {
+ xmlWriter.getBuffer().setLength(0);
+ return new StreamResult(xmlWriter);
+ }
+
+ public String getElement(StreamResult rt) {
+ String xml = rt.getWriter().toString();
+ int beginIndex = xml.indexOf(START_TAG) + START_TAG.length();
+ int endIndex = xml.indexOf(END_TAG);
+ return xml.substring(beginIndex, endIndex);
+ }
+
+ public Source marshal(String n, ValidationEventHandler errorHandler) {
+ try {
+ String xml = START_TAG + n.trim() + END_TAG;
+ StringReader xmlReader = new StringReader(xml);
+ return new StreamSource(xmlReader);
+ } catch(Exception e) {
+ throw new RuntimeException(e);
+ }
+ }
+
+}
--- /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.persist.storage.file.xml.model;
+
+import com.google.common.base.Charsets;
+import com.google.common.base.Optional;
+import com.google.common.collect.Iterables;
+import com.google.common.collect.Lists;
+import com.google.common.io.Files;
+import org.apache.commons.lang3.StringUtils;
+
+import javax.xml.bind.JAXBContext;
+import javax.xml.bind.JAXBException;
+import javax.xml.bind.Marshaller;
+import javax.xml.bind.Unmarshaller;
+import javax.xml.bind.annotation.XmlElement;
+import javax.xml.bind.annotation.XmlElementWrapper;
+import javax.xml.bind.annotation.XmlRootElement;
+import java.io.File;
+import java.io.IOException;
+import java.util.List;
+
+@XmlRootElement(name = "persisted-snapshots")
+public final class Config {
+
+ private List<ConfigSnapshot> snapshots;
+
+ Config(List<ConfigSnapshot> snapshots) {
+ this.snapshots = snapshots;
+ }
+
+ public Config() {
+ this.snapshots = Lists.newArrayList();
+ }
+
+ @XmlElement(name = "snapshot")
+ @XmlElementWrapper(name = "snapshots")
+ public List<ConfigSnapshot> getSnapshots() {
+ return snapshots;
+ }
+
+ public void setSnapshots(List<ConfigSnapshot> snapshots) {
+ this.snapshots = snapshots;
+ }
+
+ public void toXml(File to) {
+ try {
+
+ // TODO Moxy has to be used instead of default jaxb impl due to a bug
+ // default implementation has a bug that prevents from serializing xml in a string
+ JAXBContext jaxbContext = org.eclipse.persistence.jaxb.JAXBContextFactory.createContext(new Class[]{Config.class}, null);
+
+ Marshaller marshaller = jaxbContext.createMarshaller();
+
+ marshaller.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, Boolean.TRUE);
+
+ marshaller.marshal(this, to);
+ } catch (JAXBException e) {
+ throw new PersistException("Unable to persist configuration", e);
+ }
+ }
+
+ public static Config fromXml(File from) {
+ if(isEmpty(from))
+ return new Config();
+
+ try {
+ JAXBContext jaxbContext = JAXBContext.newInstance(Config.class);
+ Unmarshaller um = jaxbContext.createUnmarshaller();
+
+ return (Config) um.unmarshal(from);
+ } catch (JAXBException e) {
+ throw new PersistException("Unable to restore configuration", e);
+ }
+ }
+
+ private static boolean isEmpty(File from) {
+ return from.length() == 0 || isBlank(from);
+ }
+
+ private static boolean isBlank(File from) {
+ try {
+ return StringUtils.isBlank(Files.toString(from, Charsets.UTF_8));
+ } catch (IOException e) {
+ throw new IllegalStateException("Unexpected error reading file" + from, e);
+ }
+ }
+
+ public Optional<ConfigSnapshot> getLastSnapshot() {
+ ConfigSnapshot last = Iterables.getLast(snapshots, null);
+ return last == null ? Optional.<ConfigSnapshot>absent() : Optional.of(last);
+ }
+
+ public void addConfigSnapshot(ConfigSnapshot snap, int numberOfStoredBackups) {
+ if(shouldReplaceLast(numberOfStoredBackups) && snapshots.isEmpty() == false) {
+ snapshots.remove(0);
+ }
+ snapshots.add(snap);
+ }
+
+ private boolean shouldReplaceLast(int numberOfStoredBackups) {
+ return numberOfStoredBackups == snapshots.size();
+ }
+}
--- /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.persist.storage.file.xml.model;
+
+import org.opendaylight.controller.config.persist.api.ConfigSnapshotHolder;
+
+import javax.xml.bind.annotation.XmlAnyElement;
+import javax.xml.bind.annotation.XmlElement;
+import javax.xml.bind.annotation.XmlElementWrapper;
+import javax.xml.bind.annotation.XmlRootElement;
+import java.util.SortedSet;
+
+@XmlRootElement(name = "snapshot")
+public class ConfigSnapshot {
+
+ private String configSnapshot;
+ private SortedSet<String> capabilities;
+
+ ConfigSnapshot(String configXml, SortedSet<String> capabilities) {
+ this.configSnapshot = configXml;
+ this.capabilities = capabilities;
+ }
+
+ public ConfigSnapshot() {
+ }
+
+ public static ConfigSnapshot fromConfigSnapshot(ConfigSnapshotHolder cfg) {
+ return new ConfigSnapshot(cfg.getConfigSnapshot(), cfg.getCapabilities());
+ }
+
+ @XmlAnyElement(SnapshotHandler.class)
+ public String getConfigSnapshot() {
+ return configSnapshot;
+ }
+
+ public void setConfigSnapshot(String configSnapshot) {
+ this.configSnapshot = configSnapshot;
+ }
+
+ @XmlElement(name = "capability")
+ @XmlElementWrapper(name = "required-capabilities")
+ public SortedSet<String> getCapabilities() {
+ return capabilities;
+ }
+
+ public void setCapabilities(SortedSet<String> capabilities) {
+ this.capabilities = capabilities;
+ }
+
+ @Override
+ public String toString() {
+ final StringBuffer sb = new StringBuffer("ConfigSnapshot{");
+ sb.append("configSnapshot='").append(configSnapshot).append('\'');
+ sb.append(", capabilities=").append(capabilities);
+ sb.append('}');
+ return sb.toString();
+ }
+}
--- /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.persist.storage.file.xml.model;
+
+final class PersistException extends RuntimeException {
+
+ public PersistException(String s, Exception e) {
+ super(s, e);
+ }
+}
--- /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.persist.storage.file.xml.model;
+
+import javax.xml.bind.ValidationEventHandler;
+import javax.xml.bind.annotation.DomHandler;
+import javax.xml.transform.Source;
+import javax.xml.transform.stream.StreamResult;
+import javax.xml.transform.stream.StreamSource;
+import java.io.StringReader;
+import java.io.StringWriter;
+
+class SnapshotHandler implements DomHandler<String, StreamResult> {
+
+ private static final String START_TAG = "<configuration>";
+ private static final String END_TAG = "</configuration>";
+
+ private StringWriter xmlWriter = new StringWriter();
+
+ public StreamResult createUnmarshaller(ValidationEventHandler errorHandler) {
+ xmlWriter.getBuffer().setLength(0);
+ return new StreamResult(xmlWriter);
+ }
+
+ public String getElement(StreamResult rt) {
+ String xml = rt.getWriter().toString();
+ int beginIndex = xml.indexOf(START_TAG) + START_TAG.length();
+ int endIndex = xml.indexOf(END_TAG);
+ return xml.substring(beginIndex, endIndex);
+ }
+
+ public Source marshal(String n, ValidationEventHandler errorHandler) {
+ try {
+ String xml = START_TAG + n.trim() + END_TAG;
+ StringReader xmlReader = new StringReader(xml);
+ return new StreamSource(xmlReader);
+ } catch(Exception e) {
+ throw new RuntimeException(e);
+ }
+ }
+
+}
--- /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.persist.storage.file.xml;
+
+import com.google.common.base.Charsets;
+import junit.framework.Assert;
+import org.junit.Before;
+import org.junit.Test;
+import org.mockito.Mockito;
+import org.opendaylight.controller.config.persist.api.ConfigSnapshotHolder;
+
+import java.io.File;
+import java.nio.file.Files;
+import java.util.List;
+import java.util.SortedSet;
+import java.util.TreeSet;
+
+import static junit.framework.Assert.assertFalse;
+import static org.hamcrest.CoreMatchers.is;
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertThat;
+
+public class FileStorageAdapterTest {
+
+ private static int i;
+ private File file;
+
+ @Before
+ public void setUp() throws Exception {
+ file = Files.createTempFile("testFilePersist", ".txt").toFile();
+ if (!file.exists())
+ return;
+ com.google.common.io.Files.write("", file, Charsets.UTF_8);
+ i = 1;
+ }
+
+ @Test
+ public void testFileAdapter() throws Exception {
+ XmlFileStorageAdapter storage = new XmlFileStorageAdapter();
+ storage.setFileStorage(file);
+ storage.setNumberOfBackups(Integer.MAX_VALUE);
+ final ConfigSnapshotHolder holder = new ConfigSnapshotHolder() {
+ @Override
+ public String getConfigSnapshot() {
+ return createConfig();
+ }
+
+ @Override
+ public SortedSet<String> getCapabilities() {
+ return createCaps();
+ }
+ };
+ storage.persistConfig(holder);
+
+ storage.persistConfig(holder);
+
+ assertEquals(27, com.google.common.io.Files.readLines(file, Charsets.UTF_8).size());
+ List<ConfigSnapshotHolder> lastConf = storage.loadLastConfigs();
+ assertEquals(1, lastConf.size());
+ ConfigSnapshotHolder configSnapshotHolder = lastConf.get(0);
+ assertEquals("<config>2</config>",
+ configSnapshotHolder.getConfigSnapshot().replaceAll("\\s", ""));
+ assertEquals(createCaps(), configSnapshotHolder.getCapabilities());
+
+ storage = new XmlFileStorageAdapter();
+ storage.setFileStorage(file);
+ storage.setNumberOfBackups(Integer.MAX_VALUE);
+
+ List<ConfigSnapshotHolder> last = storage.loadLastConfigs();
+ Assert.assertEquals(createCaps(), last.get(0).getCapabilities());
+ }
+
+ private SortedSet<String> createCaps() {
+ SortedSet<String> caps = new TreeSet<>();
+
+ caps.add("cap1" + i);
+ caps.add("cap2" + i);
+ caps.add("urn:opendaylight:params:xml:ns:yang:controller:netty?module=netty&revision=2013-11-19" + i);
+ caps.add("capaaaa as dasfasdf s2" + i);
+ return caps;
+ }
+
+ @Test
+ public void testFileAdapterOneBackup() throws Exception {
+ XmlFileStorageAdapter storage = new XmlFileStorageAdapter();
+ storage.setFileStorage(file);
+ storage.setNumberOfBackups(1);
+ final ConfigSnapshotHolder holder = new ConfigSnapshotHolder() {
+ @Override
+ public String getConfigSnapshot() {
+ return createConfig();
+ }
+
+ @Override
+ public SortedSet<String> getCapabilities() {
+ return createCaps();
+ }
+ };
+ storage.persistConfig(holder);
+
+ storage.persistConfig(holder);
+
+ assertEquals(16, com.google.common.io.Files.readLines(file, Charsets.UTF_8).size());
+
+ List<ConfigSnapshotHolder> lastConf = storage.loadLastConfigs();
+ assertEquals(1, lastConf.size());
+ ConfigSnapshotHolder configSnapshotHolder = lastConf.get(0);
+ assertEquals("<config>2</config>",
+ configSnapshotHolder.getConfigSnapshot().replaceAll("\\s", ""));
+ }
+
+ @Test
+ public void testFileAdapterOnlyTwoBackups() throws Exception {
+ XmlFileStorageAdapter storage = new XmlFileStorageAdapter();
+ storage.setFileStorage(file);
+ storage.setNumberOfBackups(2);
+ final ConfigSnapshotHolder holder = new ConfigSnapshotHolder() {
+ @Override
+ public String getConfigSnapshot() {
+ return createConfig();
+ }
+
+ @Override
+ public SortedSet<String> getCapabilities() {
+ return createCaps();
+ }
+ };
+ storage.persistConfig(holder);
+
+ storage.persistConfig(holder);
+ storage.persistConfig(holder);
+
+ List<String> readLines = com.google.common.io.Files.readLines(file, Charsets.UTF_8);
+ assertEquals(27, readLines.size());
+
+ List<ConfigSnapshotHolder> lastConf = storage.loadLastConfigs();
+ assertEquals(1, lastConf.size());
+ ConfigSnapshotHolder configSnapshotHolder = lastConf.get(0);
+ assertEquals("<config>3</config>",
+ configSnapshotHolder.getConfigSnapshot().replaceAll("\\s", ""));
+ assertFalse(readLines.contains(holder.getConfigSnapshot()));
+ }
+
+ @Test
+ public void testNoLastConfig() throws Exception {
+ File file = Files.createTempFile("testFilePersist", ".txt").toFile();
+ if (!file.exists())
+ return;
+ XmlFileStorageAdapter storage = new XmlFileStorageAdapter();
+ storage.setFileStorage(file);
+
+ List<ConfigSnapshotHolder> elementOptional = storage.loadLastConfigs();
+ assertThat(elementOptional.size(), is(0));
+ }
+
+ @Test(expected = NullPointerException.class)
+ public void testNoProperties() throws Exception {
+ XmlFileStorageAdapter storage = new XmlFileStorageAdapter();
+ storage.loadLastConfigs();
+ }
+
+ @Test(expected = NullPointerException.class)
+ public void testNoProperties2() throws Exception {
+ XmlFileStorageAdapter storage = new XmlFileStorageAdapter();
+ storage.persistConfig(new ConfigSnapshotHolder() {
+ @Override
+ public String getConfigSnapshot() {
+ return Mockito.mock(String.class);
+ }
+
+ @Override
+ public SortedSet<String> getCapabilities() {
+ return new TreeSet<>();
+ }
+ } );
+ }
+
+ static String createConfig() {
+ return "<config>" + i++ + "</config>";
+ }
+
+}
<groupId>${project.groupId}</groupId>
<artifactId>config-api</artifactId>
</dependency>
- <dependency>
- <groupId>org.jolokia</groupId>
- <artifactId>jolokia-client-java</artifactId>
- </dependency>
- <dependency>
- <groupId>org.jolokia</groupId>
- <artifactId>jolokia-jvm</artifactId>
- <classifier>agent</classifier>
- </dependency>
-
<!-- test dependencies -->
<dependency>
<groupId>com.google.guava</groupId>
*/
package org.opendaylight.controller.config.util;
-import java.util.Arrays;
-import java.util.List;
-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.ObjectNameUtil;
import javax.management.AttributeNotFoundException;
import javax.management.InstanceNotFoundException;
import javax.management.ObjectInstance;
import javax.management.ObjectName;
import javax.management.ReflectionException;
-
-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.ObjectNameUtil;
+import java.util.Arrays;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
public class ConfigRegistryJMXClient implements ConfigRegistryClient {
- private final ConfigRegistryMXBean configRegistryProxy;
+ private final ConfigRegistryMXBean configRegistryMXBeanProxy;
private final ObjectName configRegistryON;
private final MBeanServer configMBeanServer;
if (!(searchResult.size() == 1)) {
throw new IllegalStateException("Config registry not found");
}
- configRegistryProxy = JMX.newMXBeanProxy(configMBeanServer, configRegistryON, ConfigRegistryMXBean.class,
+ configRegistryMXBeanProxy = JMX.newMXBeanProxy(configMBeanServer, configRegistryON, ConfigRegistryMXBean.class,
false);
}
@Override
public ConfigTransactionJMXClient getConfigTransactionClient(
ObjectName objectName) {
- return new ConfigTransactionJMXClient(configRegistryProxy, objectName,
+ return new ConfigTransactionJMXClient(configRegistryMXBeanProxy, objectName,
configMBeanServer);
}
@Override
public ObjectName beginConfig() {
- return configRegistryProxy.beginConfig();
+ return configRegistryMXBeanProxy.beginConfig();
}
@Override
public CommitStatus commitConfig(ObjectName transactionControllerON)
throws ConflictingVersionException, ValidationException {
- return configRegistryProxy.commitConfig(transactionControllerON);
+ return configRegistryMXBeanProxy.commitConfig(transactionControllerON);
}
@Override
public List<ObjectName> getOpenConfigs() {
- return configRegistryProxy.getOpenConfigs();
+ return configRegistryMXBeanProxy.getOpenConfigs();
}
@Override
@Override
public Set<String> getAvailableModuleNames() {
- return configRegistryProxy.getAvailableModuleNames();
+ return configRegistryMXBeanProxy.getAvailableModuleNames();
}
@Override
public boolean isHealthy() {
- return configRegistryProxy.isHealthy();
+ return configRegistryMXBeanProxy.isHealthy();
}
@Override
public Set<ObjectName> lookupConfigBeans() {
- return configRegistryProxy.lookupConfigBeans();
+ return configRegistryMXBeanProxy.lookupConfigBeans();
}
@Override
public Set<ObjectName> lookupConfigBeans(String moduleName) {
- return configRegistryProxy.lookupConfigBeans(moduleName);
+ return configRegistryMXBeanProxy.lookupConfigBeans(moduleName);
}
@Override
public Set<ObjectName> lookupConfigBeans(String moduleName,
String instanceName) {
- return configRegistryProxy.lookupConfigBeans(moduleName, instanceName);
+ return configRegistryMXBeanProxy.lookupConfigBeans(moduleName, instanceName);
}
@Override
public ObjectName lookupConfigBean(String moduleName, String instanceName)
throws InstanceNotFoundException {
- return configRegistryProxy.lookupConfigBean(moduleName, instanceName);
+ return configRegistryMXBeanProxy.lookupConfigBean(moduleName, instanceName);
}
@Override
public Set<ObjectName> lookupRuntimeBeans() {
- return configRegistryProxy.lookupRuntimeBeans();
+ return configRegistryMXBeanProxy.lookupRuntimeBeans();
}
@Override
public Set<ObjectName> lookupRuntimeBeans(String ifcName,
String instanceName) {
- return configRegistryProxy.lookupRuntimeBeans(ifcName, instanceName);
+ return configRegistryMXBeanProxy.lookupRuntimeBeans(ifcName, instanceName);
+ }
+
+ @Override
+ public void checkConfigBeanExists(ObjectName objectName) throws InstanceNotFoundException {
+ configRegistryMXBeanProxy.checkConfigBeanExists(objectName);
+ }
+
+ @Override
+ public ObjectName lookupConfigBeanByServiceInterfaceName(String serviceInterfaceQName, String refName) {
+ return configRegistryMXBeanProxy.lookupConfigBeanByServiceInterfaceName(serviceInterfaceQName, refName);
+ }
+
+ @Override
+ public Map<String, Map<String, ObjectName>> getServiceMapping() {
+ return configRegistryMXBeanProxy.getServiceMapping();
+ }
+
+ @Override
+ public Map<String, ObjectName> lookupServiceReferencesByServiceInterfaceName(String serviceInterfaceQName) {
+ return configRegistryMXBeanProxy.lookupServiceReferencesByServiceInterfaceName(serviceInterfaceQName);
+ }
+
+ @Override
+ public Set<String> lookupServiceInterfaceNames(ObjectName objectName) throws InstanceNotFoundException {
+ return configRegistryMXBeanProxy.lookupServiceInterfaceNames(objectName);
+ }
+
+ @Override
+ public String getServiceInterfaceName(String namespace, String localName) {
+ return configRegistryMXBeanProxy.getServiceInterfaceName(namespace, localName);
}
@Override
}
}
+ @Override
+ public Set<String> getAvailableModuleFactoryQNames() {
+ return configRegistryMXBeanProxy.getAvailableModuleFactoryQNames();
+ }
+
+ @Override
+ public ObjectName getServiceReference(String serviceInterfaceQName, String refName) throws InstanceNotFoundException {
+ return configRegistryMXBeanProxy.getServiceReference(serviceInterfaceQName, refName);
+ }
+
+ @Override
+ public void checkServiceReferenceExists(ObjectName objectName) throws InstanceNotFoundException {
+ configRegistryMXBeanProxy.checkServiceReferenceExists(objectName);
+ }
+
}
*/
package org.opendaylight.controller.config.util;
+import java.util.Map;
import java.util.Set;
import javax.management.Attribute;
import org.opendaylight.controller.config.api.jmx.ObjectNameUtil;
public class ConfigTransactionJMXClient implements ConfigTransactionClient {
- private final ConfigRegistryMXBean configTransactionManagerProxy;
+ private final ConfigRegistryMXBean configRegistryMXBeanProxy;
private final ObjectName configTransactionControllerON;
- private final ConfigTransactionControllerMXBean configControllerProxy;
+ private final ConfigTransactionControllerMXBean configTransactionControllerMXBeanProxy;
private final MBeanServer configMBeanServer;
public ConfigTransactionJMXClient(
- ConfigRegistryMXBean configTransactionManagerProxy,
+ ConfigRegistryMXBean configRegistryMXBeanProxy,
ObjectName configTransactionControllerON,
MBeanServer configMBeanServer) {
this.configMBeanServer = configMBeanServer;
- this.configTransactionManagerProxy = configTransactionManagerProxy;
+ this.configRegistryMXBeanProxy = configRegistryMXBeanProxy;
this.configTransactionControllerON = configTransactionControllerON;
- this.configControllerProxy = JMX.newMXBeanProxy(configMBeanServer,
+ this.configTransactionControllerMXBeanProxy = JMX.newMXBeanProxy(configMBeanServer,
configTransactionControllerON,
ConfigTransactionControllerMXBean.class);
}
@Override
public CommitStatus commit() throws ConflictingVersionException,
ValidationException {
- return configTransactionManagerProxy
+ return configRegistryMXBeanProxy
.commitConfig(configTransactionControllerON);
}
@Override
public ObjectName createModule(String moduleName, String instanceName)
throws InstanceAlreadyExistsException {
- return configControllerProxy.createModule(moduleName, instanceName);
+ return configTransactionControllerMXBeanProxy.createModule(moduleName, instanceName);
}
@Override
public void destroyModule(ObjectName objectName)
throws InstanceNotFoundException {
- configControllerProxy.destroyModule(objectName);
+ configTransactionControllerMXBeanProxy.destroyModule(objectName);
}
@Override
@Override
public void abortConfig() {
- configControllerProxy.abortConfig();
+ configTransactionControllerMXBeanProxy.abortConfig();
}
@Override
public void validateConfig() throws ValidationException {
- configControllerProxy.validateConfig();
+ configTransactionControllerMXBeanProxy.validateConfig();
}
@Override
@Override
public String getTransactionName() {
- return configControllerProxy.getTransactionName();
+ return configTransactionControllerMXBeanProxy.getTransactionName();
}
@Override
public Set<String> getAvailableModuleNames() {
- return configControllerProxy.getAvailableModuleNames();
+ return configTransactionControllerMXBeanProxy.getAvailableModuleNames();
}
@Override
@Override
public Set<ObjectName> lookupConfigBeans() {
- return configControllerProxy.lookupConfigBeans();
+ return configTransactionControllerMXBeanProxy.lookupConfigBeans();
}
@Override
public Set<ObjectName> lookupConfigBeans(String moduleName) {
- return configControllerProxy.lookupConfigBeans(moduleName);
+ return configTransactionControllerMXBeanProxy.lookupConfigBeans(moduleName);
}
@Override
public ObjectName lookupConfigBean(String moduleName, String instanceName)
throws InstanceNotFoundException {
- return configControllerProxy.lookupConfigBean(moduleName, instanceName);
+ return configTransactionControllerMXBeanProxy.lookupConfigBean(moduleName, instanceName);
}
@Override
public Set<ObjectName> lookupConfigBeans(String moduleName,
String instanceName) {
- return configControllerProxy
+ return configTransactionControllerMXBeanProxy
.lookupConfigBeans(moduleName, instanceName);
}
+ @Override
+ public void checkConfigBeanExists(ObjectName objectName) throws InstanceNotFoundException {
+ configTransactionControllerMXBeanProxy.checkConfigBeanExists(objectName);
+ }
+
+ @Override
+ public ObjectName saveServiceReference(String serviceInterfaceName, String refName, ObjectName moduleON) throws InstanceNotFoundException {
+ return configTransactionControllerMXBeanProxy.saveServiceReference(serviceInterfaceName,refName, moduleON);
+ }
+
+ @Override
+ public void removeServiceReference(String serviceInterfaceName, String refName) throws InstanceNotFoundException{
+ configTransactionControllerMXBeanProxy.removeServiceReference(serviceInterfaceName, refName);
+ }
+
+ @Override
+ public void removeAllServiceReferences() {
+ configTransactionControllerMXBeanProxy.removeAllServiceReferences();
+ }
+
+ @Override
+ public ObjectName lookupConfigBeanByServiceInterfaceName(String serviceInterfaceQName, String refName) {
+ return configTransactionControllerMXBeanProxy.lookupConfigBeanByServiceInterfaceName(serviceInterfaceQName, refName);
+ }
+
+ @Override
+ public Map<String, Map<String, ObjectName>> getServiceMapping() {
+ return configTransactionControllerMXBeanProxy.getServiceMapping();
+ }
+
+ @Override
+ public Map<String, ObjectName> lookupServiceReferencesByServiceInterfaceName(String serviceInterfaceQName) {
+ return configTransactionControllerMXBeanProxy.lookupServiceReferencesByServiceInterfaceName(serviceInterfaceQName);
+ }
+
+ @Override
+ public Set<String> lookupServiceInterfaceNames(ObjectName objectName) throws InstanceNotFoundException {
+ return configTransactionControllerMXBeanProxy.lookupServiceInterfaceNames(objectName);
+ }
+
+ @Override
+ public String getServiceInterfaceName(String namespace, String localName) {
+ return configTransactionControllerMXBeanProxy.getServiceInterfaceName(namespace, localName);
+ }
+
+ @Override
+ public boolean removeServiceReferences(ObjectName objectName) throws InstanceNotFoundException {
+ return configTransactionControllerMXBeanProxy.removeServiceReferences(objectName);
+ }
+
+ @Override
+ public ObjectName getServiceReference(String serviceInterfaceQName, String refName) throws InstanceNotFoundException {
+ return configTransactionControllerMXBeanProxy.getServiceReference(serviceInterfaceQName, refName);
+ }
+
+ @Override
+ public void checkServiceReferenceExists(ObjectName objectName) throws InstanceNotFoundException {
+ configTransactionControllerMXBeanProxy.checkServiceReferenceExists(objectName);
+ }
+
@Override
public void validateBean(ObjectName configBeanON)
throws ValidationException {
+ attrName + " for " + on, e);
}
}
+
+ @Override
+ public Set<String> getAvailableModuleFactoryQNames() {
+ return configTransactionControllerMXBeanProxy.getAvailableModuleFactoryQNames();
+ }
}
+++ /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.util.jolokia;
-
-import java.util.List;
-import java.util.Set;
-
-import javax.management.ObjectName;
-
-import org.jolokia.client.request.J4pExecRequest;
-import org.jolokia.client.request.J4pReadRequest;
-import org.jolokia.client.request.J4pResponse;
-import org.json.simple.JSONArray;
-import org.json.simple.JSONObject;
-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.ObjectNameUtil;
-import org.opendaylight.controller.config.util.ConfigRegistryClient;
-
-public class ConfigRegistryJolokiaClient extends ListableJolokiaClient
- implements ConfigRegistryClient {
-
- public ConfigRegistryJolokiaClient(String url) {
- super(url, ConfigRegistryMXBean.OBJECT_NAME);
- }
-
- @Override
- public ConfigTransactionJolokiaClient createTransaction() {
- // create transaction
- J4pExecRequest execReq = new J4pExecRequest(objectName, "beginConfig");
- J4pResponse<J4pExecRequest> resp = execute(execReq);
- ObjectName transactionControllerON = extractObjectName(resp);
- return getConfigTransactionClient(transactionControllerON);
- }
-
- @Override
- public ConfigTransactionJolokiaClient getConfigTransactionClient(
- String transactionName) {
- ObjectName objectName = ObjectNameUtil
- .createTransactionControllerON(transactionName);
- return getConfigTransactionClient(objectName);
- }
-
- @Override
- public ConfigTransactionJolokiaClient getConfigTransactionClient(
- ObjectName objectName) {
- return new ConfigTransactionJolokiaClient(url, objectName, this);
- }
-
- @Override
- public CommitStatus commitConfig(ObjectName transactionControllerON)
- throws ConflictingVersionException, ValidationException {
- J4pExecRequest execReq = new J4pExecRequest(objectName, "commitConfig",
- transactionControllerON);
- JSONObject jsonObject;
- jsonObject = execute(execReq).getValue();
- JSONArray newInstancesArray = (JSONArray) jsonObject
- .get("newInstances");
- List<ObjectName> newInstances = jsonArrayToObjectNames(newInstancesArray);
- JSONArray reusedInstancesArray = (JSONArray) jsonObject
- .get("reusedInstances");
- List<ObjectName> reusedInstances = jsonArrayToObjectNames(reusedInstancesArray);
- JSONArray recreatedInstancesArray = (JSONArray) jsonObject
- .get("recreatedInstances");
- List<ObjectName> recreatedInstances = jsonArrayToObjectNames(recreatedInstancesArray);
- return new CommitStatus(newInstances, reusedInstances,
- recreatedInstances);
- }
-
- public Object getAttribute(ObjectName configBeanTransactionON, String key) {
- J4pReadRequest req = new J4pReadRequest(configBeanTransactionON, key);
- return execute(req).getValue();
- }
-
- public ObjectName getAttributeON(ObjectName configBeanTransactionON,
- String key) {
- JSONObject jsonAttrib = (JSONObject) getAttribute(
- configBeanTransactionON, key);
- return extractObjectName(jsonAttrib);
- }
-
- // proxy around ConfigTransactionManagerMXBean
-
- @Override
- public ObjectName beginConfig() {
- ConfigTransactionJolokiaClient result = createTransaction();
- return result.getTransactionON();
- }
-
- @Override
- public List<ObjectName> getOpenConfigs() {
- J4pReadRequest req = new J4pReadRequest(objectName, "OpenConfigs");
- JSONArray jsonArray = execute(req).getValue();
- return jsonArrayToObjectNames(jsonArray);
- }
-
- @Override
- public long getVersion() {
- J4pReadRequest req = new J4pReadRequest(objectName, "Version");
- return (Long) execute(req).getValue();
- }
-
- @Override
- public boolean isHealthy() {
- J4pReadRequest req = new J4pReadRequest(objectName, "Healthy");
- return (Boolean) execute(req).getValue();
- }
-
- @Override
- public Set<ObjectName> lookupRuntimeBeans() {
- return lookupSomething("lookupRuntimeBeans()", new Object[0]);
- }
-
- @Override
- public Set<ObjectName> lookupRuntimeBeans(String moduleName,
- String instanceName) {
- return lookupSomething(
- "lookupRuntimeBeans(java.lang.String,java.lang.String)",
- new Object[] { moduleName, instanceName });
- }
-
- @Override
- public Object invokeMethod(ObjectName on, String name, Object[] params,
- String[] signature) {
- throw new UnsupportedOperationException();
- }
-
- @Override
- public Object getAttributeCurrentValue(ObjectName on, String attributeName) {
- throw new UnsupportedOperationException();
- }
-}
+++ /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.util.jolokia;
-
-import java.util.Map;
-
-import javax.management.Attribute;
-import javax.management.AttributeNotFoundException;
-import javax.management.InstanceAlreadyExistsException;
-import javax.management.InstanceNotFoundException;
-import javax.management.ObjectName;
-
-import org.jolokia.client.request.J4pExecRequest;
-import org.jolokia.client.request.J4pReadRequest;
-import org.jolokia.client.request.J4pWriteRequest;
-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.ObjectNameUtil;
-import org.opendaylight.controller.config.util.AttributeEntry;
-import org.opendaylight.controller.config.util.ConfigTransactionClient;
-
-public class ConfigTransactionJolokiaClient extends ListableJolokiaClient
- implements ConfigTransactionClient {
-
- private final ConfigRegistryJolokiaClient configRegistryJolokiaClient;
-
- public ConfigTransactionJolokiaClient(String url,
- ObjectName transactionControllerON,
- ConfigRegistryJolokiaClient configRegistryJolokiaClient) {
- super(url, transactionControllerON);
- this.configRegistryJolokiaClient = configRegistryJolokiaClient;
- }
-
- public ObjectName getTransactionON() {
- return objectName;
- }
-
- @Override
- public CommitStatus commit() throws ConflictingVersionException,
- ValidationException {
- return configRegistryJolokiaClient.commitConfig(objectName);
- }
-
- @Override
- public ObjectName createModule(String moduleName, String instanceName)
- throws InstanceAlreadyExistsException {
- J4pExecRequest execReq = new J4pExecRequest(objectName, "createModule",
- moduleName, instanceName);
- try {
- return extractObjectName(execute(execReq));
- } catch (RuntimeException e) {
- if (e.getMessage() != null
- && e.getMessage().startsWith(
- InstanceAlreadyExistsException.class.getName()))
- throw new InstanceAlreadyExistsException();
- throw e;
- }
- }
-
- @Override
- public void destroyModule(ObjectName configBeanON) {
- J4pExecRequest execReq = new J4pExecRequest(objectName,
- "destroyModule(javax.management.ObjectName)", configBeanON);
- execute(execReq);
- }
-
- @Override
- public void destroyConfigBean(String moduleName, String instanceName)
- throws InstanceNotFoundException {
- destroyModule(ObjectNameUtil.createTransactionModuleON(
- getTransactionName(), moduleName, instanceName));
- }
-
- @Override
- public void abortConfig() {
- J4pExecRequest execReq = new J4pExecRequest(objectName, "abortConfig");
- execute(execReq);
- }
-
- @Override
- public void validateConfig() throws ValidationException {
- J4pExecRequest execReq = new J4pExecRequest(objectName,
- "validateConfig");
- execute(execReq);
- }
-
- @Override
- public long getParentVersion() {
- J4pReadRequest req = new J4pReadRequest(objectName, "ParentVersion");
- return (Long) execute(req).getValue();
- }
-
- @Override
- public long getVersion() {
- J4pReadRequest req = new J4pReadRequest(objectName, "Version");
- return (Long) execute(req).getValue();
- }
-
- public void setAttribute(ObjectName configBeanTransactionON, String key,
- Object value) {
- J4pWriteRequest req = new J4pWriteRequest(configBeanTransactionON, key,
- value);
- try {
- execute(req);
- } catch (RuntimeException e) {
- if (e.getMessage() != null
- && e.getMessage().startsWith(
- AttributeNotFoundException.class.getName())) {
- // try to fix wrong case
- Map<String, AttributeEntry> allAttributes = getAttributes(configBeanTransactionON);
- for (AttributeEntry attrib : allAttributes.values()) {
- if (attrib.getKey().equalsIgnoreCase(key)) {
- req = new J4pWriteRequest(configBeanTransactionON,
- attrib.getKey(), value);
- execute(req);
- return;
- }
- }
- }
- throw e;
- }
- }
-
- public Object getAttribute(ObjectName objectName, String key) {
- return configRegistryJolokiaClient.getAttribute(objectName, key);
- }
-
- public ObjectName getAttributeON(ObjectName objectName, String key) {
- return configRegistryJolokiaClient.getAttributeON(objectName, key);
- }
-
- @Override
- public String getTransactionName() {
- return ObjectNameUtil.getTransactionName(objectName);
- }
-
- @Override
- public void validateBean(ObjectName rwON) throws ValidationException {
- J4pExecRequest req = new J4pExecRequest(rwON, "validate", new Object[0]);
- execute(req);
- }
-
- @Override
- public void assertVersion(int expectedParentVersion,
- int expectedCurrentVersion) {
- if (expectedParentVersion != getParentVersion()) {
- throw new IllegalStateException();
- }
- if (expectedCurrentVersion != getVersion()) {
- throw new IllegalStateException();
- }
- }
-
- @Override
- public void setAttribute(ObjectName on, String jmxName, Attribute attribute) {
- throw new UnsupportedOperationException();
- }
-
-}
+++ /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.util.jolokia;
-
-import java.util.ArrayList;
-import java.util.Arrays;
-import java.util.Collections;
-import java.util.HashMap;
-import java.util.HashSet;
-import java.util.List;
-import java.util.Map;
-import java.util.Map.Entry;
-import java.util.Set;
-import java.util.regex.Pattern;
-
-import javax.management.InstanceNotFoundException;
-import javax.management.MalformedObjectNameException;
-import javax.management.ObjectName;
-
-import org.jolokia.client.J4pClient;
-import org.jolokia.client.exception.J4pException;
-import org.jolokia.client.exception.J4pRemoteException;
-import org.jolokia.client.request.J4pExecRequest;
-import org.jolokia.client.request.J4pListRequest;
-import org.jolokia.client.request.J4pQueryParameter;
-import org.jolokia.client.request.J4pReadRequest;
-import org.jolokia.client.request.J4pRequest;
-import org.jolokia.client.request.J4pResponse;
-import org.json.simple.JSONArray;
-import org.json.simple.JSONObject;
-import org.opendaylight.controller.config.api.ConflictingVersionException;
-import org.opendaylight.controller.config.api.ValidationException;
-import org.opendaylight.controller.config.api.ValidationException.ExceptionMessageWithStackTrace;
-import org.opendaylight.controller.config.api.jmx.ObjectNameUtil;
-import org.opendaylight.controller.config.util.AttributeEntry;
-
-abstract class ListableJolokiaClient {
- protected final J4pClient j4pClient;
- protected final String url;
- protected final ObjectName objectName;
-
- public ListableJolokiaClient(String url, ObjectName objectName) {
- if (url == null) {
- throw new NullPointerException("Parameter 'url' is null");
- }
- if (!url.endsWith("/")) {
- throw new IllegalArgumentException(
- "Parameter 'url' must end with '/'");
- }
-
- this.url = url;
- this.j4pClient = new J4pClient(url);
- this.objectName = objectName;
- }
-
- public ObjectName getObjectName() {
- return objectName;
- }
-
- protected <R extends J4pResponse<T>, T extends J4pRequest> R execute(
- T pRequest) {
- try {
- Map<J4pQueryParameter, String> pProcessingOptions = new HashMap<J4pQueryParameter, String>();
- pProcessingOptions
- .put(J4pQueryParameter.INCLUDE_STACKTRACE, "true");
- pProcessingOptions.put(J4pQueryParameter.SERIALIZE_EXCEPTION,
- "true");
- return j4pClient.execute(pRequest, "POST", pProcessingOptions);
- } catch (J4pRemoteException e) {
- tryToConvertException(e.getRemoteStackTrace(), e.getErrorValue());
- throw new RuntimeException(e.getRemoteStackTrace(), e);
- } catch (J4pException e) {
- throw new RuntimeException(e);
- }
- }
-
- protected void tryToConvertException(String remoteStackTrace,
- JSONObject errorValue) {
- String conflictPrefix = ConflictingVersionException.class.getName()
- + ": ";
- if (remoteStackTrace.startsWith(conflictPrefix)) {
- remoteStackTrace = remoteStackTrace.substring(conflictPrefix
- .length());
- Pattern p = Pattern.compile("\r?\n");
- remoteStackTrace = Arrays.asList(p.split(remoteStackTrace))
- .iterator().next();
- throw new ConflictingVersionException(remoteStackTrace);
- }
- String validationExceptionPrefix = ValidationException.class.getName();
- if (remoteStackTrace.startsWith(validationExceptionPrefix)) {
- throw createValidationExceptionFromJSONObject(errorValue);
- }
- }
-
- static ValidationException createValidationExceptionFromJSONObject(
- JSONObject errorValue) {
- String fValsKey = "failedValidations";
- JSONObject failedVals = (JSONObject) errorValue.get(fValsKey);
-
- checkArgument(
- !failedVals.isEmpty(),
- fValsKey + " was not present in received JSON: "
- + errorValue.toJSONString());
- Map<String, Map<String, ExceptionMessageWithStackTrace>> failedValsMap = new HashMap<String, Map<String, ExceptionMessageWithStackTrace>>();
-
- for (Object key : failedVals.keySet()) {
- checkArgument(key instanceof String, "Unexpected key " + key
- + ", expected instance of String");
- Map<String, ExceptionMessageWithStackTrace> innerMap = new HashMap<String, ValidationException.ExceptionMessageWithStackTrace>();
- for (Object innerKey : ((JSONObject) failedVals.get(key)).keySet()) {
- checkArgument(innerKey instanceof String, "Unexpected key "
- + innerKey + ", expected instance of String");
- JSONObject exWithStackTraceVal = (JSONObject) (((JSONObject) failedVals
- .get(key)).get(innerKey));
- Object mess = exWithStackTraceVal.get("message");
- Object stack = exWithStackTraceVal.get("trace");
- checkArgument(mess != null && stack != null,
- "\"Message\" and \"trace\" elements expected in received json: "
- + errorValue.toJSONString());
- innerMap.put(innerKey.toString(),
- new ExceptionMessageWithStackTrace((String) mess,
- (String) stack));
- }
- failedValsMap.put((String) key, innerMap);
- }
- return new ValidationException(failedValsMap);
- }
-
- private static void checkArgument(boolean b, String string) {
- if (b == false)
- throw new IllegalArgumentException(string);
- }
-
- public String getUrl() {
- return url;
- }
-
- public Map<String, AttributeEntry> getAttributes(ObjectName on) {
- J4pListRequest req = new J4pListRequest(on);
- J4pResponse<J4pListRequest> response = execute(req);
- JSONObject listJSONResponse = response.getValue();
- JSONObject attributes = (JSONObject) listJSONResponse.get("attr");
-
- // Empty attributes list
- if(attributes == null)
- return Collections.emptyMap();
-
- Map<String, JSONObject> listMap = new HashMap<>();
-
- for (Object entryObject : attributes.entrySet()) {
- Entry<String, Object> entry = (Entry<String, Object>) entryObject;
- JSONObject entryVal = (JSONObject) entry.getValue();
-
- // read value
- listMap.put(entry.getKey(), entryVal);
- }
- J4pReadRequest j4pReadRequest = new J4pReadRequest(on, listMap.keySet()
- .toArray(new String[0]));
- J4pResponse<J4pReadRequest> readResponse = execute(j4pReadRequest);
- Object readResponseValue = readResponse.getValue();
- // readResponseValue can be String if there is just one attribute or
- // JSONObject
- Map<String, Object> attribsToValues = new HashMap<String, Object>();
- if (readResponseValue instanceof JSONObject) {
- JSONObject readJSONResponse = (JSONObject) readResponseValue;
- for (Object entryObject : readJSONResponse.entrySet()) {
- Entry<String, Object> entry = (Entry<String, Object>) entryObject;
- String key = entry.getKey();
- Object value = entry.getValue();
- attribsToValues.put(key, value);
- }
- }
-
- Map<String, AttributeEntry> resultMap = new HashMap<String, AttributeEntry>();
- for (Entry<String, JSONObject> entry : listMap.entrySet()) {
- String key = entry.getKey();
- Object value = attribsToValues.size() > 0 ? attribsToValues
- .get(key) : readResponseValue;
- JSONObject listJSON = entry.getValue();
- String description = (String) listJSON.get("desc");
- String type = (String) listJSON.get("type");
- boolean rw = (Boolean) listJSON.get("rw");
- AttributeEntry attributeEntry = new AttributeEntry(key,
- description, value, type, rw);
- resultMap.put(key, attributeEntry);
- }
-
- return resultMap;
- }
-
- public String getConfigBeanDescripton(ObjectName on) {
- J4pListRequest req = new J4pListRequest(on);
- J4pResponse<J4pListRequest> response = execute(req);
- JSONObject jsonDesc = response.getValue();
- Object description = jsonDesc.get("desc");
- return description == null ? null : description.toString();
- }
-
- protected List<ObjectName> jsonArrayToObjectNames(JSONArray jsonArray) {
- List<ObjectName> result = new ArrayList<>(jsonArray.size());
- for (Object entry : jsonArray) {
- JSONObject jsonObject = (JSONObject) entry;
- String objectNameString = (String) jsonObject.get("objectName");
- try {
- result.add(new ObjectName(objectNameString));
- } catch (MalformedObjectNameException e) {
- throw new IllegalStateException("Cannot convert "
- + objectNameString + " to ObjectName", e);
- }
- }
- return result;
- }
-
- protected ObjectName extractObjectName(J4pResponse<J4pExecRequest> resp) {
- JSONObject jsonResponse = resp.getValue();
- return extractObjectName(jsonResponse);
- }
-
- protected ObjectName extractObjectName(JSONObject jsonResponse) {
- String result = jsonResponse.get("objectName").toString();
- return ObjectNameUtil.createON(result);
- }
-
- protected Set<ObjectName> lookupSomething(String signature,
- Object[] parameters) {
- J4pExecRequest req = new J4pExecRequest(objectName, signature,
- parameters);
- JSONArray jsonArray = execute(req).getValue();
- return new HashSet<>(jsonArrayToObjectNames(jsonArray));
- }
-
- public Set<ObjectName> lookupConfigBeans() {
- return lookupSomething("lookupConfigBeans()", new Object[0]);
- }
-
- public Set<ObjectName> lookupConfigBeans(String ifcName) {
- return lookupSomething("lookupConfigBeans(java.lang.String)",
- new Object[] { ifcName });
- }
-
- public Set<ObjectName> lookupConfigBeans(String ifcName, String instanceName) {
- return lookupSomething(
- "lookupConfigBeans(java.lang.String,java.lang.String)",
- new Object[] { ifcName, instanceName });
- }
-
- public ObjectName lookupConfigBean(String ifcName, String instanceName)
- throws InstanceNotFoundException {
- J4pExecRequest req = new J4pExecRequest(objectName,
- "lookupConfigBean(java.lang.String,java.lang.String)",
- new Object[] { ifcName, instanceName });
- try {
- J4pResponse<J4pExecRequest> resp = execute(req);
- return extractObjectName(resp);
- } catch (RuntimeException e) {
- if (e.getMessage() != null
- && e.getMessage().startsWith(
- InstanceNotFoundException.class.getName()))
- throw new InstanceNotFoundException();
- throw e;
- }
- }
-
- public Set<String> getAvailableModuleNames() {
- J4pReadRequest req = new J4pReadRequest(objectName,
- "AvailableModuleNames");
- List<String> value = execute(req).getValue();
- return new HashSet<>(value);
- }
-}
*/
package org.opendaylight.controller.config.util;
-import static org.hamcrest.core.Is.is;
-import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertThat;
-import static org.junit.Assert.fail;
-import static org.junit.matchers.JUnitMatchers.containsString;
-
-import java.lang.management.ManagementFactory;
-import java.util.Set;
+import com.google.common.collect.Sets;
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Test;
+import org.opendaylight.controller.config.api.ConfigRegistry;
import javax.management.InstanceNotFoundException;
import javax.management.MBeanServer;
import javax.management.ObjectName;
+import java.lang.management.ManagementFactory;
+import java.util.Set;
-import org.junit.After;
-import org.junit.Before;
-import org.junit.Test;
-import org.opendaylight.controller.config.api.ConfigRegistry;
-import org.opendaylight.controller.config.api.ValidationException;
-import org.opendaylight.controller.config.util.jolokia.ConfigRegistryJolokiaClient;
+import static org.junit.Assert.assertEquals;
public class ConfigRegistryClientsTest {
- private String jolokiaURL;
-
private TestingConfigRegistry testingRegistry;
private ObjectName testingRegistryON;
private final MBeanServer mbs = ManagementFactory.getPlatformMBeanServer();
- private ConfigRegistryClient jmxRegistryClient, jolokiaRegistryClient;
+ private ConfigRegistryClient jmxRegistryClient;
@Before
public void setUp() throws Exception {
- jolokiaURL = JolokiaHelper.startTestingJolokia();
testingRegistry = new TestingConfigRegistry();
testingRegistryON = ConfigRegistry.OBJECT_NAME;
mbs.registerMBean(testingRegistry, testingRegistryON);
jmxRegistryClient = new ConfigRegistryJMXClient(
ManagementFactory.getPlatformMBeanServer());
- jolokiaRegistryClient = new ConfigRegistryJolokiaClient(jolokiaURL);
}
@After
public void cleanUp() throws Exception {
- JolokiaHelper.stopJolokia();
if (testingRegistryON != null) {
mbs.unregisterMBean(testingRegistryON);
}
@Test
public void testLookupRuntimeBeans() throws Exception {
Set<ObjectName> jmxLookup = lookupRuntimeBeans(jmxRegistryClient);
- Set<ObjectName> jolokiaLookup = lookupRuntimeBeans(jolokiaRegistryClient);
- assertEquals(jmxLookup, jolokiaLookup);
+ assertEquals(Sets.newHashSet(testingRegistry.run2, testingRegistry.run1, testingRegistry.run3), jmxLookup);
}
private Set<ObjectName> lookupRuntimeBeans(ConfigRegistryClient client)
jmxRegistryClient, TestingConfigRegistry.moduleName1,
TestingConfigRegistry.instName1);
assertEquals(1, jmxLookup.size());
- Set<ObjectName> jolokiaLookup = clientLookupRuntimeBeansWithModuleAndInstance(
- jolokiaRegistryClient, TestingConfigRegistry.moduleName1,
- TestingConfigRegistry.instName1);
- assertEquals(jmxLookup, jolokiaLookup);
+ assertEquals(Sets.newHashSet(testingRegistry.run2), jmxLookup);
jmxLookup = clientLookupRuntimeBeansWithModuleAndInstance(
jmxRegistryClient, TestingConfigRegistry.moduleName2,
TestingConfigRegistry.instName2);
assertEquals(1, jmxLookup.size());
- jolokiaLookup = clientLookupRuntimeBeansWithModuleAndInstance(
- jolokiaRegistryClient, TestingConfigRegistry.moduleName2,
- TestingConfigRegistry.instName2);
- assertEquals(jmxLookup, jolokiaLookup);
+ assertEquals(Sets.newHashSet(testingRegistry.run3), jmxLookup);
jmxLookup = clientLookupRuntimeBeansWithModuleAndInstance(
jmxRegistryClient, TestingConfigRegistry.moduleName1,
TestingConfigRegistry.instName2);
assertEquals(0, jmxLookup.size());
- jolokiaLookup = clientLookupRuntimeBeansWithModuleAndInstance(
- jolokiaRegistryClient, TestingConfigRegistry.moduleName1,
- TestingConfigRegistry.instName2);
- assertEquals(jmxLookup, jolokiaLookup);
+ assertEquals(Sets.newHashSet(), jmxLookup);
}
private Set<ObjectName> clientLookupRuntimeBeansWithModuleAndInstance(
}
return beans;
}
-
- @Test
- public void testValidationExceptionDeserialization() {
- try {
- jolokiaRegistryClient.commitConfig(null);
- fail();
- } catch (ValidationException e) {
- String moduleName = "moduleName", instanceName = "instanceName";
- assertThat(e.getFailedValidations().containsKey(moduleName),
- is(true));
- assertThat(e.getFailedValidations().size(), is(1));
- assertThat(e.getFailedValidations().get(moduleName).size(), is(1));
- assertThat(
- e.getFailedValidations().get(moduleName)
- .containsKey(instanceName), is(true));
- assertThat(
- e.getFailedValidations().get(moduleName).get(instanceName)
- .getMessage(), is("message"));
- assertThat(
- e.getFailedValidations().get(moduleName).get(instanceName)
- .getTrace(),
- containsString("org.opendaylight.controller.config.util.TestingConfigRegistry.commitConfig"));
- }
- }
-
}
*/
package org.opendaylight.controller.config.util;
-import static org.junit.Assert.assertEquals;
-
-import java.lang.management.ManagementFactory;
-import java.util.Set;
-
-import javax.management.MBeanServer;
-import javax.management.ObjectName;
-
+import com.google.common.collect.Sets;
import org.junit.After;
import org.junit.Before;
import org.junit.Test;
-import org.opendaylight.controller.config.api.jmx.ConfigTransactionControllerMXBean;
import org.opendaylight.controller.config.api.jmx.ObjectNameUtil;
-import org.opendaylight.controller.config.util.jolokia.ConfigTransactionJolokiaClient;
-public class ConfigTransactionClientsTest {
+import javax.management.MBeanServer;
+import javax.management.ObjectName;
+import java.lang.management.ManagementFactory;
+import java.util.Set;
+import static org.junit.Assert.assertEquals;
+
+public class ConfigTransactionClientsTest {
private final MBeanServer mbs = ManagementFactory.getPlatformMBeanServer();
- private String jolokiaURL;
- private ConfigTransactionControllerMXBean transactionController;
+ private TestingConfigTransactionController transactionController;
private ObjectName transactionControllerON;
- private ConfigTransactionClient jmxTransactionClient,
- jolokiaTransactionClient;
+ private ConfigTransactionClient jmxTransactionClient;
@Before
public void setUp() throws Exception {
- jolokiaURL = JolokiaHelper.startTestingJolokia();
transactionController = new TestingConfigTransactionController();
transactionControllerON = new ObjectName(ObjectNameUtil.ON_DOMAIN + ":"
+ ObjectNameUtil.TYPE_KEY + "=TransactionController");
mbs.registerMBean(transactionController, transactionControllerON);
- jmxTransactionClient = new ConfigTransactionJMXClient(null,
- transactionControllerON,
+ jmxTransactionClient = new ConfigTransactionJMXClient(null, transactionControllerON,
ManagementFactory.getPlatformMBeanServer());
- jolokiaTransactionClient = new ConfigTransactionJolokiaClient(
- jolokiaURL, transactionControllerON, null);
}
@After
public void cleanUp() throws Exception {
- JolokiaHelper.stopJolokia();
if (transactionControllerON != null) {
mbs.unregisterMBean(transactionControllerON);
}
@Test
public void testLookupConfigBeans() throws Exception {
Set<ObjectName> jmxLookup = testClientLookupConfigBeans(jmxTransactionClient);
- Set<ObjectName> jolokiaLookup = testClientLookupConfigBeans(jolokiaTransactionClient);
- assertEquals(jmxLookup, jolokiaLookup);
+ assertEquals(Sets.newHashSet(transactionController.conf1,
+ transactionController.conf2, transactionController.conf3), jmxLookup);
}
private Set<ObjectName> testClientLookupConfigBeans(
assertEquals(3, beans.size());
return beans;
}
-
}
+++ /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.util;
-
-import org.jolokia.jvmagent.JolokiaServer;
-import org.jolokia.jvmagent.JvmAgentConfig;
-
-public class JolokiaHelper {
- private static JolokiaServer jolokiaServer;
-
- /**
- * Bind to port 17777. By convention, ports above 10000 are used for testing
- * and < 10000 for production
- *
- * @return url that can be passed to new J4pClient(url)
- */
- public static String startTestingJolokia() {
- return startJolokia("localhost", 17777);
- }
-
- /**
- * @return url that can be passed to new J4pClient(url)
- * @throws IOException
- */
- public static String startJolokia(String host, int port) {
- String agentArgs = "host=" + host + ",port=" + port;
- JvmAgentConfig config = new JvmAgentConfig(agentArgs);
- Exception lastException = null;
- for (int i = 0; i < 10; i++) {
- try {
- jolokiaServer = new JolokiaServer(config, false);
- jolokiaServer.start();
- return "http://" + host + ":" + port + "/jolokia/";
- } catch (Exception e) {
- lastException = e;
- try {
- Thread.sleep(100);
- } catch (InterruptedException ie) {
- ie.printStackTrace();
- }
- }
- }
- throw new RuntimeException(lastException);
- }
-
- public static void stopJolokia() {
- jolokiaServer.stop();
- }
-}
*/
package org.opendaylight.controller.config.util;
-import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.fail;
-
-import java.lang.management.ManagementFactory;
-import java.lang.reflect.Method;
-import java.util.Map;
-import java.util.Map.Entry;
-import java.util.Set;
-
-import javax.management.InstanceNotFoundException;
-import javax.management.MBeanServer;
-import javax.management.ObjectName;
-
+import com.google.common.collect.ImmutableMap;
+import com.google.common.collect.Sets;
import org.junit.After;
import org.junit.Before;
import org.junit.Test;
import org.opendaylight.controller.config.api.LookupRegistry;
import org.opendaylight.controller.config.api.jmx.ConfigTransactionControllerMXBean;
import org.opendaylight.controller.config.api.jmx.ObjectNameUtil;
-import org.opendaylight.controller.config.util.jolokia.ConfigRegistryJolokiaClient;
-import org.opendaylight.controller.config.util.jolokia.ConfigTransactionJolokiaClient;
-import com.google.common.collect.ImmutableMap;
-import com.google.common.collect.Sets;
+import javax.management.InstanceNotFoundException;
+import javax.management.MBeanServer;
+import javax.management.ObjectName;
+import java.lang.management.ManagementFactory;
+import java.lang.reflect.Method;
+import java.util.HashSet;
+import java.util.Map;
+import java.util.Map.Entry;
+import java.util.Set;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.fail;
public class LookupTest {
- private String jolokiaURL;
private TestingConfigRegistry testingRegistry;
private ObjectName testingRegistryON;
private final MBeanServer mbs = ManagementFactory.getPlatformMBeanServer();
- private ConfigRegistryClient jmxRegistryClient, jolokiaRegistryClient;
+ private ConfigRegistryClient jmxRegistryClient;
private ConfigTransactionControllerMXBean testingTransactionController;
private ObjectName testingTransactionControllerON;
- private ConfigTransactionClient jmxTransactionClient,
- jolokiaTransactionClient;
+ private ConfigTransactionClient jmxTransactionClient;
Map<LookupRegistry, ? extends Set<? extends LookupRegistry>> lookupProvidersToClients;
@Before
public void setUp() throws Exception {
- jolokiaURL = JolokiaHelper.startTestingJolokia();
testingRegistry = new TestingConfigRegistry();
testingRegistryON = ConfigRegistry.OBJECT_NAME;
mbs.registerMBean(testingRegistry, testingRegistryON);
jmxRegistryClient = new ConfigRegistryJMXClient(
ManagementFactory.getPlatformMBeanServer());
- jolokiaRegistryClient = new ConfigRegistryJolokiaClient(jolokiaURL);
+
testingTransactionController = new TestingConfigTransactionController();
testingTransactionControllerON = new ObjectName(
jmxTransactionClient = new ConfigTransactionJMXClient(null,
testingTransactionControllerON,
ManagementFactory.getPlatformMBeanServer());
- jolokiaTransactionClient = new ConfigTransactionJolokiaClient(
- jolokiaURL, testingTransactionControllerON, null);
- lookupProvidersToClients = ImmutableMap
- .of(testingRegistry, Sets.newHashSet(jmxRegistryClient, jolokiaRegistryClient),
- testingTransactionController, Sets.newHashSet(jmxTransactionClient, jolokiaTransactionClient));
+
+ HashSet<ConfigRegistryClient> registryClients = Sets.newHashSet(jmxRegistryClient);
+ HashSet<ConfigTransactionClient> configTransactionClients = Sets.newHashSet(jmxTransactionClient);
+ lookupProvidersToClients = ImmutableMap.of((LookupRegistry) testingRegistry, registryClients,
+ testingTransactionController, configTransactionClients);
}
@After
public void cleanUp() throws Exception {
- JolokiaHelper.stopJolokia();
mbs.unregisterMBean(testingRegistryON);
mbs.unregisterMBean(testingTransactionControllerON);
}
package org.opendaylight.controller.config.util;
import java.util.List;
+import java.util.Map;
import java.util.Set;
import javax.management.InstanceNotFoundException;
}
}
+ @Override
+ public void checkConfigBeanExists(ObjectName objectName) throws InstanceNotFoundException {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public ObjectName lookupConfigBeanByServiceInterfaceName(String serviceInterfaceQName, String refName) {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public Map<String, Map<String, ObjectName>> getServiceMapping() {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public Map<String, ObjectName> lookupServiceReferencesByServiceInterfaceName(String serviceInterfaceQName) {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public Set<String> lookupServiceInterfaceNames(ObjectName objectName) throws InstanceNotFoundException {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public String getServiceInterfaceName(String namespace, String localName) {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public Set<String> getAvailableModuleFactoryQNames() {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public ObjectName getServiceReference(String serviceInterfaceQName, String refName) throws InstanceNotFoundException {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public void checkServiceReferenceExists(ObjectName objectName) throws InstanceNotFoundException {
+ throw new UnsupportedOperationException();
+ }
}
*/
package org.opendaylight.controller.config.util;
+import java.util.Map;
import java.util.Set;
import javax.management.InstanceAlreadyExistsException;
public class TestingConfigTransactionController implements
ConfigTransactionControllerMXBean {
- private final ObjectName conf1, conf2, conf3;
+ public final ObjectName conf1, conf2, conf3;
public static final String moduleName1 = "moduleA";
public static final String moduleName2 = "moduleB";
return null;
}
}
+
+ @Override
+ public void checkConfigBeanExists(ObjectName objectName) throws InstanceNotFoundException {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public ObjectName saveServiceReference(String serviceInterfaceName, String refName, ObjectName moduleON) throws InstanceNotFoundException {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public void removeServiceReference(String serviceInterfaceName, String refName) {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public void removeAllServiceReferences() {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public ObjectName lookupConfigBeanByServiceInterfaceName(String serviceInterfaceQName, String refName) {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public Map<String, Map<String, ObjectName>> getServiceMapping() {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public Map<String, ObjectName> lookupServiceReferencesByServiceInterfaceName(String serviceInterfaceQName) {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public Set<String> lookupServiceInterfaceNames(ObjectName objectName) throws InstanceNotFoundException {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public String getServiceInterfaceName(String namespace, String localName) {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public boolean removeServiceReferences(ObjectName objectName) throws InstanceNotFoundException {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public Set<String> getAvailableModuleFactoryQNames() {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public ObjectName getServiceReference(String serviceInterfaceQName, String refName) throws InstanceNotFoundException {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public void checkServiceReferenceExists(ObjectName objectName) throws InstanceNotFoundException {
+ throw new UnsupportedOperationException();
+ }
}
+++ /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.util.jolokia;
-
-import static org.hamcrest.core.Is.is;
-import static org.junit.Assert.assertThat;
-
-import java.util.HashMap;
-import java.util.Map;
-
-import org.json.simple.JSONObject;
-import org.json.simple.JSONValue;
-import org.junit.Before;
-import org.junit.Test;
-import org.opendaylight.controller.config.api.ValidationException;
-import org.opendaylight.controller.config.api.ValidationException.ExceptionMessageWithStackTrace;
-
-public class ListableJolokiaClientTest {
-
- private Map<String, Map<String, ExceptionMessageWithStackTrace>> failedValidations;
-
- private ValidationException val;
-
- private final static String ex = "{\"message\":null,"
- + "\"failedValidations\":"
- + "{\"ifc2\":{\"impl1\":{\"message\":\"abc\",\"trace\":\"vvv\"},"
- + "\"impl2\":{\"message\":\"abc2\",\"trace\":\"vvv2\"}},"
- + "\"ifc1\":"
- + "{\"impl1\":{\"message\":\"abc\",\"trace\":\"vvv\"},"
- + "\"impl2\":{\"message\":\"abc2\",\"trace\":\"vvv2\"}}},"
- + "\"localizedMessage\":null," + "\"cause\":null}";
-
- @Before
- public void setUp() {
- failedValidations = new HashMap<String, Map<String, ExceptionMessageWithStackTrace>>();
- Map<String, ExceptionMessageWithStackTrace> map1 = new HashMap<String, ValidationException.ExceptionMessageWithStackTrace>();
- map1.put("impl1", new ExceptionMessageWithStackTrace("abc", "vvv"));
- map1.put("impl2", new ExceptionMessageWithStackTrace("abc2", "vvv2"));
- failedValidations.put("ifc1", map1);
- failedValidations.put("ifc2", map1);
- val = new ValidationException(failedValidations);
- }
-
- @Test
- public void testParsing() {
- JSONObject e = (JSONObject) JSONValue.parse(ex);
- ValidationException val2 = ListableJolokiaClient
- .createValidationExceptionFromJSONObject(e);
- assertThat(val2.getMessage(), is(val.getMessage()));
- assertThat(val2.getFailedValidations(), is(val.getFailedValidations()));
- }
-
-}
<module>config-util</module>
<module>config-persister-api</module>
<module>config-persister-file-adapter</module>
+ <module>config-persister-file-xml-adapter</module>
<module>yang-jmx-generator</module>
<module>yang-jmx-generator-plugin</module>
<module>yang-store-api</module>
<module>netty-event-executor-config</module>
<module>netty-timer-config</module>
<module>config-persister-directory-adapter</module>
+ <module>config-persister-directory-xml-adapter</module>
<module>yang-test-plugin</module>
</modules>
<osgi.version>5.0.0</osgi.version>
<jacoco.version>0.6.2.201302030002</jacoco.version>
<slf4j.version>1.7.2</slf4j.version>
- <jolokia.version>1.1.1</jolokia.version>
<opendaylight.yang.version>0.5.9-SNAPSHOT</opendaylight.yang.version>
<opendaylight.binding.version>0.6.0-SNAPSHOT</opendaylight.binding.version>
<opendaylight.yangtools.version>0.1.1-SNAPSHOT</opendaylight.yangtools.version>
<artifactId>guava</artifactId>
<version>14.0.1</version>
</dependency>
- <dependency>
- <groupId>org.jolokia</groupId>
- <artifactId>jolokia-core</artifactId>
- <version>${jolokia.version}</version>
- </dependency>
- <dependency>
- <groupId>org.jolokia</groupId>
- <artifactId>jolokia-jvm</artifactId>
- <version>${jolokia.version}</version>
- <classifier>agent</classifier>
- </dependency>
- <dependency>
- <groupId>org.jolokia</groupId>
- <artifactId>jolokia-client-java</artifactId>
- <version>${jolokia.version}</version>
- </dependency>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
import org.opendaylight.controller.config.api.annotations.AbstractServiceInterface;
import org.opendaylight.controller.config.spi.Module;
import org.opendaylight.controller.config.spi.ModuleFactory;
+import org.opendaylight.controller.config.yangjmxgenerator.ModuleMXBeanEntry;
import org.opendaylight.controller.config.yangjmxgenerator.plugin.ftl.model.Constructor;
import org.opendaylight.controller.config.yangjmxgenerator.plugin.ftl.model.Field;
import org.opendaylight.controller.config.yangjmxgenerator.plugin.ftl.model.Header;
private final String globallyUniqueName, moduleInstanceType;
private final List<String> providedServices;
+ private final ModuleMXBeanEntry mbe;
public AbstractFactoryTemplate(Header header, String packageName,
- String abstractFactoryName, String globallyUniqueName,
- String moduleInstanceType, List<Field> fields,
- List<String> providedServices) {
+ String abstractFactoryName, String globallyUniqueName,
+ String moduleInstanceType, List<Field> fields,
+ List<String> providedServices, ModuleMXBeanEntry mbe) {
super(header, packageName, abstractFactoryName, Collections
.<String> emptyList(), implementedIfcs, fields, Collections
.<MethodDefinition> emptyList(), true, false, Collections
this.globallyUniqueName = globallyUniqueName;
this.moduleInstanceType = moduleInstanceType;
this.providedServices = providedServices;
+ this.mbe = mbe;
}
public String getGloballyUniqueName() {
return "factory_abs_template.ftl";
}
+ public ModuleMXBeanEntry getMbe() {
+ return mbe;
+ }
}
import org.opendaylight.controller.config.yangjmxgenerator.attribute.Dependency;
import org.opendaylight.controller.config.yangjmxgenerator.attribute.JavaAttribute;
import org.opendaylight.controller.config.yangjmxgenerator.attribute.ListAttribute;
+import org.opendaylight.controller.config.yangjmxgenerator.attribute.ListDependenciesAttribute;
import org.opendaylight.controller.config.yangjmxgenerator.attribute.TOAttribute;
import org.opendaylight.controller.config.yangjmxgenerator.attribute.TypedAttribute;
import org.opendaylight.controller.config.yangjmxgenerator.attribute.VoidAttribute;
sieTemplate.getAnnotations().add(
Annotation.createDescriptionAnnotation(sie
.getNullableDescription()));
- sieTemplate.getAnnotations().add(Annotation.createSieAnnotation(sie.getQName(), sie.getExportedOsgiClassName
- ()));
+ sieTemplate.getAnnotations().addAll(Annotation.createSieAnnotations(sie));
return sieTemplate;
}
mbe.getPackageName(), mbe.getAbstractFactoryName(),
mbe.getGloballyUniqueName(), mbe.getFullyQualifiedName(mbe
.getStubModuleName()), attrProcessor.getFields(),
- Lists.newArrayList(transformed));
+ Lists.newArrayList(transformed), mbe);
}
public static AbstractModuleTemplate abstractModuleTemplateFromMbe(
}
boolean isDependency = false;
+ boolean isListOfDependencies = false;
Dependency dependency = null;
Annotation overrideAnnotation = new Annotation("Override",
Collections.<Parameter> emptyList());
.getDependency();
annotations.add(Annotation
.createRequireIfcAnnotation(dependency.getSie()));
+ if (attributeIfc instanceof ListDependenciesAttribute) {
+ isListOfDependencies = true;
+ }
}
String varName = BindingGeneratorUtil
.parseToValidParamName(attrEntry.getKey());
moduleFields.add(new ModuleField(type, varName, attributeIfc
- .getUpperCaseCammelCase(), nullableDefaultWrapped, isDependency, dependency));
+ .getUpperCaseCammelCase(), nullableDefaultWrapped, isDependency, dependency, isListOfDependencies));
String getterName = "get"
+ attributeIfc.getUpperCaseCammelCase();
.createDescriptionAnnotation(attributeIfc.getNullableDescription()));
}
+ String setterBody = "this." + varName + " = " + varName + ";";
+ if (isListOfDependencies) {
+ String nullCheck = String.format("if (%s == null) throw new IllegalArgumentException(\"Null not supported\");%n",
+ varName);
+ setterBody = nullCheck + setterBody;
+ }
MethodDefinition setter = new MethodDefinition("void",
setterName,
Lists.newArrayList(new Field(type, varName)),
- annotations, "this." + varName + " = " + varName + ";");
+ annotations, setterBody);
setter.setJavadoc(attributeIfc.getNullableDescription());
methods.add(getter);
*/
package org.opendaylight.controller.config.yangjmxgenerator.plugin.ftl.model;
+import java.util.ArrayList;
+import java.util.Collection;
import java.util.List;
import org.opendaylight.controller.config.api.annotations.Description;
import org.opendaylight.controller.config.api.annotations.RequireInterface;
import org.opendaylight.controller.config.api.annotations.ServiceInterfaceAnnotation;
+import org.opendaylight.yangtools.yang.binding.annotations.ModuleQName;
import org.opendaylight.controller.config.yangjmxgenerator.ServiceInterfaceEntry;
-import org.opendaylight.yangtools.yang.common.QName;
import com.google.common.base.Preconditions;
import com.google.common.collect.Lists;
Lists.newArrayList(new Parameter("value", q(description))));
}
- public static Annotation createSieAnnotation(QName qname,
- String exportedClassName) {
- Preconditions.checkNotNull(qname,
+ public static Collection<Annotation> createSieAnnotations(ServiceInterfaceEntry sie){
+
+ String exportedClassName = sie.getExportedOsgiClassName();
+ Preconditions.checkNotNull(sie.getQName(),
"Cannot create annotation from null qname");
Preconditions.checkNotNull(exportedClassName,
"Cannot create annotation from null exportedClassName");
+ List<Annotation> result = new ArrayList<>();
+ {
+ List<Parameter> params = Lists.newArrayList(new Parameter("value", q(sie.getQName().toString())));
+ params.add(new Parameter("osgiRegistrationType", exportedClassName + ".class"));
+
+ params.add(new Parameter("namespace", q(sie.getQName().getNamespace().toString())));
+ params.add(new Parameter("revision", q(sie.getQName().getFormattedRevision())));
+ params.add(new Parameter("localName", q(sie.getQName().getLocalName())));
+
+ Annotation sieAnnotation = new Annotation(ServiceInterfaceAnnotation.class.getCanonicalName(), params);
+ result.add(sieAnnotation);
- List<Parameter> params = Lists.newArrayList(new Parameter("value",
- q(qname.getLocalName())));
- params.add(new Parameter("osgiRegistrationType", exportedClassName
- + ".class"));
- return new Annotation(
- ServiceInterfaceAnnotation.class.getCanonicalName(), params);
+ }
+ {
+ List<Parameter> params = new ArrayList<>();
+ params.add(new Parameter("namespace", q(sie.getYangModuleQName().getNamespace().toString())));
+ params.add(new Parameter("revision", q(sie.getYangModuleQName().getFormattedRevision())));
+ params.add(new Parameter("name", q(sie.getYangModuleQName().getLocalName())));
+
+ Annotation moduleQNameAnnotation = new Annotation(ModuleQName.class.getCanonicalName(), params);
+ result.add(moduleQNameAnnotation);
+ }
+ return result;
}
public static Annotation createRequireIfcAnnotation(
public class ModuleField extends Field {
private final String nullableDefault, attributeName;
- private final boolean dependent;
+ private final boolean dependent, isListOfDependencies;
private final Dependency dependency;
- public ModuleField(List<String> modifiers, String type, String name,
+ private ModuleField(List<String> modifiers, String type, String name,
String attributeName, String nullableDefault, boolean isDependency,
- Dependency dependency) {
+ Dependency dependency, boolean isListOfDependencies) {
super(modifiers, type, name);
this.dependent = isDependency;
this.dependency = dependency;
nullableDefault = "new " + ArrayList.class.getName() + generics + "()";
}
this.nullableDefault = nullableDefault;
+ this.isListOfDependencies = isListOfDependencies;
}
public ModuleField(String type, String name, String attributeName,
- String nullableDefault, boolean isDependency, Dependency dependency) {
+ String nullableDefault, boolean isDependency, Dependency dependency, boolean isListOfDependencies) {
this(Collections.<String> emptyList(), type, name, attributeName,
- nullableDefault, isDependency, dependency);
+ nullableDefault, isDependency, dependency, isListOfDependencies);
}
public Dependency getDependency() {
return dependent;
}
+ public boolean isListOfDependencies() {
+ return isListOfDependencies;
+ }
+
public String getAttributeName() {
return attributeName;
}
package ${packageName};
<@javadocD object=javadoc/>
+@org.opendaylight.yangtools.yang.binding.annotations.ModuleQName(namespace="${mbe.getYangModuleQName().getNamespace().toString()}",revision="${mbe.getYangModuleQName().getFormattedRevision()}",name="${mbe.getYangModuleQName().getLocalName()}")
<@typeDeclarationD object=typeDeclaration/>
{
public static final java.lang.String NAME = "${globallyUniqueName}";
- private static final java.util.Set<Class<? extends ${abstractServiceInterfaceType}>> serviceIfcs = new java.util.HashSet<Class<? extends ${abstractServiceInterfaceType}>>();
+ private static final java.util.Set<Class<? extends ${abstractServiceInterfaceType}>> serviceIfcs;
<#if providedServices??>
static {
+ java.util.Set<Class<? extends ${abstractServiceInterfaceType}>> serviceIfcs2 = new java.util.HashSet<Class<? extends ${abstractServiceInterfaceType}>>();
<#list providedServices as refId>
- serviceIfcs.add(${refId});
+ serviceIfcs2.add(${refId});
</#list>
+ serviceIfcs = java.util.Collections.unmodifiableSet(serviceIfcs2);
}
</#if>
return false;
}
+ @Override
+ public java.util.Set<Class<? extends ${abstractServiceInterfaceType}>> getImplementedServiceIntefaces() {
+ return serviceIfcs;
+ }
+
+
@Override
public ${moduleType} createModule(String instanceName, ${dependencyResolverType} dependencyResolver, ${bundleContextType} bundleContext) {
return instantiateModule(instanceName, dependencyResolver, bundleContext);
throw new IllegalArgumentException("Parameter 'other' is null");
}
<#list moduleFields as field>
- <#if field.dependent==true>
- if (${field.name}Dependency == null) {
- if (other.${field.name}Dependency != null)
- return false;
- } else if (!${field.name}Dependency.equals(other.${field.name}Dependency)) {
+ <#if field.dependent==true && field.listOfDependencies == false>
+ if (${field.name}Dependency != other.${field.name}Dependency) { // reference to dependency must be same
+ return false;
+ }
+ <#elseif field.listOfDependencies>
+ if (${field.name}Dependency.equals(other.${field.name}Dependency) == false) {
return false;
}
+ for (int idx = 0; idx < ${field.name}Dependency.size(); idx++) {
+ if (${field.name}Dependency.get(idx) != other.${field.name}Dependency.get(idx)) {
+ return false;
+ }
+ }
<#else>
if (${field.name} == null) {
if (other.${field.name} != null) {
} catch (RuntimeException e) {
final Throwable cause = e.getCause();
assertNotNull(cause);
- assertTrue(cause instanceof IllegalStateException);
+ assertTrue(cause.toString() + " is unexpected", cause instanceof IllegalStateException);
assertThat(cause.getMessage(),
containsString("Name conflict in generated files"));
assertThat(cause.getMessage(), containsString("DtoA.java"));
"public static final java.lang.String NAME=\"threadfactory-naming\"");
assertDeclaredField(
fieldDeclarations,
- "private static final java.util.Set<Class<? extends org.opendaylight.controller.config.api.annotations.AbstractServiceInterface>> serviceIfcs=new java.util.HashSet<Class<? extends org.opendaylight.controller.config.api.annotations.AbstractServiceInterface>>()");
+ "private static final java.util.Set<Class<? extends org.opendaylight.controller.config.api.annotations.AbstractServiceInterface>> serviceIfcs");
assertEquals(2, fieldDeclarations.size());
- assertFactoryMethods(visitor.methods, 8);
+ assertFactoryMethods(visitor.methods, 9);
assertEquals("Incorrenct number of generated method descriptions", 0,
visitor.methodDescriptions.size());
assertEquals("Incorrenct number of generated method javadoc", 0,
<artifactId>commons-lang3</artifactId>
<scope>test</scope>
</dependency>
+ <dependency>
+ <groupId>org.opendaylight.yangtools</groupId>
+ <artifactId>binding-type-provider</artifactId>
+ </dependency>
</dependencies>
<build>
private final Map<String, QName> providedServices;
private Collection<RuntimeBeanEntry> runtimeBeans;
+ private final QName yangModuleQName;
public ModuleMXBeanEntry(IdentitySchemaNode id,
Map<String, AttributeIfc> yangToAttributes, String packageName,
Map<String, QName> providedServices2, String javaNamePrefix,
- String namespace, Collection<RuntimeBeanEntry> runtimeBeans) {
+ String namespace, Collection<RuntimeBeanEntry> runtimeBeans,
+ QName yangModuleQName) {
this.globallyUniqueName = id.getQName().getLocalName();
this.yangToAttributes = yangToAttributes;
this.nullableDescription = id.getDescription();
this.namespace = checkNotNull(namespace);
this.providedServices = Collections.unmodifiableMap(providedServices2);
this.runtimeBeans = runtimeBeans;
+ this.yangModuleQName = yangModuleQName;
}
public String getMXBeanInterfaceName() {
moduleIdentity, yangToAttributes, packageName,
providedServices, javaNamePrefix, currentModule
.getNamespace().toString(),
- runtimeBeans);
+ runtimeBeans,
+ ModuleUtil.getQName(currentModule));
moduleMXBeanEntry.setYangModuleName(currentModule
.getName());
moduleMXBeanEntry
return nullableDescription;
}
+ public QName getYangModuleQName() {
+ return yangModuleQName;
+ }
+
@Override
public String toString() {
return "ModuleMXBeanEntry{" + "globallyUniqueName='"
--- /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.yangjmxgenerator;
+
+import org.opendaylight.yangtools.yang.common.QName;
+import org.opendaylight.yangtools.yang.model.api.Module;
+
+public class ModuleUtil {
+
+ public static QName getQName(Module currentModule){
+ return new QName(currentModule.getNamespace(), currentModule.getRevision(), currentModule.getName());
+ }
+}
private final String exportedOsgiClassName;
private final QName qName;
private final String nullableDescription, packageName, typeName;
+ private final QName yangModuleQName;
- private ServiceInterfaceEntry(IdentitySchemaNode id, String packageName) {
- this(Optional.<ServiceInterfaceEntry> absent(), id, packageName);
+ private ServiceInterfaceEntry(IdentitySchemaNode id, String packageName, QName yangModuleQName) {
+ this(Optional.<ServiceInterfaceEntry> absent(), id, packageName, yangModuleQName);
}
private ServiceInterfaceEntry(Optional<ServiceInterfaceEntry> base,
- IdentitySchemaNode id, String packageName) {
+ IdentitySchemaNode id, String packageName, QName yangModuleQName) {
checkNotNull(base);
this.maybeBaseCache = base;
List<UnknownSchemaNode> unknownSchemaNodes = id.getUnknownSchemaNodes();
nullableDescription = id.getDescription();
typeName = getSimpleName(exportedOsgiClassName) + CLASS_NAME_SUFFIX;
this.packageName = packageName;
+ this.yangModuleQName = yangModuleQName;
}
private static final String getSimpleName(String fullyQualifiedName) {
* @return Map of QNames as keys and ServiceInterfaceEntry instances as
* values
*/
- public static Map<QName, ServiceInterfaceEntry> create(Module module,
+ public static Map<QName, ServiceInterfaceEntry> create(Module currentModule,
String packageName) {
logger.debug("Generating ServiceInterfaces from {} to package {}",
- module.getNamespace(), packageName);
+ currentModule.getNamespace(), packageName);
Map<IdentitySchemaNode, ServiceInterfaceEntry> identitiesToSIs = new HashMap<>();
Set<IdentitySchemaNode> notVisited = new HashSet<>(
- module.getIdentities());
+ currentModule.getIdentities());
int lastSize = notVisited.size() + 1;
while (notVisited.size() > 0) {
if (notVisited.size() == lastSize) {
} else if (identity.getBaseIdentity().getQName()
.equals(SERVICE_TYPE_Q_NAME)) {
// this is a base type
- created = new ServiceInterfaceEntry(identity, packageName);
+ created = new ServiceInterfaceEntry(identity, packageName, ModuleUtil.getQName(currentModule));
} else {
ServiceInterfaceEntry foundBase = identitiesToSIs
.get(identity.getBaseIdentity());
// derived type, did we convert the parent?
if (foundBase != null) {
created = new ServiceInterfaceEntry(
- Optional.of(foundBase), identity, packageName);
+ Optional.of(foundBase), identity, packageName, ModuleUtil.getQName(currentModule));
}
}
if (created != null) {
- created.setYangModuleName(module.getName());
+ created.setYangModuleName(currentModule.getName());
// TODO how to get local name
created.setYangModuleLocalname(identity.getQName()
.getLocalName());
return typeName;
}
+ public QName getYangModuleQName() {
+ return yangModuleQName;
+ }
+
@Override
public boolean equals(Object o) {
if (this == o)
public String getJMXParamForBaseType(TypeDefinition<?> baseType) {
return typeProvider.getConstructorPropertyName(baseType);
}
+
+ public String getJMXParamForUnionInnerType(TypeDefinition<?> unionInnerType) {
+ return typeProvider.getParamNameFromType(unionInnerType);
+ }
}
*/
package org.opendaylight.controller.config.yangjmxgenerator.attribute;
+import com.google.common.base.Preconditions;
import org.opendaylight.controller.config.yangjmxgenerator.TypeProviderWrapper;
import org.opendaylight.yangtools.sal.binding.model.api.Type;
import org.opendaylight.yangtools.yang.model.api.LeafListSchemaNode;
import org.opendaylight.yangtools.yang.model.api.LeafSchemaNode;
import org.opendaylight.yangtools.yang.model.api.TypeDefinition;
+import org.opendaylight.yangtools.yang.model.api.type.UnionTypeDefinition;
import javax.management.openmbean.ArrayType;
import javax.management.openmbean.CompositeType;
import javax.management.openmbean.OpenDataException;
import javax.management.openmbean.OpenType;
import javax.management.openmbean.SimpleType;
+import java.util.Arrays;
+import java.util.List;
public class JavaAttribute extends AbstractAttribute implements TypedAttribute {
+ public static final String DESCRIPTION_OF_VALUE_ATTRIBUTE_FOR_UNION = "valueOfArtificialUnionProperty";
+
private final Type type;
private final String nullableDescription, nullableDefault, nullableDefaultWrappedForCode;
private final TypeProviderWrapper typeProviderWrapper;
this.nullableDescription = leaf.getDescription();
}
+ public boolean isUnion() {
+ TypeDefinition<?> base = getBaseType(typeProviderWrapper, typeDefinition);
+ return base instanceof UnionTypeDefinition;
+ }
+
public TypeDefinition<?> getTypeDefinition() {
return typeDefinition;
}
return getArrayType();
} else if (isEnum(baseType)) {
return getSimpleType(baseType);
- } else if (isDerivedType(baseType)) {
+ } else if (isUnion()) {
+ return getCompositeTypeForUnion(baseTypeDefinition);
+ } else if (isDerivedType(baseType, getType())) {
return getCompositeType(baseType, baseTypeDefinition);
}
return getSimpleType(getType());
}
+ private OpenType<?> getCompositeTypeForUnion(TypeDefinition<?> baseTypeDefinition) {
+ Preconditions.checkArgument(baseTypeDefinition instanceof UnionTypeDefinition,
+ "Expected %s instance but was %s", UnionTypeDefinition.class, baseTypeDefinition);
+
+ List<TypeDefinition<?>> types = ((UnionTypeDefinition) baseTypeDefinition).getTypes();
+
+ String[] itemNames = new String[types.size()+1];
+ OpenType<?>[] itemTypes = new OpenType[itemNames.length];
+
+ addArtificialPropertyToUnionCompositeType(baseTypeDefinition, itemNames, itemTypes);
+
+ String description = getNullableDescription() == null ? getAttributeYangName() : getNullableDescription();
+
+ int i = 1;
+ for (TypeDefinition<?> innerTypeDefinition : types) {
+
+ Type innerType = typeProviderWrapper.getType(innerTypeDefinition, innerTypeDefinition);
+
+ TypeDefinition<?> baseInnerTypeDefinition = getBaseType(typeProviderWrapper, innerTypeDefinition);
+ Type innerTypeBaseType = typeProviderWrapper.getType(baseInnerTypeDefinition, baseInnerTypeDefinition);
+
+ OpenType<?> innerCompositeType;
+
+ if(isDerivedType(innerTypeBaseType, innerType)) {
+ innerCompositeType = getCompositeType(innerTypeBaseType, baseInnerTypeDefinition);
+ } else {
+ innerCompositeType = SimpleTypeResolver.getSimpleType(innerType);
+ }
+
+ itemNames[i] = typeProviderWrapper.getJMXParamForUnionInnerType(innerTypeDefinition);
+ itemTypes[i++] = innerCompositeType;
+ }
+
+ String[] descriptions = Arrays.copyOf(itemNames, itemNames.length);
+ descriptions[0] = DESCRIPTION_OF_VALUE_ATTRIBUTE_FOR_UNION;
+
+ try {
+ return new CompositeType(getUpperCaseCammelCase(), description, itemNames, descriptions, itemTypes);
+ } catch (OpenDataException e) {
+ throw new RuntimeException("Unable to create " + CompositeType.class + " with inner elements "
+ + Arrays.toString(itemTypes), e);
+ }
+ }
+
+ public static final Class<Character> TYPE_OF_ARTIFICIAL_UNION_PROPERTY = char.class;
+
+ private void addArtificialPropertyToUnionCompositeType(TypeDefinition<?> baseTypeDefinition, String[] itemNames, OpenType<?>[] itemTypes) {
+ String artificialPropertyName = typeProviderWrapper.getJMXParamForBaseType(baseTypeDefinition);
+ itemNames[0] = artificialPropertyName;
+
+ OpenType<?> artificialPropertyType = getArrayOpenTypeForSimpleType(TYPE_OF_ARTIFICIAL_UNION_PROPERTY.getName(),
+ SimpleTypeResolver.getSimpleType(TYPE_OF_ARTIFICIAL_UNION_PROPERTY.getName()));
+ itemTypes[0] = artificialPropertyType;
+ }
+
private boolean isEnum(Type baseType) {
return baseType.getFullyQualifiedName().equals(Enum.class.getName());
}
throw new RuntimeException("Unable to create " + CompositeType.class + " with inner element of type "
+ itemTypes, e);
}
-
}
private OpenType<?> getArrayType() {
String innerTypeFullyQName = getInnerType(getType());
SimpleType<?> innerSimpleType = SimpleTypeResolver.getSimpleType(innerTypeFullyQName);
+ return getArrayOpenTypeForSimpleType(innerTypeFullyQName, innerSimpleType);
+ }
+
+ private OpenType<?> getArrayOpenTypeForSimpleType(String innerTypeFullyQName, SimpleType<?> innerSimpleType) {
try {
ArrayType<Object> arrayType = isPrimitive(innerTypeFullyQName) ? new ArrayType<>(innerSimpleType, true)
: new ArrayType<>(1, innerSimpleType);
return type.getName().endsWith("[]");
}
- private boolean isDerivedType(Type baseType) {
- return baseType.equals(getType()) == false;
+ private boolean isDerivedType(Type baseType, Type currentType) {
+ return baseType.equals(currentType) == false;
}
private static String getInnerType(Type type) {
JAVA_TYPE_TO_SIMPLE_TYPE.put(Date.class.getName(), SimpleType.DATE);
JAVA_TYPE_TO_SIMPLE_TYPE.put(Double.class.getName(), SimpleType.DOUBLE);
JAVA_TYPE_TO_SIMPLE_TYPE.put(double.class.getName(), SimpleType.DOUBLE);
+
+ JAVA_TYPE_TO_SIMPLE_TYPE.put(char.class.getName(), SimpleType.CHARACTER);
}
}
import com.google.common.collect.Lists;
import com.google.common.collect.Maps;
-import com.google.common.collect.Sets;
import org.apache.commons.io.IOUtils;
import org.opendaylight.controller.config.yang.store.api.YangStoreException;
import org.opendaylight.controller.config.yangjmxgenerator.ModuleMXBeanEntry;
import org.opendaylight.yangtools.yang.model.api.SchemaContext;
import org.opendaylight.yangtools.yang.parser.impl.YangParserImpl;
-import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.io.InputStream;
-import java.util.ArrayList;
import java.util.Collection;
import java.util.HashMap;
-import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
public YangStoreSnapshotImpl parseYangFiles(
Collection<? extends InputStream> allInput)
throws YangStoreException {
- YangParserImpl parser = new YangParserImpl();
+ YangParserImpl parser = YangParserWrapper.getYangParserInstance();
- List<InputStream> bufferedInputStreams = new ArrayList<>();
- for (InputStream is : allInput) {
- String content;
- try {
- content = IOUtils.toString(is);
- } catch (IOException e) {
- throw new YangStoreException("Can not get yang as String from "
- + is, e);
- }
- InputStream buf = new ByteArrayInputStream(content.getBytes());
- bufferedInputStreams.add(buf);
- }
-
- Map<InputStream, Module> allYangModules = parser
- .parseYangModelsFromStreamsMapped(bufferedInputStreams);
+ Map<InputStream, Module> allYangModules = YangParserWrapper.parseYangFiles(parser, allInput);
- SchemaContext resolveSchemaContext = parser.resolveSchemaContext(Sets
- .newHashSet(allYangModules.values()));
+ SchemaContext resolveSchemaContext = YangParserWrapper.getSchemaContextFromModules(parser, allYangModules);
// JMX generator
public Map<Module, String> parseYangFilesToString(
Collection<? extends InputStream> allYangs) {
- YangParserImpl parser = new YangParserImpl();
+ YangParserImpl parser = YangParserWrapper.getYangParserInstance();
Map<InputStream, Module> allYangModules = parser
.parseYangModelsFromStreamsMapped(Lists.newArrayList(allYangs));
--- /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.store.impl;
+
+import com.google.common.collect.Sets;
+import org.apache.commons.io.IOUtils;
+import org.opendaylight.controller.config.yang.store.api.YangStoreException;
+import org.opendaylight.yangtools.yang.model.api.Module;
+import org.opendaylight.yangtools.yang.model.api.SchemaContext;
+import org.opendaylight.yangtools.yang.model.parser.api.YangModelParser;
+import org.opendaylight.yangtools.yang.parser.impl.YangParserImpl;
+
+import java.io.ByteArrayInputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.List;
+import java.util.Map;
+
+public class YangParserWrapper {
+
+ /**
+ * throw IllegalStateException if it is unable to parse yang files
+ */
+ public static SchemaContext parseYangFiles(Collection<? extends InputStream> yangFilesAsInputStreams) {
+ YangParserImpl parser = getYangParserInstance();
+ Map<InputStream, Module> mappedYangModules = null;
+ try {
+ mappedYangModules = parseYangFiles(parser, yangFilesAsInputStreams);
+ } catch (YangStoreException e) {
+ throw new IllegalStateException("Unable to parse yang files", e);
+ }
+ return getSchemaContextFromModules(parser, mappedYangModules);
+ }
+
+ static YangParserImpl getYangParserInstance() {
+ return new YangParserImpl();
+ }
+
+ static SchemaContext getSchemaContextFromModules(YangModelParser parser, Map<InputStream, Module> allYangModules) {
+ return parser.resolveSchemaContext(Sets
+ .newHashSet(allYangModules.values()));
+ }
+
+ static Map<InputStream, Module> parseYangFiles(YangModelParser parser, Collection<? extends InputStream> allInput) throws YangStoreException {
+ List<InputStream> bufferedInputStreams = new ArrayList<>();
+ for (InputStream is : allInput) {
+ String content;
+ try {
+ content = IOUtils.toString(is);
+ } catch (IOException e) {
+ throw new YangStoreException("Can not get yang as String from "
+ + is, e);
+ }
+ InputStream buf = new ByteArrayInputStream(content.getBytes());
+ bufferedInputStreams.add(buf);
+ }
+
+ return parser
+ .parseYangModelsFromStreamsMapped(bufferedInputStreams);
+ }
+}
<artifactId>slf4j-api</artifactId>
</dependency>
<dependency>
- <groupId>org.opendaylight.yangtools.model</groupId>
- <artifactId>ietf-inet-types</artifactId>
+ <groupId>org.opendaylight.yangtools.model</groupId>
+ <artifactId>ietf-inet-types</artifactId>
+ </dependency>
+ <dependency>
+ <groupId>org.opendaylight.bgpcep</groupId>
+ <artifactId>mockito-configuration</artifactId>
+ <scope>test</scope>
+ </dependency>
+ <dependency>
+ <groupId>${project.groupId}</groupId>
+ <artifactId>config-manager</artifactId>
+ <scope>test</scope>
+ </dependency>
+ <dependency>
+ <groupId>${project.groupId}</groupId>
+ <artifactId>config-manager</artifactId>
+ <type>test-jar</type>
+ <scope>test</scope>
+ </dependency>
+ <dependency>
+ <groupId>org.opendaylight.controller</groupId>
+ <artifactId>config-util</artifactId>
+ <scope>test</scope>
+ </dependency>
+ <dependency>
+ <groupId>junit</groupId>
+ <artifactId>junit</artifactId>
+ <scope>test</scope>
</dependency>
</dependencies>
--- /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.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.controller.config.test.types.rev131127;
+
+
+/**
+**/
+public class UnionTestBuilder {
+
+ public static UnionTest getDefaultInstance(String defaultValue) {
+ try {
+ int i = Integer.valueOf(defaultValue);
+ return new UnionTest(new ExtendTwice(i));
+ } catch (NumberFormatException e) {
+ return new UnionTest(defaultValue);
+ }
+ }
+
+}
default 127.0.0.1;
}
- leaf ip {
- type inet:ip-address;
- // TODO defaults for union default 0:0:0:0:0:0:0:1;
- }
}
leaf as-number {
default ONE;
}
+ leaf ip {
+ type inet:ip-address;
+ default 0:0:0:0:0:0:0:1;
+ }
+
+ leaf union-test-attr {
+ type tt:unionTest;
+ default 456;
+ }
+
leaf sleep-factor {
type decimal64 {
fraction-digits 2;
}
}
+ typedef unionTest {
+ type union {
+ type string;
+ type uint32;
+ type extend-twice;
+ }
+ }
+
}
--- /dev/null
+package org.opendaylight.controller.config.yang.test.impl;
+
+import com.google.common.collect.Lists;
+import junit.framework.Assert;
+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.CommitStatus;
+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 javax.management.InstanceAlreadyExistsException;
+import javax.management.ObjectName;
+import java.util.ArrayList;
+import java.util.List;
+
+public class NetconfTestImplModuleTest extends AbstractConfigTest {
+
+ public static final String TESTING_DEP_PREFIX = "testing-dep";
+ private NetconfTestImplModuleFactory factory;
+ private final String instanceName = "n1";
+
+ @Before
+ public void setUp() {
+
+ factory = new NetconfTestImplModuleFactory();
+ super.initConfigTransactionManagerImpl(new HardcodedModuleFactoriesResolver(factory,
+ new DepTestImplModuleFactory()));
+ }
+
+ @Test
+ public void testDependencyList() throws InstanceAlreadyExistsException, ValidationException,
+ ConflictingVersionException {
+ ConfigTransactionJMXClient transaction = configRegistryClient.createTransaction();
+
+ ObjectName on = createInstance(transaction, instanceName, 4);
+ transaction.validateConfig();
+ CommitStatus status = transaction.commit();
+
+ assertBeanCount(1, factory.getImplementationName());
+ assertBeanCount(4 + 1, DepTestImplModuleFactory.NAME);
+ assertStatus(status, 1 + 4 + 1, 0, 0);
+
+ transaction = configRegistryClient.createTransaction();
+
+ NetconfTestImplModuleMXBean proxy = transaction.newMXBeanProxy(ObjectNameUtil.withoutTransactionName(on),
+ NetconfTestImplModuleMXBean.class);
+ proxy.getComplexList();
+ List<ObjectName> testingDeps = proxy.getTestingDeps();
+ ObjectName testingDep = proxy.getTestingDep();
+
+ Assert.assertEquals(TESTING_DEP_PREFIX, ObjectNameUtil.getInstanceName(testingDep));
+ assertTestingDeps(testingDeps, 4);
+
+ transaction.abortConfig();
+ }
+
+ private void assertTestingDeps(List<ObjectName> testingDeps, int i) {
+ Assert.assertEquals(i, testingDeps.size());
+
+ int c = 1;
+ for (ObjectName testingDep : testingDeps) {
+ Assert.assertEquals(TESTING_DEP_PREFIX + Integer.toString(c++), ObjectNameUtil.getInstanceName(testingDep));
+ }
+ }
+
+
+ private ObjectName createInstance(ConfigTransactionJMXClient transaction, String instanceName, int depsCount)
+ throws InstanceAlreadyExistsException {
+ ObjectName nameCreated = transaction.createModule(factory.getImplementationName(), instanceName);
+ NetconfTestImplModuleMXBean mxBean = transaction.newMXBeanProxy(nameCreated, NetconfTestImplModuleMXBean.class);
+
+ ObjectName dep = transaction.createModule(DepTestImplModuleFactory.NAME, TESTING_DEP_PREFIX);
+ mxBean.setTestingDep(dep);
+
+ ArrayList<ObjectName> testingDeps = Lists.newArrayList();
+ for (int i = 0; i < depsCount; i++) {
+ dep = transaction.createModule(DepTestImplModuleFactory.NAME, TESTING_DEP_PREFIX + Integer.toString(i + 1));
+ testingDeps.add(dep);
+ }
+ mxBean.setTestingDeps(testingDeps);
+
+ return nameCreated;
+ }
+
+}
<artifactId>config-persister-file-adapter</artifactId>
<version>${config.version}</version>
</dependency>
- <dependency>
- <groupId>org.opendaylight.controller</groupId>
- <artifactId>config-persister-directory-adapter</artifactId>
- <version>${config.version}</version>
- </dependency>
+ <dependency>
+ <groupId>org.opendaylight.controller</groupId>
+ <artifactId>config-persister-file-xml-adapter</artifactId>
+ <version>${config.version}</version>
+ </dependency>
+ <dependency>
+ <groupId>org.opendaylight.controller</groupId>
+ <artifactId>config-persister-directory-adapter</artifactId>
+ <version>${config.version}</version>
+ </dependency>
+ <dependency>
+ <groupId>org.opendaylight.controller</groupId>
+ <artifactId>config-persister-directory-xml-adapter</artifactId>
+ <version>${config.version}</version>
+ </dependency>
<!-- Netconf -->
<dependency>
<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>
<dependency>
<groupId>org.opendaylight.controller</groupId>
<artifactId>config-persister-impl</artifactId>
<dependency>
<groupId>org.opendaylight.controller</groupId>
<artifactId>
- zeromq-routingtable.implementation
+ remoterpc-routingtable.implementation
</artifactId>
<version>0.4.1-SNAPSHOT</version>
</dependency>
netconf.config.persister.1.properties.directoryStorage=configuration/initial/
netconf.config.persister.1.readonly=true
-netconf.config.persister.2.storageAdapterClass=org.opendaylight.controller.config.persist.storage.file.FileStorageAdapter
-netconf.config.persister.2.properties.fileStorage=configuration/current/controller.currentconfig.txt
+#netconf.config.persister.3.storageAdapterClass=org.opendaylight.controller.config.persist.storage.directory.xml.XmlDirectoryStorageAdapter
+#netconf.config.persister.3.properties.directoryStorage=configuration/initialXml/
+#netconf.config.persister.3.readonly=true
+
+#netconf.config.persister.4.storageAdapterClass=org.opendaylight.controller.config.persist.storage.file.FileStorageAdapter
+#netconf.config.persister.4.properties.fileStorage=configuration/current/controller.currentconfig.txt
+#netconf.config.persister.4.properties.numberOfBackups=1
+
+netconf.config.persister.2.storageAdapterClass=org.opendaylight.controller.config.persist.storage.file.xml.XmlFileStorageAdapter
+netconf.config.persister.2.properties.fileStorage=configuration/current/controller.currentconfig.xml
netconf.config.persister.2.properties.numberOfBackups=1
<name>dom-broker</name>
<data-store xmlns="urn:opendaylight:params:xml:ns:yang:controller:md:sal:dom:impl">
<type xmlns:dom="urn:opendaylight:params:xml:ns:yang:controller:md:sal:dom">dom:dom-data-store</type>
- <!-- to switch to the clustered data store, comment out the ref_hash-map-data-store <name> and uncomment the ref_cluster-data-store one -->
- <name>ref_hash-map-data-store</name>
- <!-- <name>ref_cluster-data-store</name> -->
+ <!-- to switch to the clustered data store, comment out the hash-map-data-store <name> and uncomment the cluster-data-store one -->
+ <name>hash-map-data-store</name>
+ <!-- <name>cluster-data-store</name> -->
</data-store>
</module>
<module>
<name>binding-broker-impl</name>
<notification-service xmlns="urn:opendaylight:params:xml:ns:yang:controller:md:sal:binding:impl">
<type xmlns:binding="urn:opendaylight:params:xml:ns:yang:controller:md:sal:binding">binding:binding-notification-service</type>
- <name>ref_binding-notification-broker</name>
+ <name>binding-notification-broker</name>
</notification-service>
<data-broker xmlns="urn:opendaylight:params:xml:ns:yang:controller:md:sal:binding:impl">
<type xmlns:binding="urn:opendaylight:params:xml:ns:yang:controller:md:sal:binding">binding:binding-data-broker</type>
- <name>ref_binding-data-broker</name>
+ <name>binding-data-broker</name>
</data-broker>
</module>
<module>
<name>binding-data-broker</name>
<dom-broker xmlns="urn:opendaylight:params:xml:ns:yang:controller:md:sal:binding:impl">
<type xmlns:dom="urn:opendaylight:params:xml:ns:yang:controller:md:sal:dom">dom:dom-broker-osgi-registry</type>
- <name>ref_dom-broker</name>
+ <name>dom-broker</name>
</dom-broker>
<mapping-service xmlns="urn:opendaylight:params:xml:ns:yang:controller:md:sal:binding:impl">
<type xmlns:binding="urn:opendaylight:params:xml:ns:yang:controller:md:sal:binding:impl">binding:binding-dom-mapping-service</type>
- <name>ref_runtime-mapping-singleton</name>
+ <name>runtime-mapping-singleton</name>
</mapping-service>
</module>
//SERVICES START
<service>
<type xmlns:dom="urn:opendaylight:params:xml:ns:yang:controller:md:sal:dom">dom:schema-service</type>
<instance>
- <name>ref_yang-schema-service</name>
+ <name>yang-schema-service</name>
<provider>/modules/module[type='schema-service-singleton'][name='yang-schema-service']</provider>
</instance>
</service>
<service>
<type xmlns:binding="urn:opendaylight:params:xml:ns:yang:controller:md:sal:binding">binding:binding-notification-service</type>
<instance>
- <name>ref_binding-notification-broker</name>
+ <name>binding-notification-broker</name>
<provider>/modules/module[type='binding-notification-broker'][name='binding-notification-broker']</provider>
</instance>
</service>
<service>
<type xmlns:dom="urn:opendaylight:params:xml:ns:yang:controller:md:sal:dom">dom:dom-data-store</type>
<instance>
- <name>ref_hash-map-data-store</name>
+ <name>hash-map-data-store</name>
<provider>/modules/module[type='hash-map-data-store'][name='hash-map-data-store']</provider>
</instance>
<instance>
- <name>ref_cluster-data-store</name>
+ <name>cluster-data-store</name>
<provider>/modules/module[type='dom-clustered-store-impl'][name='cluster-data-store']</provider>
</instance>
</service>
<service>
<type xmlns:binding="urn:opendaylight:params:xml:ns:yang:controller:md:sal:binding">binding:binding-broker-osgi-registry</type>
<instance>
- <name>ref_binding-broker-impl</name>
+ <name>binding-osgi-broker</name>
<provider>/modules/module[type='binding-broker-impl'][name='binding-broker-impl']</provider>
</instance>
</service>
<service>
<type xmlns:binding-impl="urn:opendaylight:params:xml:ns:yang:controller:md:sal:binding:impl">binding-impl:binding-dom-mapping-service</type>
<instance>
- <name>ref_runtime-mapping-singleton</name>
+ <name>runtime-mapping-singleton</name>
<provider>/modules/module[type='runtime-generated-mapping'][name='runtime-mapping-singleton']</provider>
</instance>
</service>
<service>
<type xmlns:dom="urn:opendaylight:params:xml:ns:yang:controller:md:sal:dom">dom:dom-broker-osgi-registry</type>
<instance>
- <name>ref_dom-broker</name>
+ <name>dom-broker</name>
<provider>/modules/module[type='dom-broker-impl'][name='dom-broker']</provider>
</instance>
</service>
<service>
<type xmlns:binding="urn:opendaylight:params:xml:ns:yang:controller:md:sal:binding">binding:binding-data-broker</type>
<instance>
- <name>ref_binding-data-broker</name>
+ <name>binding-data-broker</name>
<provider>/modules/module[type='binding-data-broker'][name='binding-data-broker']</provider>
</instance>
</service>
<logger name="org.opendaylight.controller.sal.implementation" level="INFO"/>
<logger name="org.opendaylight.controller.sal.implementation.internal.Inventory" level="INFO"/>
<logger name="org.opendaylight.controller.sal.implementation.internal.Topology" level="INFO"/>
- <!-- zeromq router and zeromq routing table -->
+ <!-- remoterpc router and remoterpc routing table -->
<logger name="org.opendaylight.controller.sal.connector.remoterpc" level="INFO" />
<!-- Functional Modules -->
<logger name="org.opendaylight.controller.arphandler" level="INFO"/>
dataPacketPublisher.receiveDataPacket(inPacket);
}
- public static def RawPacket toRawPacket(PacketReceived received) {
+ public static def RawPacket toRawPacket(PacketReceived received) {
val ret = new RawPacket(received.payload);
+ ret.setIncomingNodeConnector(NodeMapping.toADNodeConnector(received.ingress))
return ret;
}
}
override onNodeRemoved(NodeRemoved notification) {
- // NOOP
+ val properties = Collections.<org.opendaylight.controller.sal.core.Property>emptySet();
+ val org.opendaylight.yangtools.yang.binding.InstanceIdentifier<? extends DataObject> identifier = notification.nodeRef.value as org.opendaylight.yangtools.yang.binding.InstanceIdentifier<? extends DataObject>;
+
+ inventoryPublisher.updateNode(notification.nodeRef.toADNode, UpdateType.REMOVED, properties);
}
override onNodeConnectorUpdated(NodeConnectorUpdated update) {
- val properties = Collections.<org.opendaylight.controller.sal.core.Property>emptySet();
- inventoryPublisher.updateNodeConnector(update.nodeConnectorRef.toADNodeConnector, UpdateType.CHANGED, properties);
+ val properties = new java.util.HashSet<org.opendaylight.controller.sal.core.Property>();
+
+
+ val org.opendaylight.yangtools.yang.binding.InstanceIdentifier<? extends DataObject> identifier = update.nodeConnectorRef.value as org.opendaylight.yangtools.yang.binding.InstanceIdentifier<? extends DataObject>;
+ var updateType = UpdateType.CHANGED;
+ if ( this._dataService.readOperationalData(identifier) == null ){
+ updateType = UpdateType.ADDED;
+ }
+
+ var nodeConnector = update.nodeConnectorRef.toADNodeConnector
+
+
+ properties.add(new org.opendaylight.controller.sal.core.Name(nodeConnector.ID.toString()));
+
+ inventoryPublisher.updateNodeConnector(nodeConnector , updateType , properties);
}
override onNodeUpdated(NodeUpdated notification) {
val properties = Collections.<org.opendaylight.controller.sal.core.Property>emptySet();
- inventoryPublisher.updateNode(notification.nodeRef.toADNode, UpdateType.CHANGED, properties);
+ val org.opendaylight.yangtools.yang.binding.InstanceIdentifier<? extends DataObject> identifier = notification.nodeRef.value as org.opendaylight.yangtools.yang.binding.InstanceIdentifier<? extends DataObject>;
+
+ var updateType = UpdateType.CHANGED;
+ if ( this._dataService.readOperationalData(identifier) == null ){
+ updateType = UpdateType.ADDED;
+ }
+ inventoryPublisher.updateNode(notification.nodeRef.toADNode, updateType, properties);
}
override getNodeProps() {
import org.opendaylight.controller.sal.reader.NodeTableStatistics;
import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.yang.types.rev100924.Counter64;
import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.statistics.rev130819.FlowStatisticsUpdatedBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.statistics.rev130819.GetAggregateFlowStatisticsFromFlowTableForAllFlowsInput;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.statistics.rev130819.GetAggregateFlowStatisticsFromFlowTableForAllFlowsOutput;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.statistics.rev130819.GetAggregateFlowStatisticsFromFlowTableForGivenMatchInput;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.statistics.rev130819.GetAggregateFlowStatisticsFromFlowTableForGivenMatchOutput;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.statistics.rev130819.GetAllFlowStatisticsFromFlowTableInput;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.statistics.rev130819.GetAllFlowStatisticsFromFlowTableOutput;
import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.statistics.rev130819.GetAllFlowStatisticsInput;
import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.statistics.rev130819.GetAllFlowStatisticsOutput;
import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.statistics.rev130819.GetAllFlowStatisticsOutputBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.statistics.rev130819.GetAllFlowsStatisticsFromAllFlowTablesInput;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.statistics.rev130819.GetAllFlowsStatisticsFromAllFlowTablesOutput;
import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.statistics.rev130819.GetAllNodeConnectorStatisticsInput;
import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.statistics.rev130819.GetAllNodeConnectorStatisticsOutput;
import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.statistics.rev130819.GetAllNodeConnectorStatisticsOutputBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.statistics.rev130819.GetFlowStatisticsFromFlowTableInput;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.statistics.rev130819.GetFlowStatisticsFromFlowTableOutput;
import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.statistics.rev130819.GetFlowStatisticsInput;
import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.statistics.rev130819.GetFlowStatisticsOutput;
import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.statistics.rev130819.GetFlowStatisticsOutputBuilder;
return builder.build();
}
+ @Override
+ public Future<RpcResult<GetAggregateFlowStatisticsFromFlowTableForAllFlowsOutput>> getAggregateFlowStatisticsFromFlowTableForAllFlows(
+ GetAggregateFlowStatisticsFromFlowTableForAllFlowsInput input) {
+ // TODO Auto-generated method stub
+ return null;
+ }
+
+ @Override
+ public Future<RpcResult<GetAggregateFlowStatisticsFromFlowTableForGivenMatchOutput>> getAggregateFlowStatisticsFromFlowTableForGivenMatch(
+ GetAggregateFlowStatisticsFromFlowTableForGivenMatchInput input) {
+ // TODO Auto-generated method stub
+ return null;
+ }
+
+ @Override
+ public Future<RpcResult<GetAllFlowStatisticsFromFlowTableOutput>> getAllFlowStatisticsFromFlowTable(
+ GetAllFlowStatisticsFromFlowTableInput input) {
+ // TODO Auto-generated method stub
+ return null;
+ }
+
+ @Override
+ public Future<RpcResult<GetAllFlowsStatisticsFromAllFlowTablesOutput>> getAllFlowsStatisticsFromAllFlowTables(
+ GetAllFlowsStatisticsFromAllFlowTablesInput input) {
+ // TODO Auto-generated method stub
+ return null;
+ }
+
+ @Override
+ public Future<RpcResult<GetFlowStatisticsFromFlowTableOutput>> getFlowStatisticsFromFlowTable(
+ GetFlowStatisticsFromFlowTableInput input) {
+ // TODO Auto-generated method stub
+ return null;
+ }
+
}
revision "2013-10-26" {
description "Initial revision of macth types";
}
-
+
grouping "mac-address-filter" {
leaf address {
mandatory true;
container vlan-id {
description "VLAN id.";
presence "Match field is active and set";
-
+
+ leaf vlan-id-present {
+ type boolean;
+ }
+
leaf vlan-id {
- mandatory true;
type l2t:vlan-id;
}
- leaf mask {
- type binary;
- }
}
leaf vlan-pcp {
description "VLAN priority.";
}
}
}
-
+
+ case strip-vlan-action-case {
+ container strip-vlan-action {
+ }
+ }
case sw-path-action-case {
container sw-path-action {
}
}
}
-}
\ No newline at end of file
+}
description "Initial revision of flow service";
}
+ typedef output-port-values {
+ type enumeration {
+ enum MAX {
+ value 1;
+ }
+ enum IN_PORT {
+ value 2;
+ }
+ enum TABLE {
+ value 3;
+ }
+ enum NORMAL {
+ value 4;
+ }
+ enum FLOOD {
+ value 5;
+ }
+ enum ALL {
+ value 6;
+ }
+ enum CONTROLLER {
+ value 7;
+ }
+ enum LOCAL {
+ value 8;
+ }
+ enum ANY {
+ value 9;
+ }
+ enum NONE {
+ value 10;
+ }
+
+ }
+ }
grouping instruction-list {
list instruction {
key "order";
uses match:match;
}
}
-}
\ No newline at end of file
+}
import ietf-inet-types {prefix inet; revision-date "2010-09-24";}
import ietf-yang-types {prefix yang; revision-date "2010-09-24";}
+ import opendaylight-queue-types {prefix queue-types; revision-date "2013-09-25";}
revision "2013-09-25" {
description "Initial revision of Port Inventory model";
uses flow-capable-port;
}
+ grouping queues {
+ list queue {
+ key "queue-id";
+ uses queue-types:queue-packet;
+ }
+ }
+
grouping flow-capable-port {
uses common-port;
units "kbps";
description "Max port bit rate in kbps";
}
+
+ uses queues;
}
grouping port-mod {
description "Initial revision of Queue Inventory model";
}
+ typedef queue-id {
+ type yang:counter32;
+ description "id for the specific queue.";
+ }
+
typedef queue-properties {
type enumeration {
enum min_rate;
}
}
-
-
grouping queue-prop-max-rate {
leaf queue-id {
- type uint32;
+ type queue-id;
description "id for the specific queue.";
}
description "Initial revision of table service";
}
+ typedef table-id {
+ type uint8;
+ }
+
typedef table-ref {
type instance-identifier;
}
revision "2013-08-19" {
description "Flow Capable Node extensions to the Inventory model";
}
-
+
+ identity feature-capability {
+ }
+
+ identity flow-feature-capability-flow-stats {
+ description "Flow statistics";
+ base feature-capability;
+ }
+
+ identity flow-feature-capability-table-stats {
+ description "Table statistics";
+ base feature-capability;
+ }
+
+ identity flow-feature-capability-port-stats {
+ description "Port statistics";
+ base feature-capability;
+ }
+
+ identity flow-feature-capability-stp {
+ description "802.1d spanning tree";
+ base feature-capability;
+ }
+
+ identity flow-feature-capability-reserved {
+ description "Reserved, must be zero";
+ base feature-capability;
+ }
+
+ identity flow-feature-capability-ip-reasm {
+ description "Can reassemble IP fragments";
+ base feature-capability;
+ }
+
+ identity flow-feature-capability-queue-stats {
+ description "Queue statistics";
+ base feature-capability;
+ }
+
+ identity flow-feature-capability-arp-match-ip {
+ description "Match IP addresses in ARP pkts";
+ base feature-capability;
+ }
+
+ identity flow-feature-capability-group-stats {
+ description "Group statistics";
+ base feature-capability;
+ }
+
+ identity flow-feature-capability-port-blocked {
+ description "Switch will block looping ports";
+ base feature-capability;
+ }
+
grouping feature {
leaf support-state {
type inv:support-type;
uses meter:meter;
}
}
-
+
+
grouping flow-node {
leaf manufacturer {
}
}
}
+
+ container switch-features {
+
+ leaf max_buffers {
+ type uint32;
+ }
+
+ leaf max_tables {
+ type uint8;
+ }
+
+ leaf-list capabilities {
+ type identityref {
+ base feature-capability;
+ }
+ }
+
+ }
}
grouping flow-node-connector {
ext:augment-identifier "flow-capable-node-connector-update-fields";
uses flow-node-connector;
}
-
+
augment "/inv:node-connector-updated" {
ext:augment-identifier "flow-capable-node-connector-updated";
uses flow-node-connector;
}
+
}
\ No newline at end of file
notification flow-added {
uses node-flow;
+ uses tr:transaction-aware;
}
notification flow-updated {
uses node-flow;
+ uses tr:transaction-aware;
}
notification flow-removed {
uses node-flow;
+ uses tr:transaction-aware;
}
notification switch-flow-removed {
notification group-added {
uses node-group;
+ uses tr:transaction-aware;
}
notification group-updated {
uses node-group;
+ uses tr:transaction-aware;
}
notification group-removed {
uses node-group;
+ uses tr:transaction-aware;
}
}
\ No newline at end of file
notification meter-added {
uses node-meter;
+ uses tr:transaction-aware;
}
notification meter-updated {
uses node-meter;
+ uses tr:transaction-aware;
}
notification meter-removed {
uses node-meter;
+ uses tr:transaction-aware;
}
}
\ No newline at end of file
output {
uses port-type:flow-capable-port;
}
- }
+ }
+
+ notification port-updated {
+ uses port-update;
+ uses tr:transaction-aware;
+ }
notification port-removed {
- uses node-port;
+ uses node-port;
}
}
\ No newline at end of file
prefix flowstat;
import yang-ext {prefix ext; revision-date "2013-07-09";}
+ import ietf-yang-types {prefix yang; revision-date "2010-09-24";}
import opendaylight-inventory {prefix inv;revision-date "2013-08-19";}
import opendaylight-flow-types {prefix flow-types;revision-date "2013-10-26";}
- import sal-flow {prefix flow;}
import opendaylight-statistics-types {prefix stat-types;revision-date "2013-09-25";}
+ import opendaylight-table-types {prefix table-types;revision-date "2013-10-26";}
+ import flow-node-inventory {prefix flow-node;revision-date "2013-08-19";}
+ import flow-capable-transaction {prefix tr;}
+ import sal-flow {prefix flow;}
+
revision "2013-08-19" {
- description "Initial revision of flow service";
+ description "Initial revision of flow statistics service";
+ }
+
+ //Augment flow statistics data to the flow-capable-node->table->flow
+ augment "/inv:nodes/inv:node/flow-node:table/flow-node:flow" {
+ ext:augment-identifier "flow-statistics-data";
+ uses flow-statistics;
+ }
+
+ grouping flow-statistics {
+ container flow-statistics {
+ //config "false";
+ uses flow-types:flow;
+ uses stat-types:generic-statistics;
+ }
+ }
+
+ typedef flow-id {
+ description "flow id";
+ type yang:counter32;
+ }
+
+ grouping flow-and-statistics-map-list {
+ description "List of flow and statistics map";
+ list flow-and-statistics-map-list {
+ key "flow-id";
+ leaf flow-id {
+ type flow-id;
+ }
+ uses flow-and-statistics-map;
+ }
+ }
+
+ grouping flow-and-statistics-map{
+ description "Mapping between flow and its statistics";
+ uses flow-types:flow;
+ uses stat-types:generic-statistics;
+ }
+
+ // RPC calls to fetch flow statistics
+ rpc get-all-flows-statistics-from-all-flow-tables {
+ description "Fetch statistics of all the flow present in all the flow tables of the switch";
+ input {
+ uses inv:node-context-ref;
+ }
+ output {
+ uses flow-and-statistics-map-list;
+ uses tr:transaction-aware;
+ }
+
}
- rpc get-node-connector-statistics {
+ rpc get-all-flow-statistics-from-flow-table {
+ description "Fetch statistics of all the flow present in the specific flow table of the switch";
input {
uses inv:node-context-ref;
- leaf node-connector {
- type inv:node-connector-ref;
+ leaf table-id {
+ type table-types:table-id;
}
}
output {
- uses stat-types:node-connector-statistics;
+ uses flow-and-statistics-map-list;
+ uses tr:transaction-aware;
}
}
- rpc get-flow-statistics {
+ rpc get-flow-statistics-from-flow-table {
+ description "Fetch statistics of the specific flow present in the specific flow table of the switch";
+ input {
+ uses inv:node-context-ref;
+ uses flow-types:flow;
+ }
+ output {
+ uses flow-and-statistics-map-list;
+ uses tr:transaction-aware;
+ }
+ }
+
+ notification flows-statistics-update {
+ description "Flows statistics sent by switch";
+ leaf moreReplies {
+ type boolean;
+ }
+ uses inv:node;
+ uses flow-and-statistics-map-list;
+ uses tr:transaction-aware;
+ }
+
+ //Models for aggregate flow statistics collection
+ augment "/inv:nodes/inv:node/flow-node:table" {
+ ext:augment-identifier "aggregate-flow-statistics-data";
+ uses aggregate-flow-statistics;
+ }
+
+ grouping aggregate-flow-statistics {
+ container aggregate-flow-statistics {
+ //config "false";
+ uses stat-types:aggregate-flow-statistics;
+ }
+ }
+
+ // RPC calls to fetch flow statistics
+ rpc get-aggregate-flow-statistics-from-flow-table-for-all-flows {
+ description "Fetch aggregate statistics for all the flows present in the specific flow table of the switch";
+ input {
+ uses inv:node-context-ref;
+ leaf table-id {
+ type table-types:table-id;
+ }
+ }
+ output {
+ uses stat-types:aggregate-flow-statistics;
+ uses tr:transaction-aware;
+ }
+ }
+ rpc get-aggregate-flow-statistics-from-flow-table-for-given-match {
+ description "Fetch aggregate statistics for all the flow matches to the given match from the given table of the switch";
+ input {
+ uses inv:node-context-ref;
+ uses flow-types:flow;
+ }
+ output {
+ uses stat-types:aggregate-flow-statistics;
+ uses tr:transaction-aware;
+ }
+ }
+
+ notification aggregate-flow-statistics-update {
+ description "Aggregate flow statistics for a table, sent by switch";
+ leaf moreReplies {
+ type boolean;
+ }
+ uses inv:node;
+ uses stat-types:aggregate-flow-statistics;
+ uses tr:transaction-aware;
+ }
+
+ //Keeping flow statistics RPC call for backward compatibility for sal-compatibility layer --START
+ rpc get-flow-statistics {
input {
uses inv:node-context-ref;
uses flow-types:flow;
}
}
+ notification flow-statistics-updated {
+ uses flow-types:flow-statistics;
+ }
+
+ //Keeping flow statistics RPC call for backward compatibility for sal-compatibility layer --END
+
+ //RPC call to fetch node connector statistics
+ rpc get-node-connector-statistics {
+ input {
+ uses inv:node-context-ref;
+ leaf node-connector {
+ type inv:node-connector-ref;
+ }
+ }
+ output {
+ uses stat-types:node-connector-statistics;
+ }
+ }
+
rpc get-all-node-connector-statistics {
input {
uses inv:node-context-ref;
}
}
- notification flow-statistics-updated {
- uses flow-types:flow-statistics;
- }
-
rpc get-flow-table-statistics {
input {
uses inv:node-context-ref;
notification node-connector-statistics-updated {
uses stat-types:node-connector-statistics;
}
-
-
}
--- /dev/null
+module opendaylight-flow-table-statistics {
+ namespace "urn:opendaylight:flow:table:statistics";
+ prefix flowtablestat;
+
+ import flow-capable-transaction {prefix tr;}
+ import yang-ext {prefix ext; revision-date "2013-07-09";}
+ import ietf-yang-types {prefix yang; revision-date "2010-09-24";}
+ import opendaylight-inventory {prefix inv;revision-date "2013-08-19";}
+ import flow-node-inventory {prefix flow-node;revision-date "2013-08-19";}
+ import opendaylight-table-types {prefix table-types;revision-date "2013-10-26";}
+ import opendaylight-statistics-types {prefix stat-types;revision-date "2013-09-25";}
+
+
+ contact
+ "Anilkumar Vishnoi
+ Email: avishnoi@in.ibm.com";
+
+ revision "2013-12-15" {
+ description "Initial revision of flow table statistics model";
+ }
+
+ //Augment flow table statistics data to the table
+ augment "/inv:nodes/inv:node/flow-node:table" {
+ ext:augment-identifier "flow-table-statistics-data";
+ uses flow-table-statistics;
+ }
+
+ grouping flow-table-statistics {
+ container flow-table-statistics {
+ //config "false";
+ uses stat-types:generic-table-statistics;
+ }
+ }
+
+ //RPC calls to fetch flow table statistics
+ grouping flow-table-and-statistics-map {
+ list flow-table-and-statistics-map {
+ key "table-id";
+ leaf table-id {
+ type table-types:table-id;
+ }
+ uses stat-types:generic-table-statistics;
+ }
+ }
+
+ rpc get-flow-tables-statistics {
+ description "Fetch statistics of all the flow tables present on the tarnet node";
+ input {
+ uses inv:node-context-ref;
+ }
+ output {
+ uses flow-table-and-statistics-map;
+ uses tr:transaction-aware;
+ }
+ }
+
+ //Notification to receive table statistics update
+
+ notification flow-table-statistics-update {
+ description "Receive flow table statistics update";
+
+ leaf moreReplies {
+ type boolean;
+ }
+ uses inv:node;
+ uses flow-table-and-statistics-map;
+ uses tr:transaction-aware;
+ }
+}
grouping group-statistics {
container group-statistics {
//config "false";
- uses group-types:group-statistics-reply;
+ uses group-types:group-statistics;
}
}
- augment "/inv:nodes/inv:node" {
+ augment "/inv:nodes/inv:node/group-types:group" {
ext:augment-identifier "node-group-statistics";
uses group-statistics;
}
grouping group-desc {
container group-desc {
//config "false";
- uses group-types:group-desc-stats-reply;
+ uses group-types:group;
}
}
- augment "/inv:nodes/inv:node" {
+ augment "/inv:nodes/inv:node/group-types:group" {
ext:augment-identifier "node-group-desc-stats";
uses group-desc;
}
import yang-ext {prefix ext; revision-date "2013-07-09";}
import opendaylight-inventory {prefix inv;revision-date "2013-08-19";}
+ import flow-node-inventory {prefix flow-node;revision-date "2013-08-19";}
import opendaylight-meter-types {prefix meter-types;revision-date "2013-09-18";}
import flow-capable-transaction {prefix tr;}
description "Initial revision of meter statistics service";
}
- augment "/inv:nodes/inv:node" {
+ augment "/inv:nodes/inv:node/flow-node:meter" {
ext:augment-identifier "node-meter-statistics";
container meter-statistics {
//config "false";
- uses meter-types:meter-statistics-reply;
+ uses meter-types:meter-statistics;
}
}
- augment "/inv:nodes/inv:node" {
+ augment "/inv:nodes/inv:node/flow-node:meter" {
ext:augment-identifier "node-meter-config-stats";
container meter-config-stats {
//config "false";
- uses meter-types:meter-config-stats-reply;
+ uses meter-types:meter;
}
}
--- /dev/null
+module opendaylight-port-statistics {
+ namespace "urn:opendaylight:port:statistics";
+ prefix portstat;
+
+ import flow-capable-transaction {prefix tr;}
+ import yang-ext {prefix ext; revision-date "2013-07-09";}
+ import ietf-yang-types {prefix yang; revision-date "2010-09-24";}
+ import opendaylight-inventory {prefix inv;revision-date "2013-08-19";}
+ import opendaylight-statistics-types {prefix stat-types;revision-date "2013-09-25";}
+
+ contact
+ "Anilkumar Vishnoi
+ Email: avishnoi@in.ibm.com";
+
+ revision "2013-12-14" {
+ description "Initial revision of port statistics model";
+ }
+
+ //Augment port statistics data to the flow-capable-node-connector
+ augment "/inv:nodes/inv:node/inv:node-connector" {
+ ext:augment-identifier "flow-capable-node-connector-statistics-data";
+ uses flow-capable-node-connector-statistics;
+ }
+
+ grouping flow-capable-node-connector-statistics {
+ container flow-capable-node-connector-statistics {
+ //config "false";
+ uses stat-types:node-connector-statistics;
+ }
+ }
+
+ // RPC calls
+ rpc get-all-ports-statistics {
+ description "Get statistics for all the ports from the node";
+ input {
+ uses inv:node-context-ref;
+ }
+ output {
+ uses stat-types:node-connector-statistics;
+ uses tr:transaction-aware;
+ }
+ }
+
+ rpc get-port-statistics {
+ description "Get statistics for given port from the node";
+ input {
+ uses inv:node-context-ref;
+ leaf node-connector-id {
+ type inv:node-connector-id;
+ }
+ }
+ output {
+ uses stat-types:node-connector-statistics;
+ uses tr:transaction-aware;
+ }
+ }
+
+ //Notification for port statistics update
+ grouping node-connector-statistics-and-port-number-map {
+ description "List of flow and statistics map";
+ list node-connector-statistics-and-port-number-map {
+ key "node-connector-id";
+ leaf node-connector-id {
+ type inv:node-connector-id;
+ }
+ uses stat-types:node-connector-statistics;
+ }
+ }
+
+ notification port-statistics-update {
+ leaf moreReplies {
+ type boolean;
+ }
+ uses inv:node;
+ uses node-connector-statistics-and-port-number-map;
+ uses tr:transaction-aware;
+ }
+}
--- /dev/null
+module opendaylight-queue-statistics {
+ namespace "urn:opendaylight:queue:statistics";
+ prefix queuestat;
+
+ import flow-capable-transaction {prefix tr;}
+ import yang-ext {prefix ext; revision-date "2013-07-09";}
+ import ietf-yang-types {prefix yang; revision-date "2010-09-24";}
+ import opendaylight-inventory {prefix inv;revision-date "2013-08-19";}
+ import flow-node-inventory {prefix flow-node;revision-date "2013-08-19";}
+ import opendaylight-queue-types {prefix queue-types;revision-date "2013-09-25";}
+ import opendaylight-statistics-types {prefix stat-types;revision-date "2013-09-25";}
+
+ contact
+ "Anilkumar Vishnoi
+ Email: avishnoi@in.ibm.com";
+
+ revision "2013-12-16" {
+ description "Initial revision of queue statistics model";
+ }
+
+ //Augment queue statistics data to the flow-capable-node-connector
+ augment "/inv:nodes/inv:node/inv:node-connector/flow-node:queue" {
+ ext:augment-identifier "flow-capable-node-connector-queue-statistics-data";
+ uses flow-capable-node-connector-queue-statistics;
+ }
+
+ grouping flow-capable-node-connector-queue-statistics {
+ container flow-capable-node-connector-queue-statistics {
+ //config "false";
+ uses stat-types:generic-queue-statistics;
+ }
+ }
+
+ //RPC calls to fetch queue statistics
+ grouping queue-id-and-statistics-map {
+ list queue-id-and-statistics-map {
+ key "queue-id node-connector-id";
+ leaf queue-id {
+ type queue-types:queue-id;
+ }
+ leaf node-connector-id {
+ type inv:node-connector-id;
+ }
+
+ uses stat-types:generic-queue-statistics;
+ }
+ }
+
+ rpc get-all-queues-statistics-from-all-ports {
+ description "Get statistics for all the queues attached to all the ports from the node";
+ input {
+ uses inv:node-context-ref;
+ }
+ output {
+ uses queue-id-and-statistics-map;
+ uses tr:transaction-aware;
+ }
+ }
+
+ rpc get-all-queues-statistics-from-given-port {
+ description "Get statistics for all queues for given port of the node";
+ input {
+ uses inv:node-context-ref;
+ leaf node-connector-id {
+ type inv:node-connector-id;
+ }
+ }
+ output {
+ uses queue-id-and-statistics-map;
+ uses tr:transaction-aware;
+ }
+ }
+
+ rpc get-queue-statistics-from-given-port {
+ description "Get statistics for given queues from given port of the node";
+ input {
+ uses inv:node-context-ref;
+ leaf node-connector-id {
+ type inv:node-connector-id;
+ }
+ leaf queue-id {
+ type queue-types:queue-id;
+ }
+ }
+ output {
+ uses queue-id-and-statistics-map;
+ uses tr:transaction-aware;
+ }
+ }
+
+ //Notification for port statistics update
+
+ notification queue-statistics-update {
+ leaf moreReplies {
+ type boolean;
+ }
+ uses inv:node;
+ uses queue-id-and-statistics-map;
+ uses tr:transaction-aware;
+ }
+}
revision "2013-09-25" {
description "Initial revision of flow service";
- }
+ }
+
+ grouping duration {
+ container duration {
+ leaf second {
+ type yang:counter32;
+ }
+ leaf nanosecond {
+ type yang:counter32;
+ }
+ }
+ }
grouping node-connector-statistics {
container packets {
leaf collision-count {
type uint64;
}
-
- container duration {
- leaf second {
- type yang:counter32;
- }
- leaf nanosecond {
- type yang:counter32;
- }
+ uses duration;
+ }
+
+ grouping generic-statistics {
+ description "Generic grouping for statistics";
+ leaf packet-count {
+ type yang:counter64;
+ }
+
+ leaf byte-count {
+ type yang:counter64;
+ }
+ uses duration;
+ }
+
+ grouping generic-table-statistics {
+ description "Generic grouping holding generic statistics related to switch table";
+ leaf active-flows {
+ type yang:counter32;
+ }
+ leaf packets-looked-up {
+ type yang:counter64;
+ }
+ leaf packets-matched {
+ type yang:counter64;
+ }
+ }
+
+ grouping aggregate-flow-statistics {
+ description "Aggregate flow statistics";
+ leaf packet-count {
+ type yang:counter64;
+ }
+
+ leaf byte-count {
+ type yang:counter64;
}
+ leaf flow-count {
+ type yang:counter32;
+ }
+ }
+
+ grouping generic-queue-statistics {
+ description "Generic statistics of switch port attached queues.";
+ leaf transmitted-bytes {
+ type yang:counter64;
+ }
+
+ leaf transmitted-packets {
+ type yang:counter64;
+ }
+
+ leaf transmission-errors {
+ type yang:counter64;
+ }
+ uses duration;
}
+
}
\ No newline at end of file
<module>sal-rest-connector</module>
<module>sal-netconf-connector</module>
- <module>zeromq-routingtable/implementation</module>
+ <module>remoterpc-routingtable/implementation</module>
<module>sal-remoterpc-connector/implementation</module>
<!-- Clustered Data Store -->
<module>clustered-data-store/implementation</module>
<sonar.host.url>https://sonar.opendaylight.org/</sonar.host.url>
<sonar.branch>${user.name}-private-view</sonar.branch>
<sonar.language>java</sonar.language>
+ <exam.version>3.0.0</exam.version>
</properties>
<pluginRepositories>
<groupId>org.apache.felix</groupId>
<artifactId>maven-bundle-plugin</artifactId>
</plugin>
+ <plugin>
+ <groupId>org.codehaus.mojo</groupId>
+ <artifactId>build-helper-maven-plugin</artifactId>
+ <version>1.8</version>
+ <executions>
+ <execution>
+ <id>add-source</id>
+ <phase>generate-sources</phase>
+ <goals>
+ <goal>add-source</goal>
+ </goals>
+ <configuration>
+ <sources>
+ <source>${project.build.directory}/generated-sources/config</source>
+ <source>${project.build.directory}/generated-sources/sal</source>
+ </sources>
+ </configuration>
+ </execution>
+ </executions>
+ </plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-jar-plugin</artifactId>
<tag>HEAD</tag>
</scm>
- <artifactId>zeromq-routingtable.implementation</artifactId>
+ <artifactId>remoterpc-routingtable.implementation</artifactId>
<version>0.4.1-SNAPSHOT</version>
<packaging>bundle</packaging>
import java.util.Collections;
import java.util.EnumSet;
import java.util.HashSet;
+import java.util.Map;
import java.util.Set;
import java.util.concurrent.ConcurrentMap;
return this.routingTableCache;
}
+ /**
+ * This is used from integration test NP rest API to check out the result of the
+ * cache population
+ * <Note> For testing purpose only-- use it wisely</Note>
+ * @return
+ */
+ public String dumpRoutingTableCache(){
+ Set<Map.Entry<I, R>> cacheEntrySet = this.routingTableCache.entrySet();
+ StringBuilder sb = new StringBuilder();
+ for(Map.Entry<I,R> entry:cacheEntrySet){
+ sb.append("Key:").append(entry.getKey()).append("---->Value:")
+ .append((entry.getValue() != null)?entry.getValue():"null")
+ .append("\n");
+ }
+ return sb.toString();
+ }
+
/**
* Invoked when a new entry is available in the cache, the key is only
* provided, the value will come as an entryUpdate invocation
<tag>HEAD</tag>
</scm>
- <artifactId>zeromq-routingtable.integrationtest</artifactId>
+ <artifactId>remoterpc-routingtable.integrationtest</artifactId>
<version>0.4.1-SNAPSHOT</version>
<dependencies>
<dependency>
<groupId>org.opendaylight.controller</groupId>
- <artifactId>zeromq-routingtable.implementation</artifactId>
+ <artifactId>remoterpc-routingtable.implementation</artifactId>
<version>0.4.1-SNAPSHOT</version>
</dependency>
<dependency>
.versionAsInProject(),
mavenBundle(ODL, "sal-connector-api")
.versionAsInProject(),
- mavenBundle(ODL, "zeromq-routingtable.implementation")
+ mavenBundle(ODL, "remoterpc-routingtable.implementation")
.versionAsInProject(),
mavenBundle("org.jboss.spec.javax.transaction",
--- /dev/null
+<?xml version="1.0" encoding="UTF-8"?>
+<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+ xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+ <modelVersion>4.0.0</modelVersion>
+ <parent>
+ <artifactId>sal-remoterpc-connector-test-parent</artifactId>
+ <groupId>org.opendaylight.controller.tests</groupId>
+ <version>1.0-SNAPSHOT</version>
+ </parent>
+
+ <artifactId>remoterpc-routingtable-nb-it</artifactId>
+ <packaging>bundle</packaging>
+
+ <build>
+ <plugins>
+ <plugin>
+ <groupId>org.apache.felix</groupId>
+ <artifactId>maven-bundle-plugin</artifactId>
+ <version>${bundle.plugin.version}</version>
+ <extensions>true</extensions>
+ <configuration>
+ <instructions>
+ <Export-Package>
+ org.opendaylight.controller.tests.zmqroutingtable.rest
+ </Export-Package>
+ <Import-Package>
+ com.sun.jersey.spi.container.servlet,
+ org.codehaus.jackson.annotate,
+ javax.ws.rs,
+ javax.ws.rs.core,
+ javax.xml.bind,
+ javax.xml.bind.annotation,
+ org.slf4j,
+ org.apache.catalina.filters,
+ org.codehaus.jackson.jaxrs,
+ org.opendaylight.controller.sal.utils,
+ org.opendaylight.yangtools.yang.common,
+ org.opendaylight.controller.sal.connector.api,
+ org.opendaylight.controller.sal.connector.remoterpc.api,
+ org.opendaylight.controller.sal.connector.remoterpc.impl,
+ org.osgi.framework,
+ com.google.common.base,
+ org.opendaylight.yangtools.yang.data.api,
+ !org.codehaus.enunciate.jaxrs
+
+ </Import-Package>
+ <Web-ContextPath>/controller/nb/v2/zmqnbrt</Web-ContextPath>
+ <Jaxrs-Resources>,${classes;ANNOTATION;javax.ws.rs.Path}</Jaxrs-Resources>
+ </instructions>
+ <manifestLocation>${project.basedir}/src/main/resources/META-INF</manifestLocation>
+ </configuration>
+ </plugin>
+ </plugins>
+ </build>
+ <dependencies>
+ <dependency>
+ <groupId>org.opendaylight.controller</groupId>
+ <artifactId>containermanager</artifactId>
+ <version>0.5.1-SNAPSHOT</version>
+ </dependency>
+ <dependency>
+ <groupId>org.opendaylight.controller</groupId>
+ <artifactId>commons.northbound</artifactId>
+ <version>0.4.1-SNAPSHOT</version>
+ </dependency>
+ <dependency>
+ <groupId>org.opendaylight.controller</groupId>
+ <artifactId>sal</artifactId>
+ <version>0.5.1-SNAPSHOT</version>
+ </dependency>
+
+ <dependency>
+ <groupId>org.osgi</groupId>
+ <artifactId>org.osgi.core</artifactId>
+ <version>5.0.0</version>
+ </dependency>
+ <dependency>
+ <groupId>junit</groupId>
+ <artifactId>junit</artifactId>
+ </dependency>
+ <dependency>
+ <groupId>org.opendaylight.controller</groupId>
+ <artifactId>remoterpc-routingtable.implementation</artifactId>
+ <version>0.4.1-SNAPSHOT</version>
+ </dependency>
+ <dependency>
+ <groupId>com.google.guava</groupId>
+ <artifactId>guava</artifactId>
+ </dependency>
+ </dependencies>
+
+ </project>
--- /dev/null
+package org.opendaylight.controller.tests.zmqroutingtable.rest;
+
+import org.opendaylight.controller.sal.connector.api.RpcRouter;
+import org.opendaylight.yangtools.yang.common.QName;
+import org.opendaylight.yangtools.yang.data.api.InstanceIdentifier;
+
+import java.io.Serializable;
+import java.net.URI;
+
+/**
+ * @author: syedbahm
+ * Date: 12/10/13
+ */
+public class RouteIdentifierImpl implements RpcRouter.RouteIdentifier, Serializable {
+
+ private final URI namespace;
+ private final QName QNAME;
+ private final QName instance;
+
+ public RouteIdentifierImpl() {
+ namespace = URI.create("http://cisco.com/example");
+ QNAME = new QName(namespace, "global");
+ instance = new QName(URI.create("127.0.0.1"), "local");
+ }
+
+ public RouteIdentifierImpl(String url,String instanceIP){
+ namespace = URI.create(url);
+ QNAME = new QName(namespace,"global");
+ instance = new QName(URI.create(instanceIP), "local");
+ }
+
+
+ @Override
+ public QName getContext() {
+ return QNAME;
+ }
+
+ @Override
+ public QName getType() {
+ return QNAME;
+ }
+
+ @Override
+ public org.opendaylight.yangtools.yang.data.api.InstanceIdentifier getRoute() {
+ return InstanceIdentifier.of(instance);
+ }
+
+ @Override
+ public boolean equals(Object o) {
+ if (this == o) return true;
+ if (o == null || getClass() != o.getClass()) return false;
+
+ RouteIdentifierImpl that = (RouteIdentifierImpl) o;
+
+ if (!QNAME.equals(that.QNAME)) return false;
+ if (!instance.equals(that.instance)) return false;
+ if (!namespace.equals(that.namespace)) return false;
+
+ return true;
+ }
+
+ @Override
+ public int hashCode() {
+ int result = namespace.hashCode();
+ result = 31 * result + QNAME.hashCode();
+ result = 31 * result + instance.hashCode();
+ return result;
+ }
+}
\ No newline at end of file
--- /dev/null
+package org.opendaylight.controller.tests.zmqroutingtable.rest;
+
+import org.opendaylight.controller.sal.connector.remoterpc.api.RoutingTable;
+import org.opendaylight.controller.sal.connector.remoterpc.api.RoutingTableException;
+import org.opendaylight.controller.sal.connector.remoterpc.api.SystemException;
+import org.opendaylight.controller.sal.connector.remoterpc.impl.RoutingTableImpl;
+import org.opendaylight.yangtools.yang.common.QName;
+import org.osgi.framework.Bundle;
+import org.osgi.framework.BundleContext;
+import org.osgi.framework.BundleReference;
+import org.osgi.framework.FrameworkUtil;
+import org.osgi.framework.ServiceReference;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import javax.ws.rs.GET;
+import javax.ws.rs.Path;
+import javax.ws.rs.Produces;
+import javax.ws.rs.QueryParam;
+import javax.ws.rs.core.MediaType;
+import java.io.Serializable;
+import java.net.URI;
+
+@Path("router")
+public class Router implements Serializable {
+ private Logger _logger = LoggerFactory.getLogger(Router.class);
+ private final URI namespace = URI.create("http://cisco.com/example");
+ private final QName QNAME = new QName(namespace, "heartbeat");
+
+
+ @GET
+ @Path("/hello")
+ @Produces(MediaType.TEXT_PLAIN)
+ public String hello() {
+ return "Hello";
+ }
+
+
+
+
+ @GET
+ @Path("/rtadd")
+ @Produces(MediaType.TEXT_PLAIN)
+ public String addToRoutingTable(@QueryParam("nsp") String namespace,@QueryParam("inst") String instance,@QueryParam("port") String port) {
+ _logger.info("Invoking adding an entry in routing table");
+
+ BundleContext ctx = getBundleContext();
+ ServiceReference routingTableServiceReference = ctx.getServiceReference(RoutingTable.class);
+ if (routingTableServiceReference == null) {
+ _logger.debug("Could not get routing table impl reference");
+ return "Could not get routingtable referen ";
+ }
+ RoutingTableImpl routingTable = (RoutingTableImpl) ctx.getService(routingTableServiceReference);
+ if (routingTable == null) {
+ _logger.info("Could not get routing table service");
+ return "Could not get routing table service";
+ }
+
+
+ RouteIdentifierImpl rii = new RouteIdentifierImpl(namespace,instance);
+ try {
+ routingTable.addGlobalRoute(rii, instance+":"+ port);
+ } catch (RoutingTableException e) {
+ _logger.error("error in adding routing identifier" + e.getMessage());
+
+ } catch (SystemException e) {
+ _logger.error("error in adding routing identifier" + e.getMessage());
+ }
+
+ StringBuilder stringBuilder = new StringBuilder();
+ stringBuilder.append("Result of adding route:").append("\n")
+ .append(routingTable.dumpRoutingTableCache());
+ return stringBuilder.toString();
+ }
+
+ @GET
+ @Path("/rtdelete")
+ @Produces(MediaType.TEXT_PLAIN)
+ public String invokeDeleteRoutingTable(@QueryParam("nsp") String namespace,@QueryParam("inst") String instance) {
+ _logger.info("Invoking delete an entry in routing table");
+
+ BundleContext ctx = getBundleContext();
+ ServiceReference routingTableServiceReference = ctx.getServiceReference(RoutingTable.class);
+ if (routingTableServiceReference == null) {
+ _logger.debug("Could not get routing table impl reference");
+ return "Could not get routingtable referen ";
+ }
+ RoutingTableImpl routingTable = (RoutingTableImpl) ctx.getService(routingTableServiceReference);
+ if (routingTable == null) {
+ _logger.info("Could not get routing table service");
+ return "Could not get routing table service";
+ }
+
+
+ RouteIdentifierImpl rii = new RouteIdentifierImpl(namespace,instance);
+ try {
+ routingTable.removeGlobalRoute(rii);
+ } catch (RoutingTableException e) {
+ _logger.error("error in adding routing identifier" + e.getMessage());
+
+ } catch (SystemException e) {
+ _logger.error("error in adding routing identifier" + e.getMessage());
+ }
+
+
+ StringBuilder stringBuilder = new StringBuilder();
+ stringBuilder.append("Result of deleting route:").append("\n")
+ .append(routingTable.dumpRoutingTableCache());
+
+ return stringBuilder.toString();
+ }
+
+ @GET
+ @Path("/routingtable")
+ @Produces(MediaType.TEXT_PLAIN)
+ public String invokeGetRoutingTable() {
+ _logger.info("Invoking getting of routing table");
+
+ BundleContext ctx = getBundleContext();
+ ServiceReference routingTableServiceReference = ctx.getServiceReference(RoutingTable.class);
+ if (routingTableServiceReference == null) {
+ _logger.debug("Could not get routing table impl reference");
+ return "Could not get routingtable referen ";
+ }
+ RoutingTableImpl routingTable = (RoutingTableImpl) ctx.getService(routingTableServiceReference);
+ if (routingTable == null) {
+ _logger.info("Could not get routing table service");
+ return "Could not get routing table service";
+ }
+
+
+ StringBuilder stringBuilder = new StringBuilder();
+ stringBuilder.append("Result of getting routetable:").append("\n")
+ .append(routingTable.dumpRoutingTableCache());
+
+ return stringBuilder.toString();
+ }
+
+
+
+ private BundleContext getBundleContext() {
+ ClassLoader tlcl = Thread.currentThread().getContextClassLoader();
+ Bundle bundle = null;
+
+ if (tlcl instanceof BundleReference) {
+ bundle = ((BundleReference) tlcl).getBundle();
+ } else {
+ _logger.info("Unable to determine the bundle context based on " +
+ "thread context classloader.");
+ bundle = FrameworkUtil.getBundle(this.getClass());
+ }
+ return (bundle == null ? null : bundle.getBundleContext());
+ }
+
+
+
+}
--- /dev/null
+<?xml version="1.0" encoding="ISO-8859-1"?>
+<web-app xmlns="http://java.sun.com/xml/ns/javaee" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+ xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd"
+ version="3.0">
+ <servlet>
+ <servlet-name>JAXRSZmqRT</servlet-name>
+ <servlet-class>com.sun.jersey.spi.container.servlet.ServletContainer</servlet-class>
+ <init-param>
+ <param-name>javax.ws.rs.Application</param-name>
+ <param-value>org.opendaylight.controller.northbound.commons.NorthboundApplication</param-value>
+ </init-param>
+ <load-on-startup>1</load-on-startup>
+ </servlet>
+
+ <servlet-mapping>
+ <servlet-name>JAXRSZmqRT</servlet-name>
+ <url-pattern>/*</url-pattern>
+ </servlet-mapping>
+
+
+
+ <security-constraint>
+ <web-resource-collection>
+ <web-resource-name>NB api</web-resource-name>
+ <url-pattern>/*</url-pattern>
+ <http-method>POST</http-method>
+ <http-method>GET</http-method>
+ <http-method>PUT</http-method>
+ <http-method>PATCH</http-method>
+ <http-method>DELETE</http-method>
+ <http-method>HEAD</http-method>
+ </web-resource-collection>
+ <auth-constraint>
+ <role-name>System-Admin</role-name>
+ <role-name>Network-Admin</role-name>
+ <role-name>Network-Operator</role-name>
+ <role-name>Container-User</role-name>
+ </auth-constraint>
+ </security-constraint>
+
+ <security-role>
+ <role-name>System-Admin</role-name>
+ </security-role>
+ <security-role>
+ <role-name>Network-Admin</role-name>
+ </security-role>
+ <security-role>
+ <role-name>Network-Operator</role-name>
+ </security-role>
+ <security-role>
+ <role-name>Container-User</role-name>
+ </security-role>
+
+ <login-config>
+ <auth-method>BASIC</auth-method>
+ <realm-name>opendaylight</realm-name>
+ </login-config>
+</web-app>
--- /dev/null
+package org.opendaylight.controller.sal.binding.api;
+
+public interface RpcAvailabilityListener {
+
+}
<artifactId>ietf-inet-types</artifactId>
<version>2010.09.24.2-SNAPSHOT</version>
</dependency>
+ <dependency>
+ <groupId>org.opendaylight.yangtools.model</groupId>
+ <artifactId>ietf-topology-l3-unicast-igp</artifactId>
+ <version>2013.10.21.0-SNAPSHOT</version>
+ <scope>test</scope>
+ </dependency>
<dependency>
<groupId>org.opendaylight.controller.model</groupId>
<artifactId>model-flow-base</artifactId>
\r
@Override\r
public java.lang.AutoCloseable createInstance() {\r
- BindingAwareBrokerImpl broker = new BindingAwareBrokerImpl(getBundleContext());\r
+ BindingAwareBrokerImpl broker = new BindingAwareBrokerImpl(getIdentifier().getInstanceName(),getBundleContext());\r
broker.setDataBroker(getDataBrokerDependency());\r
broker.setNotifyBroker(getNotificationServiceDependency());\r
broker.start();\r
import org.opendaylight.controller.config.yang.md.sal.binding.statistics.DataBrokerRuntimeMXBeanImpl;\r
import org.opendaylight.controller.md.sal.common.impl.routing.AbstractDataReadRouter;\r
import org.opendaylight.controller.sal.binding.impl.DataBrokerImpl;\r
-import org.opendaylight.controller.sal.binding.impl.connect.dom.BindingIndependentDataServiceConnector;\r
+import org.opendaylight.controller.sal.binding.impl.connect.dom.BindingIndependentConnector;\r
import org.opendaylight.controller.sal.binding.impl.connect.dom.BindingIndependentMappingService;\r
import org.opendaylight.controller.sal.core.api.Broker;\r
import org.opendaylight.controller.sal.core.api.data.DataProviderService;\r
BindingIndependentMappingService mappingService = getMappingServiceDependency();\r
\r
if (domBroker != null && mappingService != null) {\r
- BindingIndependentDataServiceConnector runtimeMapping = new BindingIndependentDataServiceConnector();\r
+ BindingIndependentConnector runtimeMapping = new BindingIndependentConnector();\r
runtimeMapping.setMappingService(mappingService);\r
runtimeMapping.setBaDataService(dataBindingBroker);\r
domBroker.registerProvider(runtimeMapping, getBundleContext());\r
import javassist.ClassPool;
+import org.opendaylight.controller.sal.binding.codegen.impl.SingletonHolder;
import org.opendaylight.controller.sal.binding.dom.serializer.impl.RuntimeGeneratedMappingServiceImpl;
import org.osgi.framework.BundleContext;
@Override
public java.lang.AutoCloseable createInstance() {
RuntimeGeneratedMappingServiceImpl service = new RuntimeGeneratedMappingServiceImpl();
- ClassPool pool = new ClassPool(); // Should be default singleton
- service.setPool(pool);
+ service.setPool(SingletonHolder.CLASS_POOL);
service.start(getBundleContext());
return service;
}
* @return Instance of RpcService of provided serviceType which implements
* also {@link RpcRouter}<T> and {@link DelegateProxy}
*/
- <T extends RpcService> RpcRouter<T> getRouterFor(Class<T> serviceType) throws IllegalArgumentException;
+ <T extends RpcService> RpcRouter<T> getRouterFor(Class<T> serviceType,String name) throws IllegalArgumentException;
NotificationInvokerFactory getInvokerFactory();
}
if (field == null) throw new UnsupportedOperationException(
"Unable to set routing table. Table field does not exists");
field.set(target,routingTable);
-
}
}
--- /dev/null
+package org.opendaylight.controller.sal.binding.codegen.impl;
+
+import org.opendaylight.yangtools.yang.binding.RpcService;
+import org.opendaylight.controller.sal.binding.api.BindingAwareBroker.RoutedRpcRegistration;
+import org.opendaylight.controller.sal.binding.api.BindingAwareBroker.RpcRegistration;
+import org.opendaylight.controller.sal.binding.spi.RpcRouter;
+import org.opendaylight.yangtools.yang.binding.BaseIdentity;
+import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
+
+import static org.opendaylight.controller.sal.binding.codegen.RuntimeCodeHelper.*;
+
+import java.util.Map;
+import java.util.Set;
+import java.util.HashMap;
+
+import org.opendaylight.controller.sal.binding.spi.RpcRoutingTable;
+import org.opendaylight.yangtools.yang.binding.DataContainer;
+import org.opendaylight.yangtools.yang.binding.RpcImplementation;
+import org.opendaylight.controller.md.sal.common.api.routing.MutableRoutingTable;
+import org.opendaylight.controller.md.sal.common.api.routing.RouteChange;
+import org.opendaylight.controller.md.sal.common.api.routing.RouteChangeListener;
+import org.opendaylight.yangtools.concepts.AbstractObjectRegistration;
+import org.opendaylight.yangtools.concepts.ListenerRegistration;
+import org.opendaylight.yangtools.concepts.util.ListenerRegistry;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import com.google.common.collect.ImmutableMap;
+import com.google.common.collect.ImmutableSet;
+
+public class RpcRouterCodegenInstance<T extends RpcService> implements //
+ RpcRouter<T>, RouteChangeListener<Class<? extends BaseIdentity>, InstanceIdentifier<?>> {
+
+ private static final Logger LOG = LoggerFactory.getLogger(RpcRouterCodegenInstance.class);
+
+ private T defaultService;
+
+ private final Class<T> serviceType;
+
+ private final T invocationProxy;
+
+ private final Set<Class<? extends BaseIdentity>> contexts;
+
+ private final ListenerRegistry<RouteChangeListener<Class<? extends BaseIdentity>, InstanceIdentifier<?>>> listeners;
+
+ private final Map<Class<? extends BaseIdentity>, RpcRoutingTableImpl<? extends BaseIdentity, T>> routingTables;
+
+ private final String name;
+
+ @SuppressWarnings("unchecked")
+ public RpcRouterCodegenInstance(String name,Class<T> type, T routerImpl, Set<Class<? extends BaseIdentity>> contexts,
+ Set<Class<? extends DataContainer>> inputs) {
+ this.name = name;
+ this.listeners = ListenerRegistry.create();
+ this.serviceType = type;
+ this.invocationProxy = routerImpl;
+ this.contexts = ImmutableSet.copyOf(contexts);
+ Map<Class<? extends BaseIdentity>, RpcRoutingTableImpl<? extends BaseIdentity, T>> mutableRoutingTables = new HashMap<>();
+ for (Class<? extends BaseIdentity> ctx : contexts) {
+ RpcRoutingTableImpl<? extends BaseIdentity, T> table = new RpcRoutingTableImpl<>(name,ctx,type);
+
+ @SuppressWarnings("rawtypes")
+ Map invokerView = table.getRoutes();
+
+ setRoutingTable((RpcService) invocationProxy, ctx, invokerView);
+ mutableRoutingTables.put(ctx, table);
+ table.registerRouteChangeListener(this);
+ }
+ this.routingTables = ImmutableMap.copyOf(mutableRoutingTables);
+ }
+
+ @Override
+ public Class<T> getServiceType() {
+ return serviceType;
+ }
+
+ @Override
+ public T getInvocationProxy() {
+ return invocationProxy;
+ }
+
+ @Override
+ @SuppressWarnings("unchecked")
+ public <C extends BaseIdentity> RpcRoutingTable<C, T> getRoutingTable(Class<C> routeContext) {
+ return (RpcRoutingTable<C, T>) routingTables.get(routeContext);
+ }
+
+ @Override
+ public T getDefaultService() {
+ return defaultService;
+ }
+
+ @Override
+ public Set<Class<? extends BaseIdentity>> getContexts() {
+ return contexts;
+ }
+
+ @Override
+ public <L extends RouteChangeListener<Class<? extends BaseIdentity>, InstanceIdentifier<?>>> ListenerRegistration<L> registerRouteChangeListener(
+ L listener) {
+ return listeners.registerWithType(listener);
+ }
+
+ @Override
+ public void onRouteChange(RouteChange<Class<? extends BaseIdentity>, InstanceIdentifier<?>> change) {
+ for (ListenerRegistration<RouteChangeListener<Class<? extends BaseIdentity>, InstanceIdentifier<?>>> listener : listeners) {
+ try {
+ listener.getInstance().onRouteChange(change);
+ } catch (Exception e) {
+ LOG.error("Error occured during invoker listener {}", listener.getInstance(), e);
+ }
+ }
+ }
+
+ @Override
+ public T getService(Class<? extends BaseIdentity> context, InstanceIdentifier<?> path) {
+ return routingTables.get(context).getRoute(path);
+ }
+
+ @Override
+ public RoutedRpcRegistration<T> addRoutedRpcImplementation(T service) {
+ return new RoutedRpcRegistrationImpl(service);
+ }
+
+ @Override
+ public RpcRegistration<T> registerDefaultService(T service) {
+ // TODO Auto-generated method stub
+ return null;
+ }
+
+ private class RoutedRpcRegistrationImpl extends AbstractObjectRegistration<T> implements RoutedRpcRegistration<T> {
+
+ public RoutedRpcRegistrationImpl(T instance) {
+ super(instance);
+ }
+
+ @Override
+ public Class<T> getServiceType() {
+ return serviceType;
+ }
+
+ @Override
+ public void registerPath(Class<? extends BaseIdentity> context, InstanceIdentifier<?> path) {
+ routingTables.get(context).updateRoute(path, getInstance());
+ }
+
+ @Override
+ public void unregisterPath(Class<? extends BaseIdentity> context, InstanceIdentifier<?> path) {
+ routingTables.get(context).removeRoute(path, getInstance());
+
+ }
+
+ @Override
+ public void registerInstance(Class<? extends BaseIdentity> context, InstanceIdentifier<?> instance) {
+ registerPath(context, instance);
+ }
+
+ @Override
+ public void unregisterInstance(Class<? extends BaseIdentity> context, InstanceIdentifier<?> instance) {
+ unregisterPath(context, instance);
+ }
+
+ @Override
+ protected void removeRegistration() {
+
+ }
+ }
+}
+++ /dev/null
-package org.opendaylight.controller.sal.binding.codegen.impl
-
-import org.opendaylight.yangtools.yang.binding.RpcService
-import org.opendaylight.controller.sal.binding.spi.RpcRouter
-import org.opendaylight.yangtools.yang.binding.BaseIdentity
-import org.opendaylight.yangtools.yang.binding.InstanceIdentifier
-import static extension org.opendaylight.controller.sal.binding.codegen.RuntimeCodeHelper.*
-import java.util.Set
-import java.util.HashMap
-import org.opendaylight.controller.sal.binding.spi.RpcRoutingTable
-import org.opendaylight.yangtools.yang.binding.DataContainer
-import org.opendaylight.yangtools.yang.binding.RpcImplementation
-
-class RpcRouterCodegenInstance<T extends RpcService> implements RpcRouter<T> {
-
- @Property
- val T invocationProxy
-
- @Property
- val RpcImplementation invokerDelegate;
-
- @Property
- val Class<T> serviceType
-
- @Property
- val Set<Class<? extends BaseIdentity>> contexts
-
- @Property
- val Set<Class<? extends DataContainer>> supportedInputs;
-
- val routingTables = new HashMap<Class<? extends BaseIdentity>, RpcRoutingTableImpl<? extends BaseIdentity, ? extends RpcService>>;
-
- @Property
- var T defaultService
-
- new(Class<T> type, T routerImpl, Set<Class<? extends BaseIdentity>> contexts,
- Set<Class<? extends DataContainer>> inputs) {
- _serviceType = type
- _invocationProxy = routerImpl
- _invokerDelegate = routerImpl as RpcImplementation
- _contexts = contexts
- _supportedInputs = inputs;
-
- for (ctx : contexts) {
- val table = XtendHelper.createRoutingTable(ctx)
- invocationProxy.setRoutingTable(ctx, table.routes);
- routingTables.put(ctx, table);
- }
- }
-
- override <C extends BaseIdentity> getRoutingTable(Class<C> table) {
- routingTables.get(table) as RpcRoutingTable<C,T>
- }
-
- override getService(Class<? extends BaseIdentity> context, InstanceIdentifier<?> path) {
- val table = getRoutingTable(context);
- return table.getRoute(path);
- }
-
- override <T extends DataContainer> invoke(Class<T> type, T input) {
- return invokerDelegate.invoke(type, input);
- }
-
-}
--- /dev/null
+package org.opendaylight.controller.sal.binding.codegen.impl;
+
+import org.opendaylight.controller.sal.binding.spi.RpcRoutingTable;
+import org.opendaylight.yangtools.yang.binding.BaseIdentity;
+import org.opendaylight.yangtools.yang.binding.RpcService;
+import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
+
+import java.util.Collections;
+import java.util.Map;
+import java.util.concurrent.ConcurrentHashMap;
+import java.util.concurrent.ConcurrentMap;
+
+import org.opendaylight.yangtools.yang.binding.DataObject;
+import org.opendaylight.controller.md.sal.common.api.routing.RouteChangePublisher;
+import org.opendaylight.controller.md.sal.common.api.routing.RouteChangeListener;
+import org.opendaylight.controller.md.sal.common.impl.routing.RoutingUtils;
+import org.opendaylight.yangtools.concepts.AbstractObjectRegistration;
+import org.opendaylight.yangtools.concepts.Identifiable;
+import org.opendaylight.yangtools.concepts.ListenerRegistration;
+import org.opendaylight.yangtools.concepts.Mutable;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+class RpcRoutingTableImpl<C extends BaseIdentity, S extends RpcService> //
+implements //
+ Mutable, //
+ RpcRoutingTable<C, S>, //
+ RouteChangePublisher<Class<? extends BaseIdentity>, InstanceIdentifier<?>> {
+
+ private static final Logger LOGGER = LoggerFactory.getLogger(RpcRoutingTableImpl.class);
+ private final String routerName;
+ private final Class<S> serviceType;
+
+ private final Class<C> contextType;
+ private final ConcurrentMap<InstanceIdentifier<?>, S> routes;
+ private final Map<InstanceIdentifier<?>, S> unmodifiableRoutes;
+
+ private RouteChangeListener<Class<? extends BaseIdentity>, InstanceIdentifier<?>> listener;
+ private S defaultRoute;
+
+ public RpcRoutingTableImpl(String routerName,Class<C> contextType, Class<S> serviceType) {
+ super();
+ this.routerName = routerName;
+ this.serviceType = serviceType;
+ this.contextType = contextType;
+ this.routes = new ConcurrentHashMap<>();
+ this.unmodifiableRoutes = Collections.unmodifiableMap(routes);
+ }
+
+ @Override
+ public void setDefaultRoute(S target) {
+ defaultRoute = target;
+ }
+
+ @Override
+ public S getDefaultRoute() {
+ return defaultRoute;
+ }
+
+ @Override
+ public <L extends RouteChangeListener<Class<? extends BaseIdentity>, InstanceIdentifier<?>>> ListenerRegistration<L> registerRouteChangeListener(
+ L listener) {
+ return (ListenerRegistration<L>) new SingletonListenerRegistration<L>(listener);
+ }
+
+ @Override
+ public Class<C> getIdentifier() {
+ return contextType;
+ }
+
+ @Override
+ @SuppressWarnings("unchecked")
+ public void updateRoute(InstanceIdentifier<?> path, S service) {
+ S previous = this.routes.put(path, service);
+
+ LOGGER.debug("Route {} updated to {} in routing table {}",path,service,this);
+ @SuppressWarnings("rawtypes")
+ RouteChangeListener listenerCapture = listener;
+ if (previous == null && listenerCapture != null) {
+ listenerCapture.onRouteChange(RoutingUtils.announcementChange(contextType, path));
+ }
+ }
+
+
+ @Override
+ @SuppressWarnings("unchecked")
+ public void removeRoute(InstanceIdentifier<?> path) {
+ S previous = this.routes.remove(path);
+ LOGGER.debug("Route {} to {} removed in routing table {}",path,previous,this);
+ @SuppressWarnings("rawtypes")
+ RouteChangeListener listenerCapture = listener;
+ if (previous != null && listenerCapture != null) {
+ listenerCapture.onRouteChange(RoutingUtils.removalChange(contextType, path));
+ }
+ }
+
+ public void removeRoute(InstanceIdentifier<?> path, S service) {
+ @SuppressWarnings("rawtypes")
+ RouteChangeListener listenerCapture = listener;
+ if (routes.remove(path, service) && listenerCapture != null) {
+ LOGGER.debug("Route {} to {} removed in routing table {}",path,service,this);
+ listenerCapture.onRouteChange(RoutingUtils.removalChange(contextType, path));
+ }
+ }
+
+ @Override
+ public S getRoute(InstanceIdentifier<?> nodeInstance) {
+ S route = routes.get(nodeInstance);
+ if (route != null) {
+ return route;
+ }
+ return getDefaultRoute();
+ }
+
+ @Override
+ public Map<InstanceIdentifier<?>, S> getRoutes() {
+ return unmodifiableRoutes;
+ }
+
+ protected void removeAllReferences(S service) {
+
+ }
+
+
+
+ @Override
+ public String toString() {
+ return "RpcRoutingTableImpl [router=" + routerName + ", service=" + serviceType.getSimpleName() + ", context="
+ + contextType.getSimpleName() + "]";
+ }
+
+
+
+ private class SingletonListenerRegistration<L extends RouteChangeListener<Class<? extends BaseIdentity>, InstanceIdentifier<?>>> extends
+ AbstractObjectRegistration<L>
+ implements ListenerRegistration<L> {
+
+ public SingletonListenerRegistration(L instance) {
+ super(instance);
+ listener = instance;
+ }
+
+ @Override
+ protected void removeRegistration() {
+ listener = null;
+ }
+ }
+}
\ No newline at end of file
+++ /dev/null
-package org.opendaylight.controller.sal.binding.codegen.impl
-
-import org.opendaylight.controller.sal.binding.spi.RpcRoutingTable
-import org.opendaylight.yangtools.yang.binding.BaseIdentity
-import org.opendaylight.yangtools.yang.binding.RpcService
-import org.opendaylight.yangtools.yang.binding.InstanceIdentifier
-import java.util.Map
-import org.opendaylight.yangtools.yang.binding.DataObject
-import java.util.HashMap
-
-class RpcRoutingTableImpl<C extends BaseIdentity,S extends RpcService> implements RpcRoutingTable<C,S>{
-
- @Property
- val Class<C> identifier;
-
- @Property
- var S defaultRoute;
-
- @Property
- val Map<InstanceIdentifier<? extends DataObject>,S> routes;
-
- new(Class<C> ident, Map<InstanceIdentifier<? extends DataObject>,S> route) {
- _identifier = ident
- _routes = route
- }
-
- new(Class<C> ident) {
- _identifier = ident
- _routes = new HashMap
- }
-
-
- override getRoute(InstanceIdentifier<? extends Object> nodeInstance) {
- val ret = routes.get(nodeInstance);
- if(ret !== null) {
- return ret;
- }
- return defaultRoute;
- }
-
- override removeRoute(InstanceIdentifier<? extends Object> path) {
- routes.remove(path);
- }
-
- @SuppressWarnings("rawtypes")
- override updateRoute(InstanceIdentifier<? extends Object> path, S service) {
- routes.put(path as InstanceIdentifier<? extends DataObject>,service);
- }
-}
\ No newline at end of file
import static extension org.opendaylight.controller.sal.binding.codegen.YangtoolsMappingHelper.*
import static extension org.opendaylight.controller.sal.binding.codegen.RuntimeCodeSpecification.*
import java.util.HashSet
-import static org.opendaylight.controller.sal.binding.impl.util.ClassLoaderUtils.*
+import static org.opendaylight.yangtools.concepts.util.ClassLoaderUtils.*
import org.opendaylight.controller.sal.binding.spi.NotificationInvokerFactory
import org.opendaylight.controller.sal.binding.spi.NotificationInvokerFactory.NotificationInvoker
import java.util.Set
import org.opendaylight.yangtools.yang.binding.DataContainer
import org.opendaylight.yangtools.yang.binding.RpcImplementation
import org.opendaylight.controller.sal.binding.codegen.util.JavassistUtils
+import org.opendaylight.controller.sal.binding.impl.util.ClassLoaderUtils
+import javassist.LoaderClassPath
class RuntimeCodeGenerator implements org.opendaylight.controller.sal.binding.codegen.RuntimeCodeGenerator, NotificationInvokerFactory {
val extension JavassistUtils utils;
val Map<Class<? extends NotificationListener>, RuntimeGeneratedInvokerPrototype> invokerClasses;
- public new(ClassPool pool) {
+
+ new(ClassPool pool) {
classPool = pool;
utils = new JavassistUtils(pool);
invokerClasses = new WeakHashMap();
BROKER_NOTIFICATION_LISTENER = org.opendaylight.controller.sal.binding.api.NotificationListener.asCtClass;
+ pool.appendClassPath(new LoaderClassPath(RpcService.classLoader));
}
override <T extends RpcService> getDirectProxyFor(Class<T> iface) {
- val supertype = iface.asCtClass
- val targetCls = createClass(iface.directProxyName, supertype) [
- field(DELEGATE_FIELD, iface);
- implementMethodsFrom(supertype) [
- body = '''
- {
- if(«DELEGATE_FIELD» == null) {
+ val T instance = withClassLoaderAndLock(iface.classLoader,lock) [|
+ val proxyName = iface.directProxyName;
+ val potentialClass = ClassLoaderUtils.tryToLoadClassWithTCCL(proxyName)
+ if(potentialClass != null) {
+ return potentialClass.newInstance as T;
+ }
+ val supertype = iface.asCtClass
+ val createdCls = createClass(iface.directProxyName, supertype) [
+ field(DELEGATE_FIELD, iface);
+ implementsType(RpcImplementation.asCtClass)
+ implementMethodsFrom(supertype) [
+ body = '''
+ {
+ if(«DELEGATE_FIELD» == null) {
+ throw new java.lang.IllegalStateException("No default provider is available");
+ }
+ return ($r) «DELEGATE_FIELD».«it.name»($$);
+ }
+ '''
+ ]
+ implementMethodsFrom(RpcImplementation.asCtClass) [
+ body = '''
+ {
throw new java.lang.IllegalStateException("No provider is processing supplied message");
+ return ($r) null;
}
- return ($r) «DELEGATE_FIELD».«it.name»($$);
- }
- '''
+ '''
+ ]
]
+ return createdCls.toClass(iface.classLoader).newInstance as T
]
- return targetCls.toClass(iface.classLoader).newInstance as T
+ return instance;
}
- override <T extends RpcService> getRouterFor(Class<T> iface) {
- val instance = <RpcRouterCodegenInstance<T>>withClassLoaderAndLock(iface.classLoader,lock) [ |
+ override <T extends RpcService> getRouterFor(Class<T> iface,String routerInstanceName) {
+ val metadata = withClassLoader(iface.classLoader) [|
+ val supertype = iface.asCtClass
+ return supertype.rpcMetadata;
+ ]
+
+ val instance = <T>withClassLoaderAndLock(iface.classLoader,lock) [ |
val supertype = iface.asCtClass
- val metadata = supertype.rpcMetadata;
+ val routerName = iface.routerName;
+ val potentialClass = ClassLoaderUtils.tryToLoadClassWithTCCL(routerName)
+ if(potentialClass != null) {
+ return potentialClass.newInstance as T;
+ }
+
val targetCls = createClass(iface.routerName, supertype) [
- addInterface(RpcImplementation.asCtClass)
+
field(DELEGATE_FIELD, iface)
//field(REMOTE_INVOKER_FIELD,iface);
+ implementsType(RpcImplementation.asCtClass)
for (ctx : metadata.contexts) {
field(ctx.routingTableField, Map)
instance = «DELEGATE_FIELD»;
}
if(instance == null) {
- throw new java.lang.IllegalStateException("No provider is processing supplied message");
+ throw new java.lang.IllegalStateException("No routable provider is processing routed message for " + String.valueOf(identifier));
}
return ($r) instance.«it.name»($$);
}'''
}
]
implementMethodsFrom(RpcImplementation.asCtClass) [
- switch (name) {
- case "getSupportedInputs":
- body = '''
- {
- throw new java.lang.UnsupportedOperationException("Not implemented yet");
- return ($r) null;
- }'''
- case "invoke": {
- val tmpBody = '''
- {
- «FOR input : metadata.supportedInputs SEPARATOR " else "»
- «val rpcMetadata = metadata.rpcInputs.get(input)»
- if(«input.name».class.equals($1)) {
- return ($r) this.«rpcMetadata.methodName»((«input.name») $2);
- }
- «ENDFOR»
- throw new java.lang.IllegalArgumentException("Not supported message type");
- return ($r) null;
- }
- '''
- body = tmpBody
- }
+ body = '''
+ {
+ throw new java.lang.IllegalStateException("No provider is processing supplied message");
+ return ($r) null;
}
+ '''
]
]
- val instance = targetCls.toClass(iface.classLoader,iface.protectionDomain).newInstance as T
- return new RpcRouterCodegenInstance(iface, instance, metadata.contexts,metadata.supportedInputs);
+ return targetCls.toClass(iface.classLoader,iface.protectionDomain).newInstance as T
+
];
- return instance;
+ return new RpcRouterCodegenInstance(routerInstanceName,iface, instance, metadata.contexts,metadata.supportedInputs);
}
private def RpcServiceMetadata getRpcMetadata(CtClass iface) {
--- /dev/null
+package org.opendaylight.controller.sal.binding.codegen.impl;
+
+import org.opendaylight.controller.sal.binding.codegen.RuntimeCodeGenerator;
+import org.opendaylight.controller.sal.binding.spi.NotificationInvokerFactory;
+
+import javassist.ClassPool;
+
+public class SingletonHolder {
+
+ public static final ClassPool CLASS_POOL = new ClassPool();
+ public static final org.opendaylight.controller.sal.binding.codegen.impl.RuntimeCodeGenerator RPC_GENERATOR_IMPL = new org.opendaylight.controller.sal.binding.codegen.impl.RuntimeCodeGenerator(CLASS_POOL);
+ public static final RuntimeCodeGenerator RPC_GENERATOR = RPC_GENERATOR_IMPL;
+ public static final NotificationInvokerFactory INVOKER_FACTORY = RPC_GENERATOR_IMPL.getInvokerFactory();
+}
package org.opendaylight.controller.sal.binding.codegen.impl;
+import java.util.List;
+
import org.opendaylight.yangtools.yang.binding.BaseIdentity;
import org.opendaylight.yangtools.yang.binding.RpcService;
+import org.opendaylight.yangtools.yang.model.api.TypeDefinition;
+import org.opendaylight.yangtools.yang.model.api.type.UnionTypeDefinition;
public class XtendHelper {
- public static <C extends BaseIdentity> RpcRoutingTableImpl createRoutingTable(
- Class<C> cls) {
- return new RpcRoutingTableImpl<>(cls);
+ @SuppressWarnings({"rawtypes","unchecked"})
+ public static Iterable<TypeDefinition> getTypes(UnionTypeDefinition definition) {
+ return (Iterable<TypeDefinition>) (List) definition.getTypes();
}
}
import javassist.ClassClassPath
import java.util.concurrent.locks.Lock
import java.util.concurrent.locks.ReentrantLock
+import org.slf4j.LoggerFactory
+import java.util.HashMap
+import java.util.WeakHashMap
class JavassistUtils {
+ private static val LOG = LoggerFactory.getLogger(JavassistUtils);
+
+ private val loaderClassPaths = new WeakHashMap<ClassLoader,LoaderClassPath>();
+
ClassPool classPool
@Property
try {
return pool.get(cls.name)
} catch (NotFoundException e) {
- pool.appendClassPath(new LoaderClassPath(cls.classLoader));
+ appendClassLoaderIfMissing(cls.classLoader)
try {
return pool.get(cls.name)
-
} catch (NotFoundException ef) {
+ LOG.warn("Appending ClassClassPath for {}",cls);
pool.appendClassPath(new ClassClassPath(cls));
+
return pool.get(cls.name)
}
}
}
+
+ def void appendClassLoaderIfMissing(ClassLoader loader) {
+ if(loaderClassPaths.containsKey(loader)) {
+ return;
+ }
+ val ctLoader = new LoaderClassPath(loader);
+ classPool.appendClassPath(ctLoader);
+ }
+
+ def void ensureClassLoader(Class<?> child) {
+ appendClassLoaderIfMissing(child.classLoader);
+ }
}
});
return ret;
} catch (Exception e) {
- LOG.error("Could not find augmentable for {}", augmentation, e);
+ LOG.debug("Could not find augmentable for {} using {}", augmentation, augmentation.getClassLoader(), e);
return null;
}
}
if (typeToClass.containsKey(typeRef)) {
return;
}
- LOG.info("Binding Class {} encountered.", cls);
+ LOG.trace("Binding Class {} encountered.", cls);
WeakReference<Class> weakRef = new WeakReference<>(cls);
typeToClass.put(typeRef, weakRef);
if (Augmentation.class.isAssignableFrom(cls)) {
if (typeToClass.containsKey(typeRef)) {
return;
}
- LOG.info("Binding Class {} encountered.", cls);
+ LOG.trace("Binding Class {} encountered.", cls);
WeakReference<Class> weakRef = new WeakReference<>((Class) cls);
typeToClass.put(typeRef, weakRef);
}
public void onModuleContextAdded(SchemaContext schemaContext, Module module, ModuleContext context) {
pathToType.putAll(context.getChildNodes());
qnamesToIdentityMap.putAll(context.getIdentities());
- for(Entry<QName, GeneratedTOBuilder> identity : context.getIdentities().entrySet()) {
- typeToQname.put(new ReferencedTypeImpl(identity.getValue().getPackageName(), identity.getValue().getName()),identity.getKey());
+ for (Entry<QName, GeneratedTOBuilder> identity : context.getIdentities().entrySet()) {
+ typeToQname.put(
+ new ReferencedTypeImpl(identity.getValue().getPackageName(), identity.getValue().getName()),
+ identity.getKey());
}
captureCases(context.getCases(), schemaContext);
}
@Override
public Class<?> deserialize(QName input) {
Type type = qnamesToIdentityMap.get(input);
- if(type == null) {
+ if (type == null) {
return null;
}
ReferencedTypeImpl typeref = new ReferencedTypeImpl(type.getPackageName(), type.getName());
WeakReference<Class> softref = typeToClass.get(typeref);
- if(softref == null) {
+ if (softref == null) {
return null;
}
return softref.get();
checkArgument(BaseIdentity.class.isAssignableFrom(input));
bindingClassEncountered(input);
QName qname = identityQNames.get(input);
- if(qname != null) {
+ if (qname != null) {
return qname;
}
ConcreteType typeref = Types.typeForClass(input);
qname = typeToQname.get(typeref);
- if(qname != null) {
+ if (qname != null) {
identityQNames.put(input, qname);
}
return qname;
return serialize((Class) input);
}
}
+
+ public boolean isCodecAvailable(Class<? extends DataContainer> cls) {
+ if (containerCodecs.containsKey(cls)) {
+ return true;
+ }
+ if (identifierCodecs.containsKey(cls)) {
+ return true;
+ }
+ if (choiceCodecs.containsKey(cls)) {
+ return true;
+ }
+ if (caseCodecs.containsKey(cls)) {
+ return true;
+ }
+ if (augmentableCodecs.containsKey(cls)) {
+ return true;
+ }
+ if (augmentationCodecs.containsKey(cls)) {
+ return true;
+ }
+ return false;
+ }
}
\ No newline at end of file
import org.opendaylight.yangtools.yang.data.api.Node
import org.opendaylight.yangtools.yang.data.impl.SimpleNodeTOImpl
import org.opendaylight.yangtools.yang.data.impl.CompositeNodeTOImpl
+import org.opendaylight.yangtools.yang.binding.RpcService
+import java.util.Set
+import org.opendaylight.yangtools.yang.common.QName
+import com.google.common.collect.FluentIterable
+import org.opendaylight.yangtools.binding.generator.util.BindingGeneratorUtil
class RuntimeGeneratedMappingServiceImpl implements BindingIndependentMappingService, SchemaServiceListener, AutoCloseable {
@Property
val ConcurrentMap<Type, SchemaNode> typeToSchemaNode = new ConcurrentHashMap();
+
+ @Property
+ val ConcurrentMap<Type,Set<QName>> serviceTypeToRpc = new ConcurrentHashMap();
val promisedTypeDefinitions = HashMultimap.<Type, SettableFuture<GeneratedTypeBuilder>>create;
registry.onModuleContextAdded(schemaContext, entry.key, entry.value);
binding.pathToType.putAll(entry.value.childNodes)
- //val module = entry.key;
+ val module = entry.key;
val context = entry.value;
updateBindingFor(context.childNodes, schemaContext);
updateBindingFor(context.cases, schemaContext);
+ val namespace = BindingGeneratorUtil.moduleNamespaceToPackageName(module);
+
+ if(!module.rpcs.empty) {
+ val rpcs = FluentIterable.from(module.rpcs).transform[QName].toSet
+ val serviceClass = new ReferencedTypeImpl(namespace,BindingGeneratorUtil.parseToClassName(module.name)+"Service");
+ serviceTypeToRpc.put(serviceClass,rpcs);
+ }
val typedefs = context.typedefs;
for (typedef : typedefs.entrySet) {
*/
return;
}
-
+ if(registry.isCodecAvailable(class1)) {
+ return;
+ }
val ref = Types.typeForClass(class1);
getSchemaWithRetry(ref);
}
}
override dataObjectFromDataDom(InstanceIdentifier<? extends DataObject> path, CompositeNode node) {
- return tryDeserialization[ |
- if (node == null) {
- return null;
- }
- val targetType = path.targetType
- val transformer = registry.getCodecForDataObject(targetType);
- val ret = transformer.deserialize(node)?.value as DataObject;
- return ret;
- ]
+ dataObjectFromDataDom(path.targetType,node) as DataObject;
}
override fromDataDom(org.opendaylight.yangtools.yang.data.api.InstanceIdentifier entry) {
listenerRegistration = ctx.registerService(SchemaServiceListener, this, new Hashtable<String, String>());
}
}
-
- private def getTypeDefinition(Type type) {
- val typeDef = typeToDefinition.get(type);
- if (typeDef !== null) {
- return typeDef;
- }
- return type.getTypeDefInFuture.get();
- }
-
- private def Future<GeneratedTypeBuilder> getTypeDefInFuture(Type type) {
- val future = SettableFuture.<GeneratedTypeBuilder>create()
- promisedTypeDefinitions.put(type, future);
- return future;
- }
-
- private def void updatePromisedTypeDefinitions(GeneratedTypeBuilder builder) {
- val futures = promisedTypeDefinitions.get(builder);
- if (futures === null || futures.empty) {
- return;
- }
- for (future : futures) {
- future.set(builder);
- }
- promisedTypeDefinitions.removeAll(builder);
+
+ override getRpcQNamesFor(Class<? extends RpcService> service) {
+ return serviceTypeToRpc.get(new ReferencedTypeImpl(service.package.name,service.simpleName));
}
private def getSchemaWithRetry(Type type) {
override close() throws Exception {
listenerRegistration?.unregister();
}
+
+ override dataObjectFromDataDom(Class<? extends DataContainer> container, CompositeNode domData) {
+ return tryDeserialization[ |
+ if (domData == null) {
+ return null;
+ }
+ val transformer = registry.getCodecForDataObject(container);
+ val ret = transformer.deserialize(domData)?.value as DataObject;
+ return ret;
+ ]
+ }
}
import org.opendaylight.yangtools.yang.model.util.EnumerationType
import static com.google.common.base.Preconditions.*
import org.opendaylight.yangtools.yang.model.api.SchemaPath
+import javassist.CtMethod
+import javassist.CannotCompileException
+import java.util.concurrent.locks.Lock
+import java.util.concurrent.Callable
+import org.opendaylight.controller.sal.binding.impl.util.ClassLoaderUtils
+import org.opendaylight.yangtools.yang.model.api.TypeDefinition
+import org.opendaylight.yangtools.yang.model.api.type.UnionTypeDefinition
+import org.opendaylight.yangtools.yang.model.api.type.BitsTypeDefinition
+import java.util.HashSet
+import java.util.Collections
+import org.opendaylight.yangtools.yang.model.api.type.BitsTypeDefinition.Bit
+import java.util.Set
+import org.opendaylight.controller.sal.binding.codegen.impl.XtendHelper
class TransformerGenerator {
@Property
var GeneratorListener listener;
-
+
public static val CLASS_TYPE = Types.typeForClass(Class);
public new(ClassPool pool) {
if (typeSpecBuilder == null) {
typeSpecBuilder = pathToType.get(node.path);
}
+ var schemaNode = typeToSchemaNode.get(ref);
+ if(schemaNode === null) {
+ schemaNode = node;
+ }
checkState(typeSpecBuilder !== null, "Could not find TypeDefinition for %s, $s", inputType.name, node);
val typeSpec = typeSpecBuilder.toInstance();
- val newret = generateTransformerFor(inputType, typeSpec, node);
+ val newret = generateTransformerFor(inputType, typeSpec, schemaNode);
listener.onClassProcessed(inputType);
return newret as Class<? extends BindingCodec<Map<QName,Object>, Object>>;
]
transformerFor(cls, node);
}
- private def Class<?> getValueSerializer(GeneratedTransferObject type) {
+ private def Class<?> valueSerializer(GeneratedTransferObject type, TypeDefinition<?> typeDefinition) {
val cls = loadClassWithTCCL(type.resolvedName);
val transformer = cls.generatedClass;
if (transformer !== null) {
return transformer;
}
+ var baseType = typeDefinition;
+ while (baseType.baseType != null) {
+ baseType = baseType.baseType;
+ }
+ val finalType = baseType;
return withClassLoaderAndLock(cls.classLoader, lock) [ |
- val valueTransformer = generateValueTransformer(cls, type);
+ val valueTransformer = generateValueTransformer(cls, type, finalType);
return valueTransformer;
]
}
- private def Class<?> getValueSerializer(Enumeration type) {
+ private def Class<?> valueSerializer(Enumeration type, TypeDefinition<?> typeDefinition) {
val cls = loadClassWithTCCL(type.resolvedName);
val transformer = cls.generatedClass;
if (transformer !== null) {
implementsType(BINDING_CODEC)
method(Object, "toDomStatic", QName, Object) [
modifiers = PUBLIC + FINAL + STATIC
- body = '''
+ bodyChecked = '''
{
«QName.name» _resultName;
if($1 != null) {
]
method(Object, "fromDomStatic", QName, Object) [
modifiers = PUBLIC + FINAL + STATIC
- body = '''
+ bodyChecked = '''
{
if($2 == null){
return null;
'''
]
method(Object, "serialize", Object) [
- body = '''
+ bodyChecked = '''
{
java.util.Map.Entry _input = (java.util.Map.Entry) $1;
«QName.name» _localQName = («QName.name») _input.getKey();
'''
]
method(Object, "deserialize", Object) [
- body = '''
+ bodyChecked = '''
return fromDomStatic(QNAME,$1);
'''
]
]
val ret = ctCls.toClassImpl(inputType.classLoader, inputType.protectionDomain)
- log.info("DOM Codec for {} was generated {}", inputType, ret)
+ log.debug("DOM Codec for {} was generated {}", inputType, ret)
return ret as Class<? extends BindingCodec<Map<QName,Object>, ?>>;
} catch (Exception e) {
processException(inputType, e);
staticField(it, IDENTITYREF_CODEC, BindingCodec)
method(Object, "toDomStatic", QName, Object) [
modifiers = PUBLIC + FINAL + STATIC
- body = '''
+ bodyChecked = '''
{
«QName.name» _resultName = «QName.name».create($1,QNAME.getLocalName());
java.util.List _childNodes = new java.util.ArrayList();
'''
]
method(Object, "serialize", Object) [
- body = '''
+ bodyChecked = '''
{
java.util.Map.Entry _input = (java.util.Map.Entry) $1;
«QName.name» _localName = QNAME;
]
method(Object, "fromDomStatic", QName, Object) [
modifiers = PUBLIC + FINAL + STATIC
- body = deserializeBody(type, node)
+ bodyChecked = deserializeBody(type, node)
]
method(Object, "deserialize", Object) [
- body = '''
+ bodyChecked = '''
{
- //System.out.println("«type.name»#deserialize: " +$1);
+ ////System.out.println("«type.name»#deserialize: " +$1);
java.util.Map.Entry _input = (java.util.Map.Entry) $1;
return fromDomStatic((«QName.name»)_input.getKey(),_input.getValue());
}
val ret = ctCls.toClassImpl(inputType.classLoader, inputType.protectionDomain) as Class<? extends BindingCodec<Object, Object>>
listener?.onDataContainerCodecCreated(inputType, ret);
- log.info("DOM Codec for {} was generated {}", inputType, ret)
+ log.debug("DOM Codec for {} was generated {}", inputType, ret)
return ret;
} catch (Exception e) {
processException(inputType, e);
implementsType(BINDING_CODEC)
method(Object, "toDomStatic", QName, Object) [
modifiers = PUBLIC + FINAL + STATIC
- body = serializeBodyFacade(typeSpec, node)
+ bodyChecked = serializeBodyFacade(typeSpec, node)
]
method(Object, "serialize", Object) [
- body = '''
+ bodyChecked = '''
{
java.util.Map.Entry _input = (java.util.Map.Entry) $1;
«QName.name» _localName = QNAME;
]
method(Object, "fromDomStatic", QName, Object) [
modifiers = PUBLIC + FINAL + STATIC
- body = deserializeBody(typeSpec, node)
+ bodyChecked = deserializeBody(typeSpec, node)
]
method(Object, "deserialize", Object) [
- body = '''
+ bodyChecked = '''
return fromDomStatic(QNAME,$1);
'''
]
val ret = ctCls.toClassImpl(inputType.classLoader, inputType.protectionDomain) as Class<? extends BindingCodec<Map<QName,Object>, Object>>
listener?.onDataContainerCodecCreated(inputType, ret);
- log.info("DOM Codec for {} was generated {}", inputType, ret)
+ log.debug("DOM Codec for {} was generated {}", inputType, ret)
return ret;
} catch (Exception e) {
processException(inputType, e);
implementsType(BINDING_CODEC)
method(Object, "toDomStatic", QName, Object) [
modifiers = PUBLIC + FINAL + STATIC
- body = '''
+ bodyChecked = '''
{
- //System.out.println("Qname " + $1);
- //System.out.println("Value " + $2);
+ ////System.out.println("Qname " + $1);
+ ////System.out.println("Value " + $2);
«QName.name» _resultName = «QName.name».create(QNAME,QNAME.getLocalName());
java.util.List _childNodes = new java.util.ArrayList();
«type.resolvedName» value = («type.resolvedName») $2;
«FOR child : node.childNodes»
«var signature = properties.getFor(child)»
- //System.out.println("«signature.key»" + value.«signature.key»());
+ ////System.out.println("«signature.key»" + value.«signature.key»());
«serializeProperty(child, signature.value, signature.key)»
«ENDFOR»
return ($r) _childNodes;
'''
]
method(Object, "serialize", Object) [
- body = '''
+ bodyChecked = '''
{
java.util.Map.Entry _input = (java.util.Map.Entry) $1;
«QName.name» _localName = QNAME;
]
method(Object, "fromDomStatic", QName, Object) [
modifiers = PUBLIC + FINAL + STATIC
- body = '''
+ bodyChecked = '''
{
«QName.name» _localQName = QNAME;
return null;
}
java.util.Map _compositeNode = (java.util.Map) $2;
- //System.out.println(_localQName + " " + _compositeNode);
+ System.out.println(_localQName + " " + _compositeNode);
«type.builderName» _builder = new «type.builderName»();
boolean _is_empty = true;
«FOR child : node.childNodes»
'''
]
method(Object, "deserialize", Object) [
- body = '''
+ bodyChecked = '''
return fromDomStatic(QNAME,$1);
'''
]
implementsType(BINDING_CODEC)
method(List, "toDomStatic", QName, Object) [
modifiers = PUBLIC + FINAL + STATIC
- body = '''
+ bodyChecked = '''
{
if($2 == null) {
return null;
}
java.util.Map.Entry _input = new «SimpleEntry.name»($1,_baValue);
Object _ret = _codec.serialize(_input);
- //System.out.println("«typeSpec.name»#toDomStatic: " + _ret);
+ ////System.out.println("«typeSpec.name»#toDomStatic: " + _ret);
return («List.name») _ret;
}
'''
]
method(Object, "serialize", Object) [
- body = '''
+ bodyChecked = '''
throw new «UnsupportedOperationException.name»("Direct invocation not supported.");
'''
]
method(Object, "fromDomStatic", QName, Map) [
modifiers = PUBLIC + FINAL + STATIC
- body = '''
+ bodyChecked = '''
{
«BINDING_CODEC.name» _codec = («BINDING_CODEC.name») «COMPOSITE_TO_CASE».get($2);
if(_codec != null) {
'''
]
method(Object, "deserialize", Object) [
- body = '''
+ bodyChecked = '''
throw new «UnsupportedOperationException.name»("Direct invocation not supported.");
'''
]
val rawRet = ctCls.toClassImpl(inputType.classLoader, inputType.protectionDomain)
val ret = rawRet as Class<? extends BindingCodec<Map<QName,Object>, Object>>;
listener?.onChoiceCodecCreated(inputType, ret, node);
- log.info("DOM Codec for {} was generated {}", inputType, ret)
+ log.debug("DOM Codec for {} was generated {}", inputType, ret)
return ret;
} catch (Exception e) {
processException(inputType, e);
return null;
}
java.util.Map _compositeNode = (java.util.Map) $2;
+ System.out.println(_localQName + " " + _compositeNode);
«type.builderName» _builder = new «type.builderName»();
«deserializeKey(type, node)»
«deserializeDataNodeContainerBody(type, node)»
return null;
}
java.util.Map _compositeNode = (java.util.Map) $2;
+ System.out.println(_localQName + " " + _compositeNode);
«type.builderName» _builder = new «type.builderName»();
«deserializeDataNodeContainerBody(type, node)»
«deserializeAugmentations»
return null;
}
java.util.Map _compositeNode = (java.util.Map) $2;
- //System.out.println(_localQName + " " + _compositeNode);
+ System.out.println(_localQName + " " + _compositeNode);
«type.builderName» _builder = new «type.builderName»();
«deserializeDataNodeContainerBody(type, node)»
«deserializeAugmentations»
«Iterator.name» _entries = _augmentation.entrySet().iterator();
while(_entries.hasNext()) {
java.util.Map.Entry _entry = (java.util.Map.Entry) _entries.next();
- //System.out.println("Aug. key:" + _entry.getKey());
+ ////System.out.println("Aug. key:" + _entry.getKey());
Class _type = (Class) _entry.getKey();
«Augmentation.resolvedName» _value = («Augmentation.name») _entry.getValue();
if(_value != null) {
String propertyName) '''
java.util.List _dom_«propertyName» = _compositeNode.get(«QName.name».create(_localQName,"«schema.QName.
localName»"));
- //System.out.println("«propertyName»#deCode"+_dom_«propertyName»);
+ ////System.out.println("«propertyName»#deCode"+_dom_«propertyName»);
java.util.List «propertyName» = new java.util.ArrayList();
if(_dom_«propertyName» != null) {
java.util.List _serialized = new java.util.ArrayList();
while(_hasNext) {
Object _listItem = _iterator.next();
_is_empty = false;
- //System.out.println(" item" + _listItem);
+ ////System.out.println(" item" + _listItem);
Object _value = «type.actualTypeArguments.get(0).serializer(schema).resolvedName».fromDomStatic(_localQName,_listItem);
- //System.out.println(" value" + _value);
+ ////System.out.println(" value" + _value);
«propertyName».add(_value);
_hasNext = _iterator.hasNext();
}
}
- //System.out.println(" list" + «propertyName»);
+ ////System.out.println(" list" + «propertyName»);
'''
private def dispatch CharSequence deserializeProperty(LeafListSchemaNode schema, ParameterizedType type,
Object _listItem = _iterator.next();
if(_listItem instanceof java.util.Map.Entry) {
Object _innerValue = ((java.util.Map.Entry) _listItem).getValue();
- Object _value = «deserializeValue(type.actualTypeArguments.get(0), "_innerValue")»;
+ Object _value = «deserializeValue(type.actualTypeArguments.get(0), "_innerValue", schema.type)»;
«propertyName».add(_value);
}
_hasNext = _iterator.hasNext();
_is_empty = false;
java.util.Map.Entry _dom_«propertyName» = (java.util.Map.Entry) _dom_«propertyName»_list.get(0);
Object _inner_value = _dom_«propertyName».getValue();
- «propertyName» = «deserializeValue(type, "_inner_value")»;
+ «propertyName» = «deserializeValue(type, "_inner_value", schema.type)»;
}
'''
}
'''
- private def dispatch String deserializeValue(GeneratedTransferObject type, String domParameter) '''
- («type.resolvedName») «type.valueSerializer.resolvedName».fromDomValue(«domParameter»)
+ private def dispatch String deserializeValue(GeneratedTransferObject type, String domParameter,
+ TypeDefinition<?> typeDefinition) '''
+ («type.resolvedName») «type.valueSerializer(typeDefinition).resolvedName».fromDomValue(«domParameter»)
'''
- private def dispatch String deserializeValue(Enumeration type, String domParameter) '''
- («type.resolvedName») «type.valueSerializer.resolvedName».fromDomValue(«domParameter»)
+ private def dispatch String deserializeValue(Enumeration type, String domParameter, TypeDefinition<?> typeDefinition) '''
+ («type.resolvedName») «type.valueSerializer(typeDefinition).resolvedName».fromDomValue(«domParameter»)
'''
private def dispatch Class<? extends BindingCodec<Map<QName, Object>, Object>> generateValueTransformer(
- Class<?> inputType, GeneratedTransferObject typeSpec) {
+ Class<?> inputType, GeneratedTransferObject typeSpec, TypeDefinition<?> typeDef) {
try {
val returnType = typeSpec.valueReturnType;
val ret = ctCls.toClassImpl(inputType.classLoader, inputType.protectionDomain)
return ret as Class<? extends BindingCodec<Map<QName,Object>, Object>>;
}
- var hasBinding = false;
- try {
- val bindingCodecClass = loadClassWithTCCL(BINDING_CODEC.name);
- hasBinding = bindingCodecClass !== null;
- } catch (ClassNotFoundException e) {
- hasBinding = false;
- }
- val hasYangBinding = hasBinding
+
val ctCls = createClass(typeSpec.codecClassName) [
//staticField(Map,"AUGMENTATION_SERIALIZERS");
- if (hasYangBinding) {
+ if (inputType.isYangBindingAvailable) {
implementsType(BINDING_CODEC)
staticField(it, INSTANCE_IDENTIFIER_CODEC, BindingCodec)
staticField(it, IDENTITYREF_CODEC, BindingCodec)
}
method(Object, "toDomValue", Object) [
modifiers = PUBLIC + FINAL + STATIC
- body = '''
+ val ctSpec = typeSpec.asCtClass;
+ bodyChecked = '''
{
- //System.out.println("«inputType.simpleName»#toDomValue: "+$1);
+ ////System.out.println("«inputType.simpleName»#toDomValue: "+$1);
if($1 == null) {
return null;
}
«typeSpec.resolvedName» _encapsulatedValue = («typeSpec.resolvedName») $1;
- //System.out.println("«inputType.simpleName»#toDomValue:Enc: "+_encapsulatedValue);
+ ////System.out.println("«inputType.simpleName»#toDomValue:Enc: "+_encapsulatedValue);
«returnType.resolvedName» _value = _encapsulatedValue.getValue();
- //System.out.println("«inputType.simpleName»#toDomValue:DeEnc: "+_value);
- Object _domValue = «serializeValue(returnType, "_value")»;
+ ////System.out.println("«inputType.simpleName»#toDomValue:DeEnc: "+_value);
+ Object _domValue = «serializeValue(returnType, "_value", null)»;
return _domValue;
}
'''
]
method(Object, "serialize", Object) [
- body = '''
+ bodyChecked = '''
{
return toDomValue($1);
}
]
method(Object, "fromDomValue", Object) [
modifiers = PUBLIC + FINAL + STATIC
- body = '''
+ bodyChecked = '''
{
- //System.out.println("«inputType.simpleName»#fromDomValue: "+$1);
+ ////System.out.println("«inputType.simpleName»#fromDomValue: "+$1);
if($1 == null) {
return null;
}
- «returnType.resolvedName» _simpleValue = «deserializeValue(returnType, "$1")»;
+ «returnType.resolvedName» _simpleValue = «deserializeValue(returnType, "$1", null)»;
«typeSpec.resolvedName» _value = new «typeSpec.resolvedName»(_simpleValue);
return _value;
}
'''
]
method(Object, "deserialize", Object) [
- body = '''{
+ bodyChecked = '''{
return fromDomValue($1);
}
'''
]
val ret = ctCls.toClassImpl(inputType.classLoader, inputType.protectionDomain)
- log.info("DOM Codec for {} was generated {}", inputType, ret)
+ log.debug("DOM Codec for {} was generated {}", inputType, ret)
return ret as Class<? extends BindingCodec<Map<QName,Object>, Object>>;
} catch (Exception e) {
log.error("Cannot compile DOM Codec for {}", inputType, e);
exception.addSuppressed(e);
throw exception;
}
+ }
+ private def dispatch Class<? extends BindingCodec<Map<QName, Object>, Object>> generateValueTransformer(
+ Class<?> inputType, GeneratedTransferObject typeSpec, UnionTypeDefinition typeDef) {
+ try {
+ val ctCls = createClass(typeSpec.codecClassName) [
+ val properties = typeSpec.allProperties;
+ val getterToTypeDefinition = XtendHelper.getTypes(typeDef).toMap[type | type.QName.getterName];
+ //staticField(Map,"AUGMENTATION_SERIALIZERS");
+ if (inputType.isYangBindingAvailable) {
+ implementsType(BINDING_CODEC)
+ staticField(it, INSTANCE_IDENTIFIER_CODEC, BindingCodec)
+ staticField(it, IDENTITYREF_CODEC, BindingCodec)
+ implementsType(BindingDeserializer.asCtClass)
+ }
+ method(Object, "toDomValue", Object) [
+ modifiers = PUBLIC + FINAL + STATIC
+ val ctSpec = inputType.asCtClass;
+
+ bodyChecked = '''
+ {
+ ////System.out.println("«inputType.simpleName»#toDomValue: "+$1);
+
+ if($1 == null) {
+ return null;
+ }
+ «typeSpec.resolvedName» _value = («typeSpec.resolvedName») $1;
+ «FOR property : properties.entrySet»
+ «IF property.key != "getValue"»
+ «property.value.resolvedName» «property.key» = («property.value.resolvedName») _value.«property.
+ key»();
+ if(«property.key» != null) {
+ return «serializeValue(property.value, property.key, getterToTypeDefinition.get(property.key))»;
+ }
+ «ENDIF»
+ «ENDFOR»
+
+ return null;
+ }
+ '''
+ ]
+ method(Object, "serialize", Object) [
+ bodyChecked = '''
+ {
+ return toDomValue($1);
+ }
+ '''
+ ]
+ method(Object, "fromDomValue", Object) [
+ modifiers = PUBLIC + FINAL + STATIC
+ bodyChecked = '''
+ {
+ ////System.out.println("«inputType.simpleName»#fromDomValue: "+$1);
+
+ if($1 == null) {
+ return null;
+ }
+ if($1 instanceof String) {
+ String _simpleValue = (String) $1;
+ return new «typeSpec.resolvedName»(_simpleValue.toCharArray());
+ }
+ return null;
+ }
+ '''
+ ]
+ method(Object, "deserialize", Object) [
+ bodyChecked = '''{
+ return fromDomValue($1);
+ }
+ '''
+ ]
+ ]
+
+ val ret = ctCls.toClassImpl(inputType.classLoader, inputType.protectionDomain)
+ log.debug("DOM Codec for {} was generated {}", inputType, ret)
+ return ret as Class<? extends BindingCodec<Map<QName,Object>, Object>>;
+ } catch (Exception e) {
+ log.error("Cannot compile DOM Codec for {}", inputType, e);
+ val exception = new CodeGenerationException("Cannot compile Transformator for " + inputType);
+ exception.addSuppressed(e);
+ throw exception;
+ }
+ }
+
+
+ private def dispatch Class<? extends BindingCodec<Map<QName, Object>, Object>> generateValueTransformer(
+ Class<?> inputType, GeneratedTransferObject typeSpec, BitsTypeDefinition typeDef) {
+ try {
+ val ctCls = createClass(typeSpec.codecClassName) [
+ //staticField(Map,"AUGMENTATION_SERIALIZERS");
+ if (inputType.isYangBindingAvailable) {
+ implementsType(BINDING_CODEC)
+ staticField(it, INSTANCE_IDENTIFIER_CODEC, BindingCodec)
+ staticField(it, IDENTITYREF_CODEC, BindingCodec)
+ implementsType(BindingDeserializer.asCtClass)
+ }
+ method(Object, "toDomValue", Object) [
+ modifiers = PUBLIC + FINAL + STATIC
+ val ctSpec = typeSpec.asCtClass;
+ bodyChecked = '''
+ {
+ ////System.out.println("«inputType.simpleName»#toDomValue: "+$1);
+
+ if($1 == null) {
+ return null;
+ }
+ «typeSpec.resolvedName» _encapsulatedValue = («typeSpec.resolvedName») $1;
+ «HashSet.resolvedName» _value = new «HashSet.resolvedName»();
+ //System.out.println("«inputType.simpleName»#toDomValue:Enc: "+_encapsulatedValue);
+
+ «FOR bit : typeDef.bits»
+ «val getter = bit.getterName()»
+ if(Boolean.TRUE.equals(_encapsulatedValue.«getter»())) {
+ _value.add("«bit.name»");
+ }
+ «ENDFOR»
+ «Set.resolvedName» _domValue = «Collections.resolvedName».unmodifiableSet(_value);
+ //System.out.println("«inputType.simpleName»#toDomValue:DeEnc: "+_domValue);
+
+ return _domValue;
+ }
+ '''
+ ]
+ method(Object, "serialize", Object) [
+ bodyChecked = '''
+ {
+ return toDomValue($1);
+ }
+ '''
+ ]
+ method(Object, "fromDomValue", Object) [
+ modifiers = PUBLIC + FINAL + STATIC
+ val sortedBits = typeDef.bits.sort[o1, o2|o1.propertyName.compareTo(o2.propertyName)]
+ bodyChecked = '''
+ {
+ //System.out.println("«inputType.simpleName»#fromDomValue: "+$1);
+
+ if($1 == null) {
+ return null;
+ }
+ «Set.resolvedName» _domValue = («Set.resolvedName») $1;
+ «FOR bit : sortedBits»
+ Boolean «bit.propertyName» = Boolean.valueOf(_domValue.contains("«bit.name»"));
+ «ENDFOR»
+
+ return new «inputType.resolvedName»(«FOR bit : sortedBits SEPARATOR ","»«bit.propertyName»«ENDFOR»);
+ }
+ '''
+ ]
+ method(Object, "deserialize", Object) [
+ bodyChecked = '''{
+ return fromDomValue($1);
+ }
+ '''
+ ]
+ ]
+
+ val ret = ctCls.toClassImpl(inputType.classLoader, inputType.protectionDomain)
+ log.debug("DOM Codec for {} was generated {}", inputType, ret)
+ return ret as Class<? extends BindingCodec<Map<QName,Object>, Object>>;
+ } catch (Exception e) {
+ log.error("Cannot compile DOM Codec for {}", inputType, e);
+ val exception = new CodeGenerationException("Cannot compile Transformator for " + inputType);
+ exception.addSuppressed(e);
+ throw exception;
+ }
+ }
+
+ def String getPropertyName(Bit bit) {
+ '''_«BindingGeneratorUtil.parseToValidParamName(bit.name)»'''
+ }
+
+ def String getterName(Bit bit) {
+
+ val paramName = BindingGeneratorUtil.parseToValidParamName(bit.name);
+ return '''is«paramName.toFirstUpper»''';
+ }
+
+ def boolean isYangBindingAvailable(Class<?> class1) {
+ try {
+ val bindingCodecClass = class1.classLoader.loadClass(BINDING_CODEC.name);
+ return bindingCodecClass !== null;
+ } catch (ClassNotFoundException e) {
+ return false;
+ }
}
private def createDummyImplementation(Class<?> object, GeneratedTransferObject typeSpec) {
log.info("Generating Dummy DOM Codec for {} with {}", object, object.classLoader)
return createClass(typeSpec.codecClassName) [
- //staticField(Map,"AUGMENTATION_SERIALIZERS");
- implementsType(BINDING_CODEC)
- implementsType(BindingDeserializer.asCtClass)
+ if (object.isYangBindingAvailable) {
+ implementsType(BINDING_CODEC)
+ staticField(it, INSTANCE_IDENTIFIER_CODEC, BindingCodec)
+ staticField(it, IDENTITYREF_CODEC, BindingCodec)
+ implementsType(BindingDeserializer.asCtClass)
+ }
+ //implementsType(BindingDeserializer.asCtClass)
method(Object, "toDomValue", Object) [
modifiers = PUBLIC + FINAL + STATIC
- body = '''return null;'''
+ bodyChecked = '''{
+ if($1 == null) {
+ return null;
+ }
+ return $1.toString();
+
+ }'''
]
method(Object, "serialize", Object) [
- body = '''
+ bodyChecked = '''
{
return toDomValue($1);
}
]
method(Object, "fromDomValue", Object) [
modifiers = PUBLIC + FINAL + STATIC
- body = '''return null;'''
+ bodyChecked = '''return null;'''
]
method(Object, "deserialize", Object) [
- body = '''{
+ bodyChecked = '''{
return fromDomValue($1);
}
'''
return null;
}
- private def dispatch Class<?> generateValueTransformer(Class<?> inputType, Enumeration typeSpec) {
+ private def Class<?> generateValueTransformer(Class<?> inputType, Enumeration typeSpec) {
try {
val typeRef = new ReferencedTypeImpl(typeSpec.packageName, typeSpec.name);
val schema = typeToSchemaNode.get(typeRef) as ExtendedType;
//implementsType(BINDING_CODEC)
method(Object, "toDomValue", Object) [
modifiers = PUBLIC + FINAL + STATIC
- body = '''{
+ bodyChecked = '''{
if($1 == null) {
return null;
}
'''
]
method(Object, "serialize", Object) [
- body = '''
+ bodyChecked = '''
return toDomValue($1);
'''
]
method(Object, "fromDomValue", Object) [
modifiers = PUBLIC + FINAL + STATIC
- body = '''
+ bodyChecked = '''
{
if($1 == null) {
return null;
'''
]
method(Object, "deserialize", Object) [
- body = '''
+ bodyChecked = '''
return fromDomValue($1);
'''
]
]
val ret = ctCls.toClassImpl(inputType.classLoader, inputType.protectionDomain)
- log.info("DOM Codec for {} was generated {}", inputType, ret)
+ log.debug("DOM Codec for {} was generated {}", inputType, ret)
return ret;
} catch (CodeGenerationException e) {
throw new CodeGenerationException("Cannot compile Transformator for " + inputType, e);
}
- private def dispatch String deserializeValue(Type type, String domParameter) {
+ private def dispatch String deserializeValue(Type type, String domParameter, TypeDefinition<?> typeDef) {
if (INSTANCE_IDENTIFIER.equals(type)) {
return '''(«InstanceIdentifier.name») «INSTANCE_IDENTIFIER_CODEC».deserialize(«domParameter»)'''
} else if (CLASS_TYPE.equals(type)) {
«FOR child : node.childNodes»
«val signature = properties.getFor(child)»
«IF signature !== null»
- //System.out.println("«type.name»#«signature.key»" + value.«signature.key»());
+ ////System.out.println("«type.name»#«signature.key»" + value.«signature.key»());
«serializeProperty(child, signature.value, signature.key)»
«ENDIF»
«ENDFOR»
private def dispatch CharSequence serializeProperty(ListSchemaNode schema, ParameterizedType type,
String propertyName) '''
«type.resolvedName» «propertyName» = value.«propertyName»();
- //System.out.println("«propertyName»:" + «propertyName»);
+ ////System.out.println("«propertyName»:" + «propertyName»);
if(«propertyName» != null) {
java.util.Iterator _iterator = «propertyName».iterator();
boolean _hasNext = _iterator.hasNext();
if(«propertyName» != null) {
«QName.name» _qname = «QName.name».create(_resultName,"«schema.QName.localName»");
- Object _propValue = «serializeValue(type, propertyName)»;
+ Object _propValue = «serializeValue(type, propertyName, schema.type)»;
if(_propValue != null) {
Object _domValue = java.util.Collections.singletonMap(_qname,_propValue);
_childNodes.add(_domValue);
}
'''
- private def dispatch serializeValue(GeneratedTransferObject type, String parameter) '''«type.valueSerializer.
- resolvedName».toDomValue(«parameter»)'''
+ private def dispatch serializeValue(GeneratedTransferObject type, String parameter, TypeDefinition<?> typeDefinition) {
+ '''«type.valueSerializer(typeDefinition).resolvedName».toDomValue(«parameter»)'''
+ }
- private def dispatch serializeValue(Enumeration type, String parameter) '''«type.valueSerializer.resolvedName».toDomValue(«parameter»)'''
+ private def dispatch serializeValue(Enumeration type, String parameter, TypeDefinition<?> typeDefinition) {
+ '''«type.valueSerializer(typeDefinition).resolvedName».toDomValue(«parameter»)'''
+ }
- private def dispatch serializeValue(Type signature, String property) {
+ private def dispatch serializeValue(Type signature, String property, TypeDefinition<?> typeDefinition) {
if (INSTANCE_IDENTIFIER == signature) {
return '''«INSTANCE_IDENTIFIER_CODEC».serialize(«property»)'''
- }else if (CLASS_TYPE.equals(signature)) {
+ } else if (CLASS_TYPE.equals(signature)) {
return '''(«QName.resolvedName») «IDENTITYREF_CODEC».serialize(«property»)'''
}
+ if ("char[]" == signature.name) {
+ return '''new String(«property»)''';
+ }
return '''«property»''';
}
boolean _hasNext = _iterator.hasNext();
while(_hasNext) {
Object _listItem = _iterator.next();
- Object _propValue = «serializeValue(type.actualTypeArguments.get(0), "_listItem")»;
+ Object _propValue = «serializeValue(type.actualTypeArguments.get(0), "_listItem", schema.type)»;
Object _domValue = java.util.Collections.singletonMap(_qname,_propValue);
_childNodes.add(_domValue);
_hasNext = _iterator.hasNext();
throw exception;
}
+ private def setBodyChecked(CtMethod method, String body) {
+ try {
+ method.setBody(body);
+ } catch (CannotCompileException e) {
+ log.error("Cannot compile method: {}#{} {}, Reason: {} Body: {}", method.declaringClass, method.name,
+ method.signature, e.message, body)
+ throw e;
+ }
+ }
+
+ private def <V> V withClassLoaderAndLock(ClassLoader cls, Lock lock, Callable<V> function) throws Exception {
+ appendClassLoaderIfMissing(cls);
+ ClassLoaderUtils.withClassLoaderAndLock(cls, lock, function);
+ }
+
}
@Data
import org.opendaylight.controller.sal.binding.api.BindingAwareConsumer
import org.opendaylight.controller.sal.binding.api.BindingAwareProvider
-import org.opendaylight.yangtools.yang.binding.RpcService
-import javassist.ClassPool
import org.osgi.framework.BundleContext
-import java.util.Map
-import java.util.HashMap
-import javassist.LoaderClassPath
import org.opendaylight.controller.sal.binding.api.BindingAwareBroker
-import java.util.Hashtable
-import static extension org.opendaylight.controller.sal.binding.codegen.RuntimeCodeHelper.*
-
import org.opendaylight.controller.sal.binding.api.NotificationProviderService
-import org.osgi.framework.ServiceRegistration
-import static org.opendaylight.controller.sal.binding.impl.osgi.Constants.*
-import static extension org.opendaylight.controller.sal.binding.impl.osgi.PropertiesUtils.*
-import org.opendaylight.controller.sal.binding.api.NotificationService
import org.opendaylight.controller.sal.binding.api.BindingAwareBroker.ProviderContext
-
-import org.slf4j.LoggerFactory
-import org.opendaylight.controller.sal.binding.codegen.impl.RuntimeCodeGenerator
import org.opendaylight.yangtools.yang.binding.InstanceIdentifier
-import org.opendaylight.controller.sal.binding.api.BindingAwareBroker.RoutedRpcRegistration
-import org.opendaylight.controller.sal.binding.api.BindingAwareBroker.RpcRegistration
-import org.opendaylight.controller.sal.binding.api.data.DataProviderService
-import org.opendaylight.controller.sal.binding.api.data.DataBrokerService
-import org.opendaylight.controller.sal.binding.spi.RpcRouter
-import java.util.concurrent.ConcurrentHashMap
-import static com.google.common.base.Preconditions.*
-import org.opendaylight.yangtools.concepts.AbstractObjectRegistration
-import org.opendaylight.yangtools.yang.binding.BaseIdentity
-import com.google.common.collect.Multimap
-import com.google.common.collect.HashMultimap
-import static org.opendaylight.controller.sal.binding.impl.util.ClassLoaderUtils.*
-import java.util.concurrent.Executors
-import java.util.Collections
import org.opendaylight.yangtools.yang.binding.DataObject
-import java.util.concurrent.locks.ReentrantLock
-import java.util.concurrent.Callable
-import java.util.WeakHashMap
-import javax.annotation.concurrent.GuardedBy
-import org.opendaylight.controller.sal.binding.api.RpcProviderRegistry
+import org.opendaylight.controller.md.sal.common.api.routing.RouteChangeListener
+import org.opendaylight.controller.sal.binding.spi.RpcContextIdentifier
+import org.opendaylight.controller.sal.binding.api.data.DataProviderService
+import org.slf4j.LoggerFactory
-class BindingAwareBrokerImpl implements BindingAwareBroker, RpcProviderRegistry, AutoCloseable {
+class BindingAwareBrokerImpl extends RpcProviderRegistryImpl implements BindingAwareBroker, AutoCloseable {
private static val log = LoggerFactory.getLogger(BindingAwareBrokerImpl)
private InstanceIdentifier<? extends DataObject> root = InstanceIdentifier.builder().toInstance();
- private static val clsPool = ClassPool.getDefault()
- public static var RuntimeCodeGenerator generator;
-
- /**
- * Map of all Managed Direct Proxies
- *
- */
- private val Map<Class<? extends RpcService>, RpcProxyContext> managedProxies = new ConcurrentHashMap();
-
- /**
- *
- * Map of all available Rpc Routers
- *
- *
- */
- private val Map<Class<? extends RpcService>, RpcRouter<? extends RpcService>> rpcRouters = new WeakHashMap();
-
@Property
private var NotificationProviderService notifyBroker
@Property
var BundleContext brokerBundleContext
- ServiceRegistration<NotificationProviderService> notifyProviderRegistration
-
- ServiceRegistration<NotificationService> notifyConsumerRegistration
-
- ServiceRegistration<DataProviderService> dataProviderRegistration
-
- ServiceRegistration<DataBrokerService> dataConsumerRegistration
-
- private val proxyGenerationLock = new ReentrantLock;
-
- private val routerGenerationLock = new ReentrantLock;
-
- public new(BundleContext bundleContext) {
+ public new(String name,BundleContext bundleContext) {
+ super(name);
_brokerBundleContext = bundleContext;
}
def start() {
log.info("Starting MD-SAL: Binding Aware Broker");
- initGenerator();
-
- val executor = Executors.newCachedThreadPool;
-
- // Initialization of notificationBroker
- log.info("Starting MD-SAL: Binding Aware Notification Broker");
-
- log.info("Starting MD-SAL: Binding Aware Data Broker");
-
- log.info("Starting MD-SAL: Binding Aware Data Broker");
- log.info("MD-SAL: Binding Aware Broker Started");
}
- def initGenerator() {
- // YANG Binding Class Loader
- clsPool.appendClassPath(new LoaderClassPath(RpcService.classLoader));
- generator = new RuntimeCodeGenerator(clsPool);
- }
override registerConsumer(BindingAwareConsumer consumer, BundleContext bundleCtx) {
val ctx = consumer.createContext(bundleCtx)
new OsgiProviderContext(providerCtx, this)
}
- /**
- * Returns a Managed Direct Proxy for supplied class
- *
- * Managed direct proxy is a generated proxy class conforming to the supplied interface
- * which delegates all calls to the backing delegate.
- *
- * Proxy does not do any validation, null pointer checks or modifies data in any way, it
- * is only use to avoid exposing direct references to backing implementation of service.
- *
- * If proxy class does not exist for supplied service class it will be generated automatically.
- */
- private def <T extends RpcService> getManagedDirectProxy(Class<T> service) {
- var RpcProxyContext existing = null
-
- if ((existing = managedProxies.get(service)) != null) {
- return existing.proxy
- }
- return withLock(proxyGenerationLock) [ |
- val maybeProxy = managedProxies.get(service);
- if (maybeProxy !== null) {
- return maybeProxy.proxy;
- }
-
-
- val proxyInstance = generator.getDirectProxyFor(service)
- val rpcProxyCtx = new RpcProxyContext(proxyInstance.class)
- val properties = new Hashtable<String, String>()
- rpcProxyCtx.proxy = proxyInstance as RpcService
- properties.salServiceType = SAL_SERVICE_TYPE_CONSUMER_PROXY
- rpcProxyCtx.registration = brokerBundleContext.registerService(service, rpcProxyCtx.proxy as T, properties)
- managedProxies.put(service, rpcProxyCtx)
- return rpcProxyCtx.proxy
- ]
- }
-
- private static def <T> T withLock(ReentrantLock lock, Callable<T> method) {
- try {
- lock.lock();
- val ret = method.call;
- return ret;
- } finally {
- lock.unlock();
- }
- }
-
- /**
- * Registers RPC Implementation
- *
- */
- override <T extends RpcService> addRpcImplementation(Class<T> type, T service) {
- checkNotNull(type, "Service type should not be null")
- checkNotNull(service, "Service type should not be null")
-
- val proxy = getManagedDirectProxy(type)
- checkState(proxy.delegate === null, "The Service for type %s is already registered", type)
-
- proxy.delegate = service;
- return new RpcServiceRegistrationImpl<T>(type, service, this);
- }
-
- override <T extends RpcService> RoutedRpcRegistration<T> addRoutedRpcImplementation(Class<T> type, T service) {
- checkNotNull(type, "Service type should not be null")
- checkNotNull(service, "Service type should not be null")
-
- val router = resolveRpcRouter(type);
- checkState(router !== null)
- return new RoutedRpcRegistrationImpl<T>(service, router, this)
+ override <L extends RouteChangeListener<RpcContextIdentifier, InstanceIdentifier<?>>> registerRouteChangeListener(L listener) {
+ super.<L>registerRouteChangeListener(listener)
}
- override <T extends RpcService> getRpcService(Class<T> service) {
- checkNotNull(service, "Service should not be null");
- return getManagedDirectProxy(service) as T;
- }
-
- private def <T extends RpcService> RpcRouter<T> resolveRpcRouter(Class<T> type) {
-
- val router = rpcRouters.get(type);
- if (router !== null) {
- return router as RpcRouter<T>;
- }
-
- // We created Router
- return withLock(routerGenerationLock) [ |
- val maybeRouter = rpcRouters.get(type);
- if (maybeRouter !== null) {
- return maybeRouter as RpcRouter<T>;
- }
-
- val newRouter = generator.getRouterFor(type);
- checkState(newRouter !== null);
- rpcRouters.put(type, newRouter);
- // We create / update Direct Proxy for router
- val proxy = getManagedDirectProxy(type);
- proxy.delegate = newRouter.invocationProxy
- return newRouter;
- ]
-
- }
-
- protected def <T extends RpcService> void registerPath(RoutedRpcRegistrationImpl<T> registration,
- Class<? extends BaseIdentity> context, InstanceIdentifier<? extends Object> path) {
-
- val router = registration.router;
- val paths = registration.registeredPaths;
-
- val routingTable = router.getRoutingTable(context)
- checkState(routingTable != null);
-
- // Updating internal structure of registration
- routingTable.updateRoute(path, registration.instance)
-
- // Update routing table / send announce to message bus
- val success = paths.put(context, path);
- }
-
- protected def <T extends RpcService> void unregisterPath(RoutedRpcRegistrationImpl<T> registration,
- Class<? extends BaseIdentity> context, InstanceIdentifier<? extends Object> path) {
-
- val router = registration.router;
- val paths = registration.registeredPaths;
-
- val routingTable = router.getRoutingTable(context)
- checkState(routingTable != null);
-
- // Updating internal structure of registration
- val target = routingTable.getRoute(path)
- checkState(target === registration.instance)
- routingTable.removeRoute(path)
- checkState(paths.remove(context, path));
- }
-
- protected def <T extends RpcService> void unregisterRoutedRpcService(RoutedRpcRegistrationImpl<T> registration) {
-
- val router = registration.router;
- val paths = registration.registeredPaths;
-
- for (ctxMap : registration.registeredPaths.entries) {
- val context = ctxMap.key
- val routingTable = router.getRoutingTable(context)
- val path = ctxMap.value
- routingTable.removeRoute(path)
- }
- }
-
- protected def <T extends RpcService> void unregisterRpcService(RpcServiceRegistrationImpl<T> registration) {
-
- val type = registration.serviceType;
-
- val proxy = managedProxies.get(type);
- if (proxy.proxy.delegate === registration.instance) {
- proxy.proxy.delegate = null;
- }
- }
-
- def createDelegate(Class<? extends RpcService> type) {
- getManagedDirectProxy(type);
- }
-
- def getRpcRouters() {
- return Collections.unmodifiableMap(rpcRouters);
- }
-
- override close() {
- dataConsumerRegistration.unregister()
- dataProviderRegistration.unregister()
- notifyConsumerRegistration.unregister()
- notifyProviderRegistration.unregister()
- }
-
-}
-
-class RoutedRpcRegistrationImpl<T extends RpcService> extends AbstractObjectRegistration<T> implements RoutedRpcRegistration<T> {
-
- @Property
- private val BindingAwareBrokerImpl broker;
-
- @Property
- private val RpcRouter<T> router;
-
- @Property
- private val Multimap<Class<? extends BaseIdentity>, InstanceIdentifier<?>> registeredPaths = HashMultimap.create();
-
- private var closed = false;
-
- new(T instance, RpcRouter<T> backingRouter, BindingAwareBrokerImpl broker) {
- super(instance)
- _router = backingRouter;
- _broker = broker;
- }
-
- override protected removeRegistration() {
- closed = true
- broker.unregisterRoutedRpcService(this)
- }
-
- override registerInstance(Class<? extends BaseIdentity> context, InstanceIdentifier<? extends Object> instance) {
- registerPath(context, instance);
- }
-
- override unregisterInstance(Class<? extends BaseIdentity> context, InstanceIdentifier<? extends Object> instance) {
- unregisterPath(context, instance);
- }
-
- override registerPath(Class<? extends BaseIdentity> context, InstanceIdentifier<? extends Object> path) {
- checkClosed()
- broker.registerPath(this, context, path);
- }
-
- override unregisterPath(Class<? extends BaseIdentity> context, InstanceIdentifier<? extends Object> path) {
- checkClosed()
- broker.unregisterPath(this, context, path);
- }
-
- override getServiceType() {
- return router.serviceType;
- }
-
- private def checkClosed() {
- if (closed)
- throw new IllegalStateException("Registration was closed.");
- }
-
-}
-
-class RpcServiceRegistrationImpl<T extends RpcService> extends AbstractObjectRegistration<T> implements RpcRegistration<T> {
-
- private var BindingAwareBrokerImpl broker;
-
- @Property
- val Class<T> serviceType;
-
- public new(Class<T> type, T service, BindingAwareBrokerImpl broker) {
- super(service);
- this._serviceType = type;
- this.broker = broker;
- }
-
- override protected removeRegistration() {
- broker.unregisterRpcService(this);
- broker = null;
+ override close() throws Exception {
+
}
-
-}
+}
\ No newline at end of file
import org.opendaylight.yangtools.concepts.ListenerRegistration\r
import org.opendaylight.yangtools.concepts.Registration\r
import org.opendaylight.yangtools.yang.binding.Notification\r
-import org.slf4j.LoggerFactory\r
-\r
+import org.slf4j.LoggerFactory\rimport org.opendaylight.controller.sal.binding.codegen.impl.SingletonHolder
+
class NotificationBrokerImpl implements NotificationProviderService, AutoCloseable {\r
\r
val Multimap<Class<? extends Notification>, NotificationListener<?>> listeners;\r
@Property\r
var ExecutorService executor;\r
\r
+ new() {\r
+ listeners = HashMultimap.create()\r
+ }\r
+\r
+ @Deprecated\r
new(ExecutorService executor) {\r
listeners = HashMultimap.create()\r
this.executor = executor;\r
\r
override registerNotificationListener(\r
org.opendaylight.yangtools.yang.binding.NotificationListener listener) {\r
- val invoker = BindingAwareBrokerImpl.generator.invokerFactory.invokerFor(listener);\r
+ val invoker = SingletonHolder.INVOKER_FACTORY.invokerFor(listener);\r
for (notifyType : invoker.supportedNotifications) {\r
listeners.put(notifyType, invoker.invocationProxy)\r
}\r
val ref = services.iterator().next() as ServiceReference<T>;
return bundleContext.getService(ref) as T;
} else {
- broker.createDelegate(module);
- return getRpcService(module);
+ return broker.getRpcService(module);
}
} catch (InvalidSyntaxException e) {
log.error("Created filter was invalid:", e.message, e)
--- /dev/null
+package org.opendaylight.controller.sal.binding.impl;
+
+import java.util.Map;
+import java.util.Map.Entry;
+import java.util.HashMap;
+import java.util.Set;
+import java.util.WeakHashMap;
+
+import javax.swing.tree.ExpandVetoException;
+
+import org.opendaylight.controller.md.sal.common.api.routing.RouteChange;
+import org.opendaylight.controller.md.sal.common.api.routing.RouteChangeListener;
+import org.opendaylight.controller.md.sal.common.api.routing.RouteChangePublisher;
+import org.opendaylight.controller.md.sal.common.impl.routing.RoutingUtils;
+import org.opendaylight.controller.sal.binding.api.RpcProviderRegistry;
+import org.opendaylight.controller.sal.binding.api.BindingAwareBroker.RoutedRpcRegistration;
+import org.opendaylight.controller.sal.binding.api.BindingAwareBroker.RpcRegistration;
+import org.opendaylight.controller.sal.binding.codegen.RuntimeCodeGenerator;
+import org.opendaylight.controller.sal.binding.codegen.RuntimeCodeHelper;
+import org.opendaylight.controller.sal.binding.codegen.impl.SingletonHolder;
+import org.opendaylight.controller.sal.binding.spi.RpcContextIdentifier;
+import org.opendaylight.controller.sal.binding.spi.RpcRouter;
+import org.opendaylight.yangtools.concepts.AbstractObjectRegistration;
+import org.opendaylight.yangtools.concepts.Identifiable;
+import org.opendaylight.yangtools.concepts.ListenerRegistration;
+import org.opendaylight.yangtools.concepts.util.ListenerRegistry;
+import org.opendaylight.yangtools.yang.binding.BaseIdentity;
+import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
+import org.opendaylight.yangtools.yang.binding.RpcService;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import static com.google.common.base.Preconditions.*;
+
+public class RpcProviderRegistryImpl implements //
+ RpcProviderRegistry, //
+ RouteChangePublisher<RpcContextIdentifier, InstanceIdentifier<?>> {
+
+ private RuntimeCodeGenerator rpcFactory = SingletonHolder.RPC_GENERATOR_IMPL;
+
+ private final Map<Class<? extends RpcService>, RpcService> publicProxies = new WeakHashMap<>();
+ private final Map<Class<? extends RpcService>, RpcRouter<?>> rpcRouters = new WeakHashMap<>();
+ private final ListenerRegistry<RouteChangeListener<RpcContextIdentifier, InstanceIdentifier<?>>> routeChangeListeners = ListenerRegistry
+ .create();
+
+ private final static Logger LOG = LoggerFactory.getLogger(RpcProviderRegistryImpl.class);
+
+ private final String name;
+
+ public String getName() {
+ return name;
+ }
+
+ public RpcProviderRegistryImpl(String name) {
+ super();
+ this.name = name;
+ }
+
+ @Override
+ public final <T extends RpcService> RoutedRpcRegistration<T> addRoutedRpcImplementation(Class<T> type,
+ T implementation) throws IllegalStateException {
+ return getRpcRouter(type).addRoutedRpcImplementation(implementation);
+ }
+
+ @Override
+ public final <T extends RpcService> RpcRegistration<T> addRpcImplementation(Class<T> type, T implementation)
+ throws IllegalStateException {
+ @SuppressWarnings("unchecked")
+ RpcRouter<T> potentialRouter = (RpcRouter<T>) rpcRouters.get(type);
+ if (potentialRouter != null) {
+ checkState(potentialRouter.getDefaultService() == null,
+ "Default service for routed RPC already registered.");
+ return potentialRouter.registerDefaultService(implementation);
+ }
+ T publicProxy = getRpcService(type);
+ RpcService currentDelegate = RuntimeCodeHelper.getDelegate(publicProxy);
+ checkState(currentDelegate == null, "Rpc service is already registered");
+ LOG.debug("Registering {} as global implementation of {} in {}",implementation,type.getSimpleName(),this);
+ RuntimeCodeHelper.setDelegate(publicProxy, implementation);
+ return new RpcProxyRegistration<T>(type, implementation, this);
+ }
+
+ @SuppressWarnings("unchecked")
+ @Override
+ public final <T extends RpcService> T getRpcService(Class<T> type) {
+
+ @SuppressWarnings("unchecked")
+ T potentialProxy = (T) publicProxies.get(type);
+ if (potentialProxy != null) {
+ return potentialProxy;
+ }
+ synchronized(this) {
+ /**
+ * Potential proxy could be instantiated by other thread while we were
+ * waiting for the lock.
+ */
+
+ potentialProxy = (T) publicProxies.get(type);
+ if (potentialProxy != null) {
+ return (T) potentialProxy;
+ }
+ T proxy = rpcFactory.getDirectProxyFor(type);
+ LOG.debug("Created {} as public proxy for {} in {}",proxy,type.getSimpleName(),this);
+ publicProxies.put(type, proxy);
+ return proxy;
+ }
+ }
+
+ private <T extends RpcService> RpcRouter<T> getRpcRouter(Class<T> type) {
+ RpcRouter<?> potentialRouter = rpcRouters.get(type);
+ if (potentialRouter != null) {
+ return (RpcRouter<T>) potentialRouter;
+ }
+ synchronized(this) {
+ /**
+ * Potential Router could be instantiated by other thread while we were
+ * waiting for the lock.
+ */
+ potentialRouter = rpcRouters.get(type);
+ if (potentialRouter != null) {
+ return (RpcRouter<T>) potentialRouter;
+ }
+ RpcRouter<T> router = rpcFactory.getRouterFor(type,name);
+ router.registerRouteChangeListener(new RouteChangeForwarder(type));
+ LOG.debug("Registering router {} as global implementation of {} in {}",router,type.getSimpleName(),this);
+ RuntimeCodeHelper.setDelegate(getRpcService(type), router.getInvocationProxy());
+ rpcRouters.put(type, router);
+ return router;
+ }
+ }
+
+ @Override
+ public <L extends RouteChangeListener<RpcContextIdentifier, InstanceIdentifier<?>>> ListenerRegistration<L> registerRouteChangeListener(
+ L listener) {
+ return (ListenerRegistration<L>) routeChangeListeners.register(listener);
+ }
+
+ public RuntimeCodeGenerator getRpcFactory() {
+ return rpcFactory;
+ }
+
+ public void setRpcFactory(RuntimeCodeGenerator rpcFactory) {
+ this.rpcFactory = rpcFactory;
+ }
+
+ private class RouteChangeForwarder<T extends RpcService> implements
+ RouteChangeListener<Class<? extends BaseIdentity>, InstanceIdentifier<?>> {
+
+ private final Class<T> type;
+
+ public RouteChangeForwarder(Class<T> type) {
+ this.type = type;
+ }
+
+ @Override
+ public void onRouteChange(RouteChange<Class<? extends BaseIdentity>, InstanceIdentifier<?>> change) {
+ Map<RpcContextIdentifier, Set<InstanceIdentifier<?>>> announcements = new HashMap<>();
+ for (Entry<Class<? extends BaseIdentity>, Set<InstanceIdentifier<?>>> entry : change.getAnnouncements()
+ .entrySet()) {
+ RpcContextIdentifier key = RpcContextIdentifier.contextFor(type, entry.getKey());
+ announcements.put(key, entry.getValue());
+ }
+ Map<RpcContextIdentifier, Set<InstanceIdentifier<?>>> removals = new HashMap<>();
+ for (Entry<Class<? extends BaseIdentity>, Set<InstanceIdentifier<?>>> entry : change.getRemovals()
+ .entrySet()) {
+ RpcContextIdentifier key = RpcContextIdentifier.contextFor(type, entry.getKey());
+ removals.put(key, entry.getValue());
+ }
+ RouteChange<RpcContextIdentifier, InstanceIdentifier<?>> toPublish = RoutingUtils
+ .<RpcContextIdentifier, InstanceIdentifier<?>> change(announcements, removals);
+ for (ListenerRegistration<RouteChangeListener<RpcContextIdentifier, InstanceIdentifier<?>>> listener : routeChangeListeners) {
+ try {
+ listener.getInstance().onRouteChange(toPublish);
+ } catch (Exception e) {
+ e.printStackTrace();
+ }
+ }
+ }
+ }
+
+ public static class RpcProxyRegistration<T extends RpcService> extends AbstractObjectRegistration<T> implements
+ RpcRegistration<T> {
+
+ private final Class<T> serviceType;
+ private RpcProviderRegistryImpl registry;
+
+ public RpcProxyRegistration(Class<T> type, T service, RpcProviderRegistryImpl registry) {
+ super(service);
+ serviceType = type;
+ }
+
+ @Override
+ public Class<T> getServiceType() {
+ return serviceType;
+ }
+
+ @Override
+ protected void removeRegistration() {
+ if (registry != null) {
+ T publicProxy = registry.getRpcService(serviceType);
+ RpcService currentDelegate = RuntimeCodeHelper.getDelegate(publicProxy);
+ if (currentDelegate == getInstance()) {
+ RuntimeCodeHelper.setDelegate(publicProxy, null);
+ }
+ registry = null;
+ }
+ }
+ }
+}
package org.opendaylight.controller.sal.binding.impl.connect.dom;
+import java.lang.ref.WeakReference;
+import java.lang.reflect.InvocationTargetException;
+import java.lang.reflect.Method;
+import java.lang.reflect.ParameterizedType;
import java.util.Collection;
import java.util.Collections;
+import java.util.HashMap;
+import java.util.HashSet;
import java.util.Map;
import java.util.Map.Entry;
+import java.util.Set;
+import java.util.WeakHashMap;
+import java.util.concurrent.Callable;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentMap;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.Future;
+
import org.opendaylight.controller.md.sal.common.api.RegistrationListener;
import org.opendaylight.controller.md.sal.common.api.TransactionStatus;
import org.opendaylight.controller.md.sal.common.api.data.DataCommitHandler;
import org.opendaylight.controller.md.sal.common.api.data.DataCommitHandler.DataCommitTransaction;
import org.opendaylight.controller.md.sal.common.api.data.DataCommitHandlerRegistration;
import org.opendaylight.controller.md.sal.common.api.data.DataModification;
+import org.opendaylight.controller.md.sal.common.api.routing.RouteChange;
+import org.opendaylight.controller.md.sal.common.api.routing.RouteChangeListener;
+import org.opendaylight.controller.sal.binding.api.RpcProviderRegistry;
import org.opendaylight.controller.sal.binding.api.data.DataProviderService;
import org.opendaylight.controller.sal.binding.api.data.RuntimeDataProvider;
+import org.opendaylight.controller.sal.binding.impl.RpcProviderRegistryImpl;
+import org.opendaylight.controller.sal.binding.spi.RpcContextIdentifier;
+import org.opendaylight.controller.sal.binding.spi.RpcRouter;
import org.opendaylight.controller.sal.common.util.Rpcs;
import org.opendaylight.controller.sal.core.api.Provider;
import org.opendaylight.controller.sal.core.api.Broker.ProviderSession;
+import org.opendaylight.controller.sal.core.api.RpcImplementation;
+import org.opendaylight.controller.sal.core.api.RpcProvisionRegistry;
import org.opendaylight.controller.sal.core.api.data.DataModificationTransaction;
+import org.opendaylight.yangtools.concepts.ListenerRegistration;
import org.opendaylight.yangtools.concepts.Registration;
+import org.opendaylight.yangtools.concepts.util.ClassLoaderUtils;
import org.opendaylight.yangtools.yang.binding.Augmentable;
import org.opendaylight.yangtools.yang.binding.Augmentation;
+import org.opendaylight.yangtools.yang.binding.BaseIdentity;
+import org.opendaylight.yangtools.yang.binding.BindingMapping;
+import org.opendaylight.yangtools.yang.binding.DataContainer;
import org.opendaylight.yangtools.yang.binding.DataObject;
import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
+import org.opendaylight.yangtools.yang.binding.RpcInput;
+import org.opendaylight.yangtools.yang.binding.RpcService;
+import org.opendaylight.yangtools.yang.binding.util.BindingReflections;
+import org.opendaylight.yangtools.yang.common.QName;
import org.opendaylight.yangtools.yang.common.RpcError;
import org.opendaylight.yangtools.yang.common.RpcResult;
import org.opendaylight.yangtools.yang.data.api.CompositeNode;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
-public class BindingIndependentDataServiceConnector implements //
+import com.google.common.base.Function;
+import com.google.common.base.Optional;
+import com.google.common.collect.FluentIterable;
+import com.google.common.collect.ImmutableSet;
+
+import static com.google.common.base.Preconditions.*;
+import static org.opendaylight.yangtools.concepts.util.ClassLoaderUtils.*;
+
+public class BindingIndependentConnector implements //
RuntimeDataProvider, //
- Provider, AutoCloseable {
+ Provider, //
+ AutoCloseable {
- private final Logger LOG = LoggerFactory.getLogger(BindingIndependentDataServiceConnector.class);
+ private final Logger LOG = LoggerFactory.getLogger(BindingIndependentConnector.class);
private static final InstanceIdentifier<? extends DataObject> ROOT = InstanceIdentifier.builder().toInstance();
private Registration<DataCommitHandler<org.opendaylight.yangtools.yang.data.api.InstanceIdentifier, CompositeNode>> biCommitHandlerRegistration;
+ private RpcProvisionRegistry biRpcRegistry;
+ private RpcProviderRegistryImpl baRpcRegistry;
+
+ private ListenerRegistration<DomToBindingRpcForwardingManager> domToBindingRpcManager;
+ // private ListenerRegistration<BindingToDomRpcForwardingManager>
+ // bindingToDomRpcManager;
+
+ private Function<InstanceIdentifier<?>, org.opendaylight.yangtools.yang.data.api.InstanceIdentifier> toDOMInstanceIdentifier = new Function<InstanceIdentifier<?>, org.opendaylight.yangtools.yang.data.api.InstanceIdentifier>() {
+
+ @Override
+ public org.opendaylight.yangtools.yang.data.api.InstanceIdentifier apply(InstanceIdentifier<?> input) {
+ return mappingService.toDataDom(input);
+ }
+
+ };
+
@Override
public DataObject readOperationalData(InstanceIdentifier<? extends DataObject> path) {
try {
org.opendaylight.yangtools.yang.data.api.InstanceIdentifier biPath = mappingService.toDataDom(path);
-
-
+
CompositeNode result = biDataService.readOperationalData(biPath);
Class<? extends DataObject> targetType = path.getTargetType();
-
- if(Augmentation.class.isAssignableFrom(targetType)) {
+
+ if (Augmentation.class.isAssignableFrom(targetType)) {
path = mappingService.fromDataDom(biPath);
Class<? extends Augmentation<?>> augmentType = (Class<? extends Augmentation<?>>) targetType;
DataObject parentTo = mappingService.dataObjectFromDataDom(path, result);
- if(parentTo instanceof Augmentable<?>) {
+ if (parentTo instanceof Augmentable<?>) {
return (DataObject) ((Augmentable) parentTo).getAugmentation(augmentType);
}
-
+
}
return mappingService.dataObjectFromDataDom(path, result);
-
+
} catch (DeserializationException e) {
throw new IllegalStateException(e);
}
this.baDataService = baDataService;
}
+ public RpcProviderRegistry getRpcRegistry() {
+ return baRpcRegistry;
+ }
+
+ public void setRpcRegistry(RpcProviderRegistryImpl rpcRegistry) {
+ this.baRpcRegistry = rpcRegistry;
+ }
+
public void start() {
baDataService.registerDataReader(ROOT, this);
baCommitHandlerRegistration = baDataService.registerCommitHandler(ROOT, bindingToDomCommitHandler);
biCommitHandlerRegistration = biDataService.registerCommitHandler(ROOT_BI, domToBindingCommitHandler);
baDataService.registerCommitHandlerListener(domToBindingCommitHandler);
+
+ if (baRpcRegistry != null && biRpcRegistry != null) {
+ domToBindingRpcManager = baRpcRegistry.registerRouteChangeListener(new DomToBindingRpcForwardingManager());
+
+ }
}
public void setMappingService(BindingIndependentMappingService mappingService) {
start();
}
+ public <T extends RpcService> void onRpcRouterCreated(Class<T> serviceType, RpcRouter<T> router) {
+
+ }
+
+ public void setDomRpcRegistry(RpcProvisionRegistry registry) {
+ biRpcRegistry = registry;
+ }
+
@Override
public void close() throws Exception {
if (baCommitHandlerRegistration != null) {
return forwardedTransaction;
}
}
+
+ private class DomToBindingRpcForwardingManager implements
+ RouteChangeListener<RpcContextIdentifier, InstanceIdentifier<?>> {
+
+ private final Map<Class<? extends RpcService>, DomToBindingRpcForwarder> forwarders = new WeakHashMap<>();
+
+ @Override
+ public void onRouteChange(RouteChange<RpcContextIdentifier, InstanceIdentifier<?>> change) {
+ for (Entry<RpcContextIdentifier, Set<InstanceIdentifier<?>>> entry : change.getAnnouncements().entrySet()) {
+ bindingRoutesAdded(entry);
+ }
+ }
+
+ private void bindingRoutesAdded(Entry<RpcContextIdentifier, Set<InstanceIdentifier<?>>> entry) {
+ Class<? extends BaseIdentity> context = entry.getKey().getRoutingContext();
+ Class<? extends RpcService> service = entry.getKey().getRpcService();
+ if (context != null) {
+ getRpcForwarder(service, context).registerPaths(context, service, entry.getValue());
+ }
+ }
+
+ private DomToBindingRpcForwarder getRpcForwarder(Class<? extends RpcService> service,
+ Class<? extends BaseIdentity> context) {
+ DomToBindingRpcForwarder potential = forwarders.get(service);
+ if (potential != null) {
+ return potential;
+ }
+ if (context == null) {
+ potential = new DomToBindingRpcForwarder(service);
+ } else {
+ potential = new DomToBindingRpcForwarder(service, context);
+ }
+ forwarders.put(service, potential);
+ return potential;
+ }
+
+ }
+
+ private class DomToBindingRpcForwarder implements RpcImplementation {
+
+ private final Set<QName> supportedRpcs;
+ private final WeakReference<Class<? extends RpcService>> rpcServiceType;
+ private Set<org.opendaylight.controller.sal.core.api.Broker.RoutedRpcRegistration> registrations;
+
+ public DomToBindingRpcForwarder(Class<? extends RpcService> service) {
+ this.rpcServiceType = new WeakReference<Class<? extends RpcService>>(service);
+ this.supportedRpcs = mappingService.getRpcQNamesFor(service);
+ for (QName rpc : supportedRpcs) {
+ biRpcRegistry.addRpcImplementation(rpc, this);
+ }
+ registrations = ImmutableSet.of();
+ }
+
+ public DomToBindingRpcForwarder(Class<? extends RpcService> service, Class<? extends BaseIdentity> context) {
+ this.rpcServiceType = new WeakReference<Class<? extends RpcService>>(service);
+ this.supportedRpcs = mappingService.getRpcQNamesFor(service);
+ registrations = new HashSet<>();
+ for (QName rpc : supportedRpcs) {
+ registrations.add(biRpcRegistry.addRoutedRpcImplementation(rpc, this));
+ }
+ registrations = ImmutableSet.copyOf(registrations);
+ }
+
+ public void registerPaths(Class<? extends BaseIdentity> context, Class<? extends RpcService> service,
+ Set<InstanceIdentifier<?>> set) {
+ QName ctx = BindingReflections.findQName(context);
+ for (org.opendaylight.yangtools.yang.data.api.InstanceIdentifier path : FluentIterable.from(set).transform(
+ toDOMInstanceIdentifier)) {
+ for (org.opendaylight.controller.sal.core.api.Broker.RoutedRpcRegistration reg : registrations) {
+ reg.registerPath(ctx, path);
+ }
+ }
+ }
+
+ public void removePaths(Class<? extends BaseIdentity> context, Class<? extends RpcService> service,
+ Set<InstanceIdentifier<?>> set) {
+ QName ctx = BindingReflections.findQName(context);
+ for (org.opendaylight.yangtools.yang.data.api.InstanceIdentifier path : FluentIterable.from(set).transform(
+ toDOMInstanceIdentifier)) {
+ for (org.opendaylight.controller.sal.core.api.Broker.RoutedRpcRegistration reg : registrations) {
+ reg.unregisterPath(ctx, path);
+ }
+ }
+ }
+
+ @Override
+ public Set<QName> getSupportedRpcs() {
+ return supportedRpcs;
+ }
+
+ @Override
+ public RpcResult<CompositeNode> invokeRpc(QName rpc, CompositeNode domInput) {
+ checkArgument(rpc != null);
+ checkArgument(domInput != null);
+
+ Class<? extends RpcService> rpcType = rpcServiceType.get();
+ checkState(rpcType != null);
+ RpcService rpcService = baRpcRegistry.getRpcService(rpcType);
+ checkState(rpcService != null);
+ CompositeNode domUnwrappedInput = domInput.getFirstCompositeByName(QName.create(rpc, "input"));
+ try {
+ return resolveInvocationStrategy(rpc, rpcType).invokeOn(rpcService, domUnwrappedInput);
+ } catch (Exception e) {
+ throw new IllegalStateException(e);
+ }
+ }
+
+ private RpcInvocationStrategy resolveInvocationStrategy(final QName rpc,
+ final Class<? extends RpcService> rpcType) throws Exception {
+ return ClassLoaderUtils.withClassLoader(rpcType.getClassLoader(), new Callable<RpcInvocationStrategy>() {
+ @Override
+ public RpcInvocationStrategy call() throws Exception {
+ String methodName = BindingMapping.getMethodName(rpc);
+ Method targetMethod = null;
+ for (Method possibleMethod : rpcType.getMethods()) {
+ if (possibleMethod.getName().equals(methodName)
+ && BindingReflections.isRpcMethod(possibleMethod)) {
+ targetMethod = possibleMethod;
+ break;
+ }
+ }
+ checkState(targetMethod != null, "Rpc method not found");
+ Optional<Class<?>> outputClass = BindingReflections.resolveRpcOutputClass(targetMethod);
+ Optional<Class<? extends DataContainer>> inputClass = BindingReflections
+ .resolveRpcInputClass(targetMethod);
+
+ RpcInvocationStrategy strategy = null;
+ if (outputClass.isPresent()) {
+ if (inputClass.isPresent()) {
+ strategy = new DefaultInvocationStrategy(targetMethod, outputClass.get(), inputClass.get());
+ } else {
+ strategy = new NoInputNoOutputInvocationStrategy(targetMethod);
+ }
+ } else {
+ strategy = null;
+ }
+ return strategy;
+ }
+
+ });
+ }
+ }
+
+ private abstract class RpcInvocationStrategy {
+
+ protected final Method targetMethod;
+
+ public RpcInvocationStrategy(Method targetMethod) {
+ this.targetMethod = targetMethod;
+ }
+
+ public abstract RpcResult<CompositeNode> uncheckedInvoke(RpcService rpcService, CompositeNode domInput)
+ throws Exception;
+
+ public RpcResult<CompositeNode> invokeOn(RpcService rpcService, CompositeNode domInput) throws Exception {
+ return uncheckedInvoke(rpcService, domInput);
+ }
+ }
+
+ private class DefaultInvocationStrategy extends RpcInvocationStrategy {
+
+ @SuppressWarnings("rawtypes")
+ private WeakReference<Class> inputClass;
+
+ @SuppressWarnings("rawtypes")
+ private WeakReference<Class> outputClass;
+
+ public DefaultInvocationStrategy(Method targetMethod, Class<?> outputClass,
+ Class<? extends DataContainer> inputClass) {
+ super(targetMethod);
+ this.outputClass = new WeakReference(outputClass);
+ this.inputClass = new WeakReference(inputClass);
+ }
+
+ @Override
+ public RpcResult<CompositeNode> uncheckedInvoke(RpcService rpcService, CompositeNode domInput) throws Exception {
+ DataContainer bindingInput = mappingService.dataObjectFromDataDom(inputClass.get(), domInput);
+ Future<RpcResult<?>> result = (Future<RpcResult<?>>) targetMethod.invoke(rpcService, bindingInput);
+ if (result == null) {
+ return Rpcs.getRpcResult(false);
+ }
+ RpcResult<?> bindingResult = result.get();
+ return Rpcs.getRpcResult(true);
+ }
+
+ }
+
+ private class NoInputNoOutputInvocationStrategy extends RpcInvocationStrategy {
+
+ public NoInputNoOutputInvocationStrategy(Method targetMethod) {
+ super(targetMethod);
+ }
+
+ public RpcResult<CompositeNode> uncheckedInvoke(RpcService rpcService, CompositeNode domInput) throws Exception {
+ Future<RpcResult<Void>> result = (Future<RpcResult<Void>>) targetMethod.invoke(rpcService);
+ RpcResult<Void> bindingResult = result.get();
+ return Rpcs.getRpcResult(bindingResult.isSuccessful(), bindingResult.getErrors());
+ }
+
+ }
}
package org.opendaylight.controller.sal.binding.impl.connect.dom;
import java.util.Map.Entry;
+import java.util.Set;
-import org.opendaylight.yangtools.concepts.ListenerRegistration;
+import org.opendaylight.yangtools.yang.binding.DataContainer;
import org.opendaylight.yangtools.yang.binding.DataObject;
import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
+import org.opendaylight.yangtools.yang.binding.RpcService;
+import org.opendaylight.yangtools.yang.common.QName;
import org.opendaylight.yangtools.yang.data.api.CompositeNode;
public interface BindingIndependentMappingService {
DataObject dataObjectFromDataDom(InstanceIdentifier<? extends DataObject> path, CompositeNode result) throws DeserializationException;
InstanceIdentifier<?> fromDataDom(org.opendaylight.yangtools.yang.data.api.InstanceIdentifier entry) throws DeserializationException;
+
+ Set<QName> getRpcQNamesFor(Class<? extends RpcService> service);
+
+ DataContainer dataObjectFromDataDom(Class<? extends DataContainer> inputClass, CompositeNode domInput);
}
public static Class<?> loadClassWithTCCL(String name) throws ClassNotFoundException {
if ("byte[]".equals(name)) {
return byte[].class;
+ } else if("char[]".equals(name)) {
+ return char[].class;
}
try {
return Thread.currentThread().getContextClassLoader().loadClass(name);
try {
return loadClassWithTCCL(fullyQualifiedName);
} catch (ClassNotFoundException e) {
-
+ return null;
}
- return null;
}
}
\ No newline at end of file
--- /dev/null
+package org.opendaylight.controller.sal.binding.spi;
+
+public class RoutingContext {
+
+}
--- /dev/null
+package org.opendaylight.controller.sal.binding.spi;
+
+import org.opendaylight.yangtools.concepts.Immutable;
+import org.opendaylight.yangtools.yang.binding.BaseIdentity;
+import org.opendaylight.yangtools.yang.binding.RpcService;
+
+public final class RpcContextIdentifier implements Immutable{
+
+ public final Class<? extends RpcService> rpcService;
+ public final Class<? extends BaseIdentity> routingContext;
+
+ private RpcContextIdentifier(Class<? extends RpcService> rpcService, Class<? extends BaseIdentity> routingContext) {
+ super();
+ this.rpcService = rpcService;
+ this.routingContext = routingContext;
+ }
+
+ public Class<? extends RpcService> getRpcService() {
+ return rpcService;
+ }
+
+ public Class<? extends BaseIdentity> getRoutingContext() {
+ return routingContext;
+ }
+
+ public static final RpcContextIdentifier contextForGlobalRpc(Class<? extends RpcService> serviceType) {
+ return new RpcContextIdentifier(serviceType, null);
+ }
+
+ public static final RpcContextIdentifier contextFor(Class<? extends RpcService> serviceType,Class<? extends BaseIdentity> routingContext) {
+ return new RpcContextIdentifier(serviceType, routingContext);
+ }
+
+ @Override
+ public int hashCode() {
+ final int prime = 31;
+ int result = 1;
+ result = prime * result + ((routingContext == null) ? 0 : routingContext.hashCode());
+ result = prime * result + ((rpcService == null) ? 0 : rpcService.hashCode());
+ return result;
+ }
+
+ @Override
+ public boolean equals(Object obj) {
+ if (this == obj)
+ return true;
+ if (obj == null)
+ return false;
+ if (getClass() != obj.getClass())
+ return false;
+ RpcContextIdentifier other = (RpcContextIdentifier) obj;
+ if (routingContext == null) {
+ if (other.routingContext != null)
+ return false;
+ } else if (!routingContext.equals(other.routingContext))
+ return false;
+ if (rpcService == null) {
+ if (other.rpcService != null)
+ return false;
+ } else if (!rpcService.equals(other.rpcService))
+ return false;
+ return true;
+ }
+
+}
import java.util.Set;
+import org.opendaylight.controller.md.sal.common.api.routing.RouteChangePublisher;
+import org.opendaylight.controller.sal.binding.api.BindingAwareBroker.RoutedRpcRegistration;
+import org.opendaylight.controller.sal.binding.api.BindingAwareBroker.RpcRegistration;
import org.opendaylight.yangtools.yang.binding.BaseIdentity;
import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
import org.opendaylight.yangtools.yang.binding.RpcImplementation;
* Type of RpcService for which router provides routing information
* and route selection.
*/
-public interface RpcRouter<T extends RpcService> extends RpcImplementation{
+public interface RpcRouter<T extends RpcService> extends //
+ RouteChangePublisher<Class<? extends BaseIdentity>, InstanceIdentifier<?>> {
/**
* Returns a type of RpcService which is served by this instance of router.
* @return default instance responsible for processing RPCs.
*/
T getDefaultService();
-
- /**
- *
- */
- void setDefaultService(T service);
Set<Class<? extends BaseIdentity>> getContexts();
+
+ RoutedRpcRegistration<T> addRoutedRpcImplementation(T service);
+
+ RpcRegistration<T> registerDefaultService(T service);
}
import org.junit.Before;
import org.opendaylight.controller.sal.binding.api.data.DataProviderService;
import org.opendaylight.controller.sal.binding.impl.DataBrokerImpl;
-import org.opendaylight.controller.sal.binding.impl.connect.dom.BindingIndependentDataServiceConnector;
+import org.opendaylight.controller.sal.binding.impl.connect.dom.BindingIndependentConnector;
import org.opendaylight.controller.sal.binding.impl.connect.dom.BindingIndependentMappingService;
import org.opendaylight.controller.sal.binding.test.util.BindingBrokerTestFactory;
import org.opendaylight.controller.sal.binding.test.util.BindingTestContext;
@Test
public void testGenerateRouter() throws Exception {
- RpcRouter<FooService> product = codeGenerator.getRouterFor(FooService.class);
+ RpcRouter<FooService> product = codeGenerator.getRouterFor(FooService.class,"test");
assertNotNull(product);
assertNotNull(product.getInvocationProxy());
- assertNotNull(product.getSupportedInputs());
- assertTrue(product.getSupportedInputs().contains(SimpleInput.class));
- assertTrue(product.getSupportedInputs().contains(InheritedContextInput.class));
assertEquals("2 fields should be generated.", 2, product.getInvocationProxy().getClass().getFields().length);
verifyRouting(product);
package org.opendaylight.controller.sal.binding.test.bugfix;
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertNull;
+
import java.math.BigInteger;
import java.util.ArrayList;
import java.util.Collections;
import org.junit.Test;
import org.opendaylight.controller.md.sal.common.api.TransactionStatus;
import org.opendaylight.controller.md.sal.common.api.data.DataChangeEvent;
-import org.opendaylight.controller.sal.binding.test.AbstractDataServiceTest;
-import org.opendaylight.controller.sal.binding.test.AugmentationVerifier;
import org.opendaylight.controller.sal.binding.api.data.DataChangeListener;
import org.opendaylight.controller.sal.binding.api.data.DataModificationTransaction;
+import org.opendaylight.controller.sal.binding.test.AbstractDataServiceTest;
+import org.opendaylight.controller.sal.binding.test.AugmentationVerifier;
import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.yang.types.rev100924.Counter32;
import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.yang.types.rev100924.Counter64;
import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.FlowCapableNode;
import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.FlowCapableNodeBuilder;
-import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.nodes.Node;
-import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.nodes.NodeBuilder;
import org.opendaylight.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.NodeBuilder;
import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.nodes.NodeKey;
import org.opendaylight.yang.gen.v1.urn.opendaylight.meter.statistics.rev131111.NodeMeterStatistics;
import org.opendaylight.yang.gen.v1.urn.opendaylight.meter.statistics.rev131111.NodeMeterStatisticsBuilder;
-import org.opendaylight.yang.gen.v1.urn.opendaylight.meter.statistics.rev131111.nodes.node.MeterStatisticsBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.meter.statistics.rev131111.nodes.node.meter.MeterStatisticsBuilder;
import org.opendaylight.yang.gen.v1.urn.opendaylight.meter.types.rev130918.MeterId;
-import org.opendaylight.yang.gen.v1.urn.opendaylight.meter.types.rev130918.meter.statistics.Duration;
import org.opendaylight.yang.gen.v1.urn.opendaylight.meter.types.rev130918.meter.statistics.DurationBuilder;
import org.opendaylight.yang.gen.v1.urn.opendaylight.meter.types.rev130918.meter.statistics.reply.MeterStats;
import org.opendaylight.yang.gen.v1.urn.opendaylight.meter.types.rev130918.meter.statistics.reply.MeterStatsBuilder;
import org.opendaylight.yangtools.yang.common.RpcResult;
import org.opendaylight.yangtools.yang.data.api.CompositeNode;
-import com.google.common.collect.FluentIterable;
-
-import static org.junit.Assert.*;
-
public class MultipleAugmentationPuts extends AbstractDataServiceTest implements DataChangeListener {
private static final QName NODE_ID_QNAME = QName.create(Node.QNAME, "id");
verifyNode(nodes, flowCapableNode).assertHasAugmentation(FlowCapableNode.class);
;
assertBindingIndependentVersion(NODE_INSTANCE_ID_BI);
- Node meterStatsNode = createTestNode(NodeMeterStatistics.class, nodeMeterStatistics());
- commitNodeAndVerifyTransaction(meterStatsNode);
-
- assertNotNull(receivedChangeEvent);
- verifyNode((Nodes) receivedChangeEvent.getUpdatedOperationalSubtree(), meterStatsNode);
-
- assertBindingIndependentVersion(NODE_INSTANCE_ID_BI);
-
- Node mergedNode = (Node) baDataService.readOperationalData(NODE_INSTANCE_ID_BA);
-
- AugmentationVerifier.from(mergedNode) //
- .assertHasAugmentation(FlowCapableNode.class) //
- .assertHasAugmentation(NodeMeterStatistics.class);
-
- assertBindingIndependentVersion(NODE_INSTANCE_ID_BI);
-
- Node meterStatsNodeWithDuration = createTestNode(NodeMeterStatistics.class, nodeMeterStatistics(5, true));
- commitNodeAndVerifyTransaction(meterStatsNodeWithDuration);
-
-
- Node nodeWithUpdatedList = (Node) baDataService.readOperationalData(NODE_INSTANCE_ID_BA);
- AugmentationVerifier.from(nodeWithUpdatedList) //
- .assertHasAugmentation(FlowCapableNode.class) //
- .assertHasAugmentation(NodeMeterStatistics.class);
-
- List<MeterStats> meterStats = nodeWithUpdatedList.getAugmentation(NodeMeterStatistics.class).getMeterStatistics().getMeterStats();
- assertNotNull(meterStats);
- assertFalse(meterStats.isEmpty());
- assertBindingIndependentVersion(NODE_INSTANCE_ID_BI);
+// Node meterStatsNode = createTestNode(NodeMeterStatistics.class, nodeMeterStatistics());
+// commitNodeAndVerifyTransaction(meterStatsNode);
+//
+// assertNotNull(receivedChangeEvent);
+// verifyNode((Nodes) receivedChangeEvent.getUpdatedOperationalSubtree(), meterStatsNode);
+//
+// assertBindingIndependentVersion(NODE_INSTANCE_ID_BI);
+//
+// Node mergedNode = (Node) baDataService.readOperationalData(NODE_INSTANCE_ID_BA);
+//
+// AugmentationVerifier.from(mergedNode) //
+// .assertHasAugmentation(FlowCapableNode.class) //
+// .assertHasAugmentation(NodeMeterStatistics.class);
+//
+// assertBindingIndependentVersion(NODE_INSTANCE_ID_BI);
+//
+// Node meterStatsNodeWithDuration = createTestNode(NodeMeterStatistics.class, nodeMeterStatistics(5, true));
+// commitNodeAndVerifyTransaction(meterStatsNodeWithDuration);
+//
+//
+// Node nodeWithUpdatedList = (Node) baDataService.readOperationalData(NODE_INSTANCE_ID_BA);
+// AugmentationVerifier.from(nodeWithUpdatedList) //
+// .assertHasAugmentation(FlowCapableNode.class) //
+// .assertHasAugmentation(NodeMeterStatistics.class);
+//
+// List<MeterStats> meterStats = nodeWithUpdatedList.getAugmentation(NodeMeterStatistics.class).getMeterStatistics().getMeterStats();
+// assertNotNull(meterStats);
+// assertFalse(meterStats.isEmpty());
+// assertBindingIndependentVersion(NODE_INSTANCE_ID_BI);
testNodeRemove();
}
stats.add(statistic.build());
}
- meterStats.setMeterStats(stats);
+ // meterStats.setMeterStats(stats);
nmsb.setMeterStatistics(meterStats.build());
return nmsb.build();
}
--- /dev/null
+package org.opendaylight.controller.sal.binding.test.bugfix;
+
+import org.junit.Test;
+import org.opendaylight.controller.sal.binding.test.AbstractDataServiceTest;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev100924.IpPrefix;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev100924.Ipv4Prefix;
+import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.nt.l3.unicast.igp.topology.rev131021.igp.node.attributes.igp.node.attributes.Prefix;
+import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.nt.l3.unicast.igp.topology.rev131021.igp.node.attributes.igp.node.attributes.PrefixBuilder;
+import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
+import org.opendaylight.yangtools.yang.data.api.CompositeNode;
+
+
+
+
+
+
+
+
+import static org.junit.Assert.*;
+
+public class UnionSerializationTest extends AbstractDataServiceTest {
+
+ public static final String PREFIX_STRING = "192.168.0.1/32";
+
+
+ @Test
+ public void testPrefixSerialization() throws Exception {
+
+ Ipv4Prefix ipv4prefix = new Ipv4Prefix(PREFIX_STRING);
+ IpPrefix ipPrefix = new IpPrefix(ipv4prefix);
+ Prefix prefix = new PrefixBuilder().setPrefix(ipPrefix).build();
+
+ CompositeNode serialized = testContext.getBindingToDomMappingService().toDataDom(prefix);
+ assertNotNull(serialized);
+ assertNotNull(serialized.getFirstSimpleByName(Prefix.QNAME));
+ assertEquals(PREFIX_STRING, serialized.getFirstSimpleByName(Prefix.QNAME).getValue());
+
+ Prefix deserialized = (Prefix) testContext.getBindingToDomMappingService().dataObjectFromDataDom(InstanceIdentifier.builder().node(Prefix.class).build(), serialized);
+ assertNotNull(deserialized);
+ assertNotNull(deserialized.getPrefix());
+ assertNotNull(deserialized.getPrefix().getIpv4Prefix());
+ assertEquals(PREFIX_STRING, deserialized.getPrefix().getIpv4Prefix().getValue());
+ }
+
+}
import javassist.ClassPool;
+import org.opendaylight.controller.sal.binding.api.RpcProviderRegistry;
import org.opendaylight.controller.sal.binding.api.data.DataProviderService;
import org.opendaylight.controller.sal.binding.dom.serializer.impl.RuntimeGeneratedMappingServiceImpl;
+import org.opendaylight.controller.sal.binding.impl.BindingAwareBrokerImpl;
import org.opendaylight.controller.sal.binding.impl.DataBrokerImpl;
-import org.opendaylight.controller.sal.binding.impl.connect.dom.BindingIndependentDataServiceConnector;
+import org.opendaylight.controller.sal.binding.impl.NotificationBrokerImpl;
+import org.opendaylight.controller.sal.binding.impl.connect.dom.BindingIndependentConnector;
import org.opendaylight.controller.sal.binding.impl.connect.dom.BindingIndependentMappingService;
import org.opendaylight.controller.sal.binding.test.AbstractDataServiceTest;
+import org.opendaylight.controller.sal.core.api.RpcImplementation;
+import org.opendaylight.controller.sal.core.api.RpcProvisionRegistry;
import org.opendaylight.controller.sal.core.api.data.DataStore;
+import org.opendaylight.controller.sal.dom.broker.BrokerImpl;
import org.opendaylight.controller.sal.dom.broker.impl.DataStoreStatsWrapper;
import org.opendaylight.controller.sal.dom.broker.impl.HashMapDataStore;
+import org.opendaylight.controller.sal.dom.broker.impl.RpcRouterImpl;
import org.opendaylight.controller.sal.dom.broker.impl.SchemaAwareDataStoreAdapter;
import org.opendaylight.yangtools.yang.model.api.Module;
import org.opendaylight.yangtools.yang.model.api.SchemaContext;
import static com.google.common.base.Preconditions.*;
-public class BindingTestContext {
+public class BindingTestContext implements AutoCloseable {
public static final org.opendaylight.yangtools.yang.data.api.InstanceIdentifier TREE_ROOT = org.opendaylight.yangtools.yang.data.api.InstanceIdentifier
private static final Logger LOG = LoggerFactory.getLogger(BindingTestContext.class);
private RuntimeGeneratedMappingServiceImpl mappingServiceImpl;
+
+
+ private BindingAwareBrokerImpl baBrokerImpl;
private DataBrokerImpl baDataImpl;
+ private NotificationBrokerImpl baNotifyImpl;
+ private BindingIndependentConnector baConnectDataServiceImpl;
+
private org.opendaylight.controller.sal.dom.broker.DataBrokerImpl biDataImpl;
-
- private BindingIndependentDataServiceConnector connectorServiceImpl;
+ private BrokerImpl biBrokerImpl;
private HashMapDataStore rawDataStore;
private SchemaAwareDataStoreAdapter schemaAwareDataStore;
private DataStoreStatsWrapper dataStoreStats;
private final ClassPool classPool;
private final boolean startWithSchema;
+
protected BindingTestContext(ListeningExecutorService executor, ClassPool classPool, boolean startWithSchema) {
this.executor = executor;
baDataImpl.setExecutor(executor);
}
+ public void startBindingBroker() {
+ checkState(executor != null,"Executor needs to be set");
+ checkState(baDataImpl != null,"Binding Data Broker must be started");
+ checkState(baNotifyImpl != null, "Notification Service must be started");
+ baBrokerImpl = new BindingAwareBrokerImpl("test",null);
+
+ baBrokerImpl.setDataBroker(baDataImpl);
+ baBrokerImpl.setNotifyBroker(baNotifyImpl);
+
+ baBrokerImpl.start();
+ }
+
public void startBindingToDomDataConnector() {
checkState(baDataImpl != null,"Binding Data Broker needs to be started");
checkState(biDataImpl != null,"DOM Data Broker needs to be started.");
checkState(mappingServiceImpl != null,"DOM Mapping Service needs to be started.");
- connectorServiceImpl = new BindingIndependentDataServiceConnector();
- connectorServiceImpl.setBaDataService(baDataImpl);
- connectorServiceImpl.setBiDataService(biDataImpl);
- connectorServiceImpl.setMappingService(mappingServiceImpl);
- connectorServiceImpl.start();
+ baConnectDataServiceImpl = new BindingIndependentConnector();
+ baConnectDataServiceImpl.setRpcRegistry(baBrokerImpl);
+ baConnectDataServiceImpl.setDomRpcRegistry(getDomRpcRegistry());
+ baConnectDataServiceImpl.setBaDataService(baDataImpl);
+ baConnectDataServiceImpl.setBiDataService(biDataImpl);
+ baConnectDataServiceImpl.setMappingService(mappingServiceImpl);
+ baConnectDataServiceImpl.start();
}
public void startBindingToDomMappingService() {
public void start() {
startBindingDataBroker();
+ startBindingNotificationBroker();
+ startBindingBroker();
startDomDataBroker();
startDomDataStore();
+ startDomBroker();
startBindingToDomMappingService();
startBindingToDomDataConnector();
if(startWithSchema) {
}
}
+ private void startDomBroker() {
+ checkState(executor != null);
+ biBrokerImpl = new BrokerImpl();
+ biBrokerImpl.setExecutor(executor);
+ biBrokerImpl.setRouter(new RpcRouterImpl("test"));
+ }
+
+ public void startBindingNotificationBroker() {
+ checkState(executor != null);
+ baNotifyImpl = new NotificationBrokerImpl(executor);
+
+ }
+
public void loadYangSchemaFromClasspath() {
String[] files = getAllYangFilesOnClasspath();
updateYangSchema(files);
dataStoreStats.getRequestCommitCount(), dataStoreStats.getRequestCommitTotalTime(),
dataStoreStats.getRequestCommitAverageTime());
}
+
+ public RpcProviderRegistry getBindingRpcRegistry() {
+ return baBrokerImpl;
+ }
+
+ public RpcProvisionRegistry getDomRpcRegistry() {
+ if(biBrokerImpl == null) {
+ return null;
+ }
+ return biBrokerImpl.getRouter();
+ }
+
+ public RpcImplementation getDomRpcInvoker() {
+ return biBrokerImpl.getRouter();
+ }
+
+ @Override
+ public void close() throws Exception {
+
+ }
}
<developerConnection>scm:git:ssh://git.opendaylight.org:29418/controller.git</developerConnection>
<url>https://wiki.opendaylight.org/view/OpenDaylight_Controller:MD-SAL</url>
</scm>
-
<build>
<plugins>
<plugin>
</build>
<dependencies>
+ <dependency>
+ <groupId>org.ops4j.pax.exam</groupId>
+ <artifactId>pax-exam-container-native</artifactId>
+ <scope>test</scope>
+ <version>${exam.version}</version>
+ </dependency>
<dependency>
<groupId>org.opendaylight.controller</groupId>
<artifactId>sal-binding-broker-impl</artifactId>
import java.util.concurrent.Executors;
import java.util.concurrent.Future;
+import javassist.ClassPool;
+
+import org.junit.Ignore;
import org.junit.Test;
import org.opendaylight.controller.md.sal.common.api.TransactionStatus;
import org.opendaylight.controller.sal.binding.test.AbstractDataServiceTest;
+import org.opendaylight.controller.sal.binding.test.util.BindingBrokerTestFactory;
import org.opendaylight.controller.sal.binding.api.data.DataModificationTransaction;
import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.config.rev130819.flows.Flow;
import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.nodes.Node;
import org.opendaylight.yangtools.yang.common.RpcResult;
import org.opendaylight.yangtools.yang.model.api.SchemaContext;
+import com.google.common.util.concurrent.ListeningExecutorService;
+import com.google.common.util.concurrent.MoreExecutors;
+
import static org.junit.Assert.*;
public class DOMCodecBug02Test extends AbstractDataServiceTest {
private static final NodeRef NODE_REF = new NodeRef(NODE_INSTANCE_ID_BA);
/**
- *
+ * This test is ignored, till found out better way to test generation
+ * of classes without leaking of instances from previous run
*
* @throws Exception
*/
+
+ public void setUp() {
+ ListeningExecutorService executor = MoreExecutors.sameThreadExecutor();
+ BindingBrokerTestFactory factory = new BindingBrokerTestFactory();
+ factory.setExecutor(executor);
+ factory.setClassPool(new ClassPool());
+ factory.setStartWithParsedSchema(getStartWithSchema());
+ testContext = factory.getTestContext();
+ testContext.start();
+
+ baDataService = testContext.getBindingDataBroker();
+ biDataService = testContext.getDomDataBroker();
+ dataStore = testContext.getDomDataStore();
+ mappingService = testContext.getBindingToDomMappingService();
+ };
+
@Test
public void testSchemaContextNotAvailable() throws Exception {
ExecutorService testExecutor = Executors.newFixedThreadPool(1);
-
+ testContext.loadYangSchemaFromClasspath();
Future<Future<RpcResult<TransactionStatus>>> future = testExecutor.submit(new Callable<Future<RpcResult<TransactionStatus>>>() {
@Override
public Future<RpcResult<TransactionStatus>> call() throws Exception {
}
});
- testContext.loadYangSchemaFromClasspath();
+
RpcResult<TransactionStatus> result = future.get().get();
assertEquals(TransactionStatus.COMMITED, result.getResult());
-
Nodes nodes = checkForNodes();
assertNotNull(nodes);
--- /dev/null
+package org.opendaylight.controller.sal.binding.test.bugfix;
+
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.List;
+import java.util.Map;
+import java.util.concurrent.Callable;
+import java.util.concurrent.ExecutorService;
+import java.util.concurrent.Executors;
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+import org.junit.Test;
+import org.opendaylight.controller.md.sal.common.api.TransactionStatus;
+import org.opendaylight.controller.sal.binding.test.AbstractDataServiceTest;
+import org.opendaylight.controller.sal.binding.api.data.DataModificationTransaction;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.action.types.rev131112.action.action.PopMplsActionCaseBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.action.types.rev131112.action.action.pop.mpls.action._case.PopMplsActionBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.action.types.rev131112.action.list.Action;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.action.types.rev131112.action.list.ActionBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.FlowCapableNode;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.FlowId;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.tables.Table;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.tables.TableKey;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.tables.table.Flow;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.tables.table.FlowBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.tables.table.FlowKey;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.types.rev131026.FlowModFlags;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.types.rev131026.flow.InstructionsBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.types.rev131026.flow.MatchBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.types.rev131026.instruction.instruction.ApplyActionsCaseBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.types.rev131026.instruction.instruction.apply.actions._case.ApplyActionsBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.types.rev131026.instruction.list.Instruction;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.types.rev131026.instruction.list.InstructionBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.types.rev131026.instruction.list.InstructionKey;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.nodes.Node;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.NodeId;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.NodeRef;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.Nodes;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.nodes.NodeKey;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.l2.types.rev130827.VlanId;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.model.match.types.rev131026.match.VlanMatchBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.model.match.types.rev131026.match.layer._3.match.Ipv4MatchBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.model.match.types.rev131026.match.layer._4.match.TcpMatchBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.model.match.types.rev131026.vlan.match.fields.VlanIdBuilder;
+import org.opendaylight.yangtools.yang.binding.DataObject;
+import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
+import org.opendaylight.yangtools.yang.common.QName;
+import org.opendaylight.yangtools.yang.common.RpcResult;
+import org.opendaylight.yangtools.yang.data.api.CompositeNode;
+
+import com.google.common.collect.ImmutableMap;
+import com.google.common.collect.ImmutableSet;
+import com.google.common.util.concurrent.Futures;
+import com.google.common.util.concurrent.ListenableFuture;
+import com.google.common.util.concurrent.ListeningExecutorService;
+import com.google.common.util.concurrent.MoreExecutors;
+
+import static org.junit.Assert.*;
+
+public class FlagsSerializationTest extends AbstractDataServiceTest {
+
+ private static final QName NODE_ID_QNAME = QName.create(Node.QNAME, "id");
+ private static final QName FLOW_ID_QNAME = QName.create(Flow.QNAME, "id");
+ private static final QName FLOW_NODE_QNAME = QName.create(Flow.QNAME, "node");
+ private static final long 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 Map<QName, Object> NODE_KEY_BI = Collections.<QName, Object> singletonMap(NODE_ID_QNAME,
+ NODE_ID);
+
+ private static final InstanceIdentifier<Node> NODE_INSTANCE_ID_BA = InstanceIdentifier.builder(Nodes.class) //
+ .child(Node.class, NODE_KEY).toInstance();
+
+ private static final org.opendaylight.yangtools.yang.data.api.InstanceIdentifier NODE_INSTANCE_ID_BI = //
+ org.opendaylight.yangtools.yang.data.api.InstanceIdentifier.builder() //
+ .node(Nodes.QNAME) //
+ .nodeWithKey(Node.QNAME, NODE_KEY_BI) //
+ .toInstance();
+ private static final NodeRef NODE_REF = new NodeRef(NODE_INSTANCE_ID_BA);
+
+
+
+// private static final org.opendaylight.yangtools.yang.data.api.InstanceIdentifier FLOW_INSTANCE_ID_BI = //
+// org.opendaylight.yangtools.yang.data.api.InstanceIdentifier.builder() //
+//
+// .node(Flows.QNAME) //
+// .nodeWithKey(Flow.QNAME, FLOW_KEY_BI) //
+// .toInstance();
+ private static final InstanceIdentifier<? extends DataObject> FLOW_INSTANCE_ID_BA = //
+ InstanceIdentifier.builder(NODE_INSTANCE_ID_BA) //
+ .augmentation(FlowCapableNode.class)
+ .child(Table.class,TABLE_KEY)
+ .child(Flow.class, FLOW_KEY) //
+ .toInstance();
+ private static final QName FLOW_FLAGS_QNAME = QName.create(Flow.QNAME, "flags");
+
+ @Test
+ public void testIndirectGeneration() throws Exception {
+
+ FlowModFlags checkOverlapFlags = new FlowModFlags(true,false,false,false,false);
+ ImmutableSet<String> domCheckOverlapFlags = ImmutableSet.<String>of("CHECK_OVERLAP");
+ testFlags(checkOverlapFlags,domCheckOverlapFlags);
+
+
+
+ FlowModFlags allFalseFlags = new FlowModFlags(false,false,false,false,false);
+ ImmutableSet<String> domAllFalseFlags = ImmutableSet.<String>of();
+ testFlags(allFalseFlags,domAllFalseFlags);
+
+ FlowModFlags allTrueFlags = new FlowModFlags(true,true,true,true,true);
+ ImmutableSet<String> domAllTrueFlags = ImmutableSet.<String>of("CHECK_OVERLAP","NO_BYT_COUNTS", "NO_PKT_COUNTS", "RESET_COUNTS", "SEND_FLOW_REM");
+ testFlags(allTrueFlags,domAllTrueFlags);
+
+ FlowModFlags nullFlags = null;
+ ImmutableSet<String> domNullFlags = null;
+ testFlags(null,null);
+
+
+
+ }
+
+ private void testFlags(FlowModFlags flagsToTest, ImmutableSet<String> domFlags) throws Exception {
+ Flow flow = createFlow(flagsToTest);
+ assertNotNull(flow);
+
+ CompositeNode domFlow = biDataService.readConfigurationData(mappingService.toDataDom(FLOW_INSTANCE_ID_BA));
+
+ assertNotNull(domFlow);
+ org.opendaylight.yangtools.yang.data.api.Node<?> readedFlags = domFlow.getFirstSimpleByName(FLOW_FLAGS_QNAME);
+
+ if(domFlags != null) {
+ assertNotNull(readedFlags);
+ assertEquals(domFlags,readedFlags.getValue());
+ } else {
+ assertNull(readedFlags);
+ }
+ assertEquals(flagsToTest, flow.getFlags());
+
+ DataModificationTransaction transaction = baDataService.beginTransaction();
+ transaction.removeConfigurationData(FLOW_INSTANCE_ID_BA);
+ RpcResult<TransactionStatus> result = transaction.commit().get();
+ assertEquals(TransactionStatus.COMMITED, result.getResult());
+
+ }
+
+ private Flow createFlow(FlowModFlags flagsToTest) throws Exception {
+
+ DataModificationTransaction modification = baDataService.beginTransaction();
+
+ FlowBuilder flow = new FlowBuilder();
+ MatchBuilder match = new MatchBuilder();
+ VlanMatchBuilder vlanBuilder = new VlanMatchBuilder();
+ VlanIdBuilder vlanIdBuilder = new VlanIdBuilder();
+ VlanId vlanId = new VlanId(10);
+ vlanBuilder.setVlanId(vlanIdBuilder.setVlanId(vlanId).build());
+ match.setVlanMatch(vlanBuilder.build());
+
+ flow.setKey(FLOW_KEY);
+ flow.setMatch(match.build());
+
+ flow.setFlags(flagsToTest);
+
+ InstructionsBuilder instructions = new InstructionsBuilder();
+ InstructionBuilder instruction = new InstructionBuilder();
+
+ instruction.setOrder(10);
+ ApplyActionsBuilder applyActions = new ApplyActionsBuilder();
+ List<Action> actionList = new ArrayList<>();
+ PopMplsActionBuilder popMplsAction = new PopMplsActionBuilder();
+ popMplsAction.setEthernetType(34);
+ actionList.add(new ActionBuilder().setAction(new PopMplsActionCaseBuilder().setPopMplsAction(popMplsAction.build()).build()).setOrder(10).build());
+
+ applyActions.setAction(actionList );
+
+ instruction.setInstruction(new ApplyActionsCaseBuilder().setApplyActions(applyActions.build()).build());
+
+
+ List<Instruction> instructionList = Collections.<Instruction>singletonList(instruction.build());
+ instructions.setInstruction(instructionList );
+
+ flow.setInstructions(instructions.build());
+ modification.putConfigurationData(FLOW_INSTANCE_ID_BA, flow.build());
+ RpcResult<TransactionStatus> ret = modification.commit().get();
+ assertNotNull(ret);
+ assertEquals(TransactionStatus.COMMITED, ret.getResult());
+ return (Flow) baDataService.readConfigurationData(FLOW_INSTANCE_ID_BA);
+ }
+}
--- /dev/null
+package org.opendaylight.controller.sal.binding.test.connect.dom;
+
+import java.math.BigInteger;
+import java.util.Collections;
+import java.util.concurrent.Future;
+
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Test;
+import org.opendaylight.controller.sal.binding.api.BindingAwareBroker.RoutedRpcRegistration;
+import org.opendaylight.controller.sal.binding.api.RpcProviderRegistry;
+import org.opendaylight.controller.sal.binding.test.util.BindingBrokerTestFactory;
+import org.opendaylight.controller.sal.binding.test.util.BindingTestContext;
+import org.opendaylight.controller.sal.common.util.Rpcs;
+import org.opendaylight.controller.sal.core.api.RpcImplementation;
+import org.opendaylight.controller.sal.core.api.RpcProvisionRegistry;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.service.rev130819.AddFlowInput;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.service.rev130819.AddFlowInputBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.service.rev130819.AddFlowOutput;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.service.rev130819.AddFlowOutputBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.service.rev130819.NodeFlowRemoved;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.service.rev130819.RemoveFlowInput;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.service.rev130819.RemoveFlowOutput;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.service.rev130819.SalFlowService;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.service.rev130819.UpdateFlowInput;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.service.rev130819.UpdateFlowOutput;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.transaction.rev131103.TransactionId;
+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.inventory.rev130819.NodeContext;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.NodeId;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.NodeRef;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.Nodes;
+import org.opendaylight.yangtools.yang.binding.BaseIdentity;
+import org.opendaylight.yangtools.yang.binding.DataObject;
+import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
+import org.opendaylight.yangtools.yang.common.QName;
+import org.opendaylight.yangtools.yang.common.RpcError;
+import org.opendaylight.yangtools.yang.common.RpcResult;
+import org.opendaylight.yangtools.yang.data.api.CompositeNode;
+import org.opendaylight.yangtools.yang.data.impl.CompositeNodeTOImpl;
+
+import static junit.framework.Assert.*;
+
+import com.google.common.collect.HashMultimap;
+import com.google.common.collect.ImmutableList;
+import com.google.common.collect.Multimap;
+import com.google.common.util.concurrent.Futures;
+import com.google.common.util.concurrent.MoreExecutors;
+
+public class CrossBrokerRpcTest {
+
+ protected RpcProviderRegistry baRpcRegistry;
+ protected RpcProvisionRegistry biRpcRegistry;
+ private BindingTestContext testContext;
+ private RpcImplementation biRpcInvoker;
+ private MessageCapturingFlowService flowService;
+
+ public static final NodeId NODE_A = new NodeId("a");
+ public static final NodeId NODE_B = new NodeId("b");
+ public static final NodeId NODE_C = new NodeId("c");
+ public static final NodeId NODE_D = new NodeId("d");
+
+ public static final InstanceIdentifier<Node> BA_NODE_A_ID = createBANodeIdentifier(NODE_A);
+ public static final InstanceIdentifier<Node> BA_NODE_B_ID = createBANodeIdentifier(NODE_B);
+ public static final InstanceIdentifier<Node> BA_NODE_C_ID = createBANodeIdentifier(NODE_C);
+ public static final InstanceIdentifier<Node> BA_NODE_D_ID = createBANodeIdentifier(NODE_D);
+
+ public static final org.opendaylight.yangtools.yang.data.api.InstanceIdentifier BI_NODE_A_ID = createBINodeIdentifier(NODE_A);
+ public static final org.opendaylight.yangtools.yang.data.api.InstanceIdentifier BI_NODE_B_ID = createBINodeIdentifier(NODE_B);
+ public static final org.opendaylight.yangtools.yang.data.api.InstanceIdentifier BI_NODE_C_ID = createBINodeIdentifier(NODE_C);
+ public static final org.opendaylight.yangtools.yang.data.api.InstanceIdentifier BI_NODE_D_ID = createBINodeIdentifier(NODE_D);
+
+ private static final QName NODE_ID_QNAME = QName.create(Node.QNAME, "id");
+ private static final QName ADD_FLOW_QNAME = QName.create(NodeFlowRemoved.QNAME, "add-flow");
+ private static final QName REMOVE_FLOW_QNAME = QName.create(NodeFlowRemoved.QNAME, "remove-flow");
+ private static final QName UPDATE_FLOW_QNAME = QName.create(NodeFlowRemoved.QNAME, "update-flow");
+
+ @Before
+ public void setup() {
+ BindingBrokerTestFactory testFactory = new BindingBrokerTestFactory();
+ testFactory.setExecutor(MoreExecutors.sameThreadExecutor());
+ testFactory.setStartWithParsedSchema(true);
+ testContext = testFactory.getTestContext();
+
+ testContext.start();
+ baRpcRegistry = testContext.getBindingRpcRegistry();
+ biRpcRegistry = testContext.getDomRpcRegistry();
+ biRpcInvoker = testContext.getDomRpcInvoker();
+ assertNotNull(baRpcRegistry);
+ assertNotNull(biRpcRegistry);
+
+ flowService = MessageCapturingFlowService.create(baRpcRegistry);
+
+ }
+
+ @Test
+ public void bindingRoutedRpcProvider_DomInvokerTest() {
+
+ flowService//
+ .registerPath(NodeContext.class, BA_NODE_A_ID) //
+ .registerPath(NodeContext.class, BA_NODE_B_ID) //
+ .setAddFlowResult(addFlowResult(true, 10));
+
+ SalFlowService baFlowInvoker = baRpcRegistry.getRpcService(SalFlowService.class);
+ assertNotSame(flowService, baFlowInvoker);
+
+ AddFlowInput addFlowA = addFlow(BA_NODE_A_ID) //
+ .setPriority(100).setBarrier(true).build();
+
+ CompositeNode addFlowDom = toDomRpc(ADD_FLOW_QNAME, addFlowA);
+ assertNotNull(addFlowDom);
+ RpcResult<CompositeNode> domResult = biRpcInvoker.invokeRpc(ADD_FLOW_QNAME, addFlowDom);
+ assertNotNull(domResult);
+ assertTrue("DOM result is successful.", domResult.isSuccessful());
+ assertTrue("Bidning Add Flow RPC was captured.", flowService.getReceivedAddFlows().containsKey(BA_NODE_A_ID));
+ assertEquals(addFlowA, flowService.getReceivedAddFlows().get(BA_NODE_A_ID).iterator().next());
+ }
+
+ public void bindingRpcInvoker_DomRoutedProviderTest() {
+
+ }
+
+ private CompositeNode toDomRpcInput(DataObject addFlowA) {
+ return testContext.getBindingToDomMappingService().toDataDom(addFlowA);
+ }
+
+ @After
+ public void teardown() throws Exception {
+ testContext.close();
+ }
+
+ private static InstanceIdentifier<Node> createBANodeIdentifier(NodeId node) {
+ return InstanceIdentifier.builder(Nodes.class).child(Node.class, new NodeKey(node)).toInstance();
+ }
+
+ private static org.opendaylight.yangtools.yang.data.api.InstanceIdentifier createBINodeIdentifier(NodeId node) {
+ return org.opendaylight.yangtools.yang.data.api.InstanceIdentifier.builder().node(Nodes.QNAME)
+ .nodeWithKey(Node.QNAME, NODE_ID_QNAME, node.getValue()).toInstance();
+ }
+
+ private Future<RpcResult<AddFlowOutput>> addFlowResult(boolean success, long xid) {
+ AddFlowOutput output = new AddFlowOutputBuilder() //
+ .setTransactionId(new TransactionId(BigInteger.valueOf(xid))).build();
+ RpcResult<AddFlowOutput> result = Rpcs.getRpcResult(success, output, ImmutableList.<RpcError> of());
+ return Futures.immediateFuture(result);
+ }
+
+ private static AddFlowInputBuilder addFlow(InstanceIdentifier<Node> nodeId) {
+ AddFlowInputBuilder builder = new AddFlowInputBuilder();
+ builder.setNode(new NodeRef(nodeId));
+ return builder;
+ }
+
+ private CompositeNode toDomRpc(QName rpcName, AddFlowInput addFlowA) {
+ return new CompositeNodeTOImpl(rpcName, null,
+ Collections.<org.opendaylight.yangtools.yang.data.api.Node<?>> singletonList(toDomRpcInput(addFlowA)));
+ }
+}
--- /dev/null
+package org.opendaylight.controller.sal.binding.test.connect.dom;
+
+import static junit.framework.Assert.assertNotNull;
+
+import java.util.concurrent.Future;
+
+import org.opendaylight.controller.sal.binding.api.RpcProviderRegistry;
+import org.opendaylight.controller.sal.binding.api.BindingAwareBroker.RoutedRpcRegistration;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.service.rev130819.AddFlowInput;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.service.rev130819.AddFlowOutput;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.service.rev130819.RemoveFlowInput;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.service.rev130819.RemoveFlowOutput;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.service.rev130819.SalFlowService;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.service.rev130819.UpdateFlowInput;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.service.rev130819.UpdateFlowOutput;
+import org.opendaylight.yangtools.yang.binding.BaseIdentity;
+import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
+import org.opendaylight.yangtools.yang.common.RpcResult;
+
+import com.google.common.collect.HashMultimap;
+import com.google.common.collect.Multimap;
+
+public class MessageCapturingFlowService implements SalFlowService, AutoCloseable {
+
+ private Future<RpcResult<AddFlowOutput>> addFlowResult;
+ private Future<RpcResult<RemoveFlowOutput>> removeFlowResult;
+ private Future<RpcResult<UpdateFlowOutput>> updateFlowResult;
+
+ private final Multimap<InstanceIdentifier<?>, AddFlowInput> receivedAddFlows = HashMultimap.create();
+ private final Multimap<InstanceIdentifier<?>, RemoveFlowInput> receivedRemoveFlows = HashMultimap.create();
+ private final Multimap<InstanceIdentifier<?>, UpdateFlowInput> receivedUpdateFlows = HashMultimap.create();
+ private RoutedRpcRegistration<SalFlowService> registration;
+
+ @Override
+ public Future<RpcResult<AddFlowOutput>> addFlow(AddFlowInput arg0) {
+ receivedAddFlows.put(arg0.getNode().getValue(), arg0);
+ return addFlowResult;
+ }
+
+ @Override
+ public Future<RpcResult<RemoveFlowOutput>> removeFlow(RemoveFlowInput arg0) {
+ receivedRemoveFlows.put(arg0.getNode().getValue(), arg0);
+ return removeFlowResult;
+ }
+
+ @Override
+ public Future<RpcResult<UpdateFlowOutput>> updateFlow(UpdateFlowInput arg0) {
+ receivedUpdateFlows.put(arg0.getNode().getValue(), arg0);
+ return updateFlowResult;
+ }
+
+ public Future<RpcResult<AddFlowOutput>> getAddFlowResult() {
+ return addFlowResult;
+ }
+
+ public MessageCapturingFlowService setAddFlowResult(Future<RpcResult<AddFlowOutput>> addFlowResult) {
+ this.addFlowResult = addFlowResult;
+ return this;
+ }
+
+ public Future<RpcResult<RemoveFlowOutput>> getRemoveFlowResult() {
+ return removeFlowResult;
+ }
+
+ public MessageCapturingFlowService setRemoveFlowResult(Future<RpcResult<RemoveFlowOutput>> removeFlowResult) {
+ this.removeFlowResult = removeFlowResult;
+ return this;
+ }
+
+ public Future<RpcResult<UpdateFlowOutput>> getUpdateFlowResult() {
+ return updateFlowResult;
+ }
+
+ public MessageCapturingFlowService setUpdateFlowResult(Future<RpcResult<UpdateFlowOutput>> updateFlowResult) {
+ this.updateFlowResult = updateFlowResult;
+ return this;
+ }
+
+ public Multimap<InstanceIdentifier<?>, AddFlowInput> getReceivedAddFlows() {
+ return receivedAddFlows;
+ }
+
+ public Multimap<InstanceIdentifier<?>, RemoveFlowInput> getReceivedRemoveFlows() {
+ return receivedRemoveFlows;
+ }
+
+ public Multimap<InstanceIdentifier<?>, UpdateFlowInput> getReceivedUpdateFlows() {
+ return receivedUpdateFlows;
+ }
+
+ public MessageCapturingFlowService registerTo(RpcProviderRegistry registry) {
+ registration = registry.addRoutedRpcImplementation(SalFlowService.class, this);
+ assertNotNull(registration);
+ return this;
+ }
+
+ public void close() throws Exception {
+ registration.close();
+ }
+
+ public MessageCapturingFlowService registerPath(Class<? extends BaseIdentity> context, InstanceIdentifier<?> path) {
+ registration.registerPath(context, path);
+ return this;
+ }
+
+ public MessageCapturingFlowService unregisterPath(Class<? extends BaseIdentity> context, InstanceIdentifier<?> path) {
+ registration.unregisterPath(context, path);
+ return this;
+ }
+
+ public static MessageCapturingFlowService create() {
+ return new MessageCapturingFlowService();
+ }
+
+ public static MessageCapturingFlowService create(RpcProviderRegistry registry) {
+ MessageCapturingFlowService ret = new MessageCapturingFlowService();
+ ret.registerTo(registry);
+ return ret;
+ }
+
+
+}
\ No newline at end of file
mavenBundle(CONTROLLER, "config-persister-api").versionAsInProject(), //
mavenBundle(CONTROLLER, "netconf-api").versionAsInProject(), //
mavenBundle(CONTROLLER, "ietf-netconf-monitoring").versionAsInProject(), //
+ mavenBundle(CONTROLLER, "ietf-netconf-monitoring-extension").versionAsInProject(), //
mavenBundle(CONTROLLER, "netconf-monitoring").versionAsInProject(), //
mavenBundle(CONTROLLER, "netconf-client").versionAsInProject(), //
public interface RouteChangePublisher<C,P> {
- ListenerRegistration<RouteChangeListener<C,P>> registerRouteChangeListener(RouteChangeListener<C,P> listener);
+ <L extends RouteChangeListener<C,P>> ListenerRegistration<L> registerRouteChangeListener(L listener);
}
--- /dev/null
+package org.opendaylight.controller.md.sal.common.impl.routing;
+
+import java.util.Map;
+import java.util.Set;
+
+import org.opendaylight.controller.md.sal.common.api.routing.RouteChange;
+
+import com.google.common.collect.ImmutableMap;
+import com.google.common.collect.ImmutableSet;
+
+public class RoutingUtils {
+
+ public static <C,P> RouteChange<C,P> removalChange(C context,P path) {
+ final ImmutableMap<C, Set<P>> announcements = ImmutableMap.<C,Set<P>>of();
+ final ImmutableMap<C, Set<P>> removals = ImmutableMap.<C,Set<P>>of(context, ImmutableSet.of(path));
+ return new RouteChangeImpl<C,P>(announcements, removals);
+ }
+
+ public static <C,P> RouteChange<C,P> announcementChange(C context,P path) {
+ final ImmutableMap<C, Set<P>> announcements = ImmutableMap.<C,Set<P>>of(context, ImmutableSet.of(path));
+ final ImmutableMap<C, Set<P>> removals = ImmutableMap.<C,Set<P>>of();
+ return new RouteChangeImpl<C,P>(announcements, removals);
+ }
+
+
+ public static <C,P> RouteChange<C,P> change(Map<C, Set<P>> announcements,
+ Map<C, Set<P>> removals) {
+ final ImmutableMap<C, Set<P>> immutableAnnouncements = ImmutableMap.<C,Set<P>>copyOf(announcements);
+ final ImmutableMap<C, Set<P>> immutableRemovals = ImmutableMap.<C,Set<P>>copyOf(removals);
+ return new RouteChangeImpl<C,P>(immutableAnnouncements, immutableRemovals);
+ }
+
+
+ private static class RouteChangeImpl<C,P> implements RouteChange<C, P> {
+ private final Map<C, Set<P>> removal;
+ private final Map<C, Set<P>> announcement;
+
+ public RouteChangeImpl(ImmutableMap<C, Set<P>> removal, ImmutableMap<C, Set<P>> announcement) {
+ super();
+ this.removal = removal;
+ this.announcement = announcement;
+ }
+
+ @Override
+ public Map<C, Set<P>> getAnnouncements() {
+ return announcement;
+ }
+
+ @Override
+ public Map<C, Set<P>> getRemovals() {
+ return removal;
+ }
+
+ @Override
+ public int hashCode() {
+ final int prime = 31;
+ int result = 1;
+ result = prime * result + ((announcement == null) ? 0 : announcement.hashCode());
+ result = prime * result + ((removal == null) ? 0 : removal.hashCode());
+ return result;
+ }
+
+ @Override
+ public boolean equals(Object obj) {
+ if (this == obj) {
+ return true;
+ }
+ if (obj == null) {
+ return false;
+ }
+ if (getClass() != obj.getClass()) {
+ return false;
+ }
+ RouteChangeImpl other = (RouteChangeImpl) obj;
+ if (announcement == null) {
+ if (other.announcement != null)
+ return false;
+ } else if (!announcement.equals(other.announcement))
+ return false;
+ if (removal == null) {
+ if (other.removal != null) {
+ return false;
+ }
+ } else if (!removal.equals(other.removal))
+ return false;
+ return true;
+ }
+ }
+
+
+
+}
<artifactId>concepts</artifactId>
<version>0.1.1-SNAPSHOT</version>
</dependency>
+ <dependency>
+ <groupId>com.google.guava</groupId>
+ <artifactId>guava</artifactId>
+ </dependency>
</dependencies>
<packaging>bundle</packaging>
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
+
+import org.opendaylight.yangtools.concepts.Immutable;
import org.opendaylight.yangtools.yang.common.RpcError;
import org.opendaylight.yangtools.yang.common.RpcResult;
+import com.google.common.collect.ImmutableList;
+
public class Rpcs {
+
+ public static <T> RpcResult<T> getRpcResult(boolean successful) {
+ RpcResult<T> ret = new RpcResultTO<T>(successful, null, ImmutableList.<RpcError>of());
+ return ret;
+ }
+
public static <T> RpcResult<T> getRpcResult(boolean successful, T result,
Collection<RpcError> errors) {
RpcResult<T> ret = new RpcResultTO<T>(successful, result, errors);
return ret;
}
- private static class RpcResultTO<T> implements RpcResult<T>, Serializable {
+ public static <T> RpcResult<T> getRpcResult(boolean successful, Collection<RpcError> errors) {
+ return new RpcResultTO<T>(successful, null, errors);
+ }
+
+ private static class RpcResultTO<T> implements RpcResult<T>, Serializable, Immutable {
private final Collection<RpcError> errors;
private final T result;
Collection<RpcError> errors) {
this.successful = successful;
this.result = result;
- this.errors = Collections.unmodifiableList(new ArrayList<RpcError>(
- errors));
+ this.errors = ImmutableList.copyOf(errors);
}
@Override
import org.opendaylight.controller.sal.dom.broker.spi.RpcRouter
import org.opendaylight.yangtools.concepts.ListenerRegistration
import org.opendaylight.controller.sal.core.api.RpcRegistrationListener
+import org.opendaylight.controller.sal.core.api.RpcProvisionRegistry
+import org.opendaylight.controller.sal.core.api.RpcImplementation
-public class BrokerImpl implements Broker, AutoCloseable {
+public class BrokerImpl implements Broker, RpcProvisionRegistry, AutoCloseable {
private static val log = LoggerFactory.getLogger(BrokerImpl);
// Broker Generic Context
deactivator?.close();
}
+ override addRpcImplementation(QName rpcType, RpcImplementation implementation) throws IllegalArgumentException {
+ router.addRpcImplementation(rpcType,implementation);
+ }
+
+ override addRoutedRpcImplementation(QName rpcType, RpcImplementation implementation) {
+ router.addRoutedRpcImplementation(rpcType,implementation);
+ }
+
}
import org.opendaylight.controller.sal.core.api.RpcRegistrationListener
import org.slf4j.LoggerFactory
import org.opendaylight.yangtools.concepts.util.ListenerRegistry
+import org.opendaylight.controller.sal.core.api.Broker.RoutedRpcRegistration
+import org.opendaylight.yangtools.yang.data.api.InstanceIdentifier
class RpcRouterImpl implements RpcRouter, Identifiable<String> {
}
override addRoutedRpcImplementation(QName rpcType, RpcImplementation implementation) {
+ checkNotNull(rpcType, "Rpc Type should not be null");
+ checkNotNull(implementation, "Implementation should not be null.");
+ val reg = new RoutedRpcRegistrationImpl(rpcType, implementation, this);
+ implementations.put(rpcType, reg)
+
+ for (listener : rpcRegistrationListeners.listeners) {
+ try {
+ listener.instance.onRpcImplementationAdded(rpcType);
+ } catch (Exception e) {
+ log.error("Unhandled exception during invoking listener", e);
+ }
+ }
+
+ return reg;
}
override addRpcImplementation(QName rpcType, RpcImplementation implementation) throws IllegalArgumentException {
override protected removeRegistration() {
router.remove(this);
}
+}
+class RoutedRpcRegistrationImpl extends RpcRegistrationImpl implements RoutedRpcRegistration {
+
+
+ new(QName type, RpcImplementation instance, RpcRouterImpl router) {
+ super(type,instance,router)
+ }
+ override protected removeRegistration() {
+ router.remove(this);
+ }
+ override registerPath(QName context, InstanceIdentifier path) {
+ //
+
+ }
+
+ override unregisterPath(QName context, InstanceIdentifier path) {
+ //
+ }
}
this.schema = null;
}
- protected CompositeNode mergeData(InstanceIdentifier path, CompositeNode stored, CompositeNode modified, boolean config) {
+ protected CompositeNode mergeData(InstanceIdentifier path, CompositeNode stored, CompositeNode modified,
+ boolean config) {
long startTime = System.nanoTime();
try {
- DataSchemaNode node = schemaNodeFor(path);
- return YangDataOperations.merge(node,stored,modified,config);
+ DataSchemaNode node = schemaNodeFor(path);
+ return YangDataOperations.merge(node, stored, modified, config);
} finally {
- //System.out.println("Merge time: " + ((System.nanoTime() - startTime) / 1000.0d));
+ // System.out.println("Merge time: " + ((System.nanoTime() -
+ // startTime) / 1000.0d));
}
}
-
-
+
private DataSchemaNode schemaNodeFor(InstanceIdentifier path) {
- checkState(schema != null,"YANG Schema is not available");
+ checkState(schema != null, "YANG Schema is not available");
return YangSchemaUtils.getSchemaNode(schema, path);
}
DataModification<InstanceIdentifier, CompositeNode> original) {
// NOOP for now
NormalizedDataModification normalized = new NormalizedDataModification(original);
- for (Entry<InstanceIdentifier,CompositeNode> entry : original.getUpdatedConfigurationData().entrySet()) {
+ for (Entry<InstanceIdentifier, CompositeNode> entry : original.getUpdatedConfigurationData().entrySet()) {
normalized.putConfigurationData(entry.getKey(), entry.getValue());
}
- for (Entry<InstanceIdentifier,CompositeNode> entry : original.getUpdatedOperationalData().entrySet()) {
+ for (Entry<InstanceIdentifier, CompositeNode> entry : original.getUpdatedOperationalData().entrySet()) {
normalized.putOperationalData(entry.getKey(), entry.getValue());
}
for (InstanceIdentifier entry : original.getRemovedConfigurationData()) {
normalized.removeConfigurationData(entry);
}
- for(InstanceIdentifier entry : original.getRemovedOperationalData()) {
+ for (InstanceIdentifier entry : original.getRemovedOperationalData()) {
normalized.removeOperationalData(entry);
}
return normalized;
}
}
}
-
+
private class NormalizedDataModification extends AbstractDataModification<InstanceIdentifier, CompositeNode> {
private Object identifier;
identifier = original;
status = TransactionStatus.NEW;
}
-
+
@Override
public Object getIdentifier() {
return this.identifier;
}
-
+
@Override
public TransactionStatus getStatus() {
return status;
public Future<RpcResult<TransactionStatus>> commit() {
throw new UnsupportedOperationException("Commit should not be invoked on this");
}
-
+
@Override
- protected CompositeNode mergeConfigurationData(InstanceIdentifier path,CompositeNode stored, CompositeNode modified) {
- return mergeData(path,stored, modified,true);
+ protected CompositeNode mergeConfigurationData(InstanceIdentifier path, CompositeNode stored,
+ CompositeNode modified) {
+ return mergeData(path, stored, modified, true);
}
-
+
@Override
- protected CompositeNode mergeOperationalData(InstanceIdentifier path,CompositeNode stored, CompositeNode modified) {
+ protected CompositeNode mergeOperationalData(InstanceIdentifier path, CompositeNode stored,
+ CompositeNode modified) {
// TODO Auto-generated method stub
- return mergeData(path,stored,modified,false);
+ return mergeData(path, stored, modified, false);
}
-
}
}
checkArgument(!iterator.hasNext(), "Path nests inside leaf node, which is not allowed.");
return currentNode;
}
+ checkState(currentNode != null, "Current node should not be null for %s",path);
}
+ checkState(previous instanceof DataSchemaNode, "Schema node for %s should be instance of DataSchemaNode. Found %s",path,previous);
return (DataSchemaNode) previous;
}
-
private static DataSchemaNode searchInChoices(DataNodeContainer node, QName arg) {
Set<DataSchemaNode> children = node.getChildNodes();
</dependency>
<dependency>
<groupId>org.opendaylight.controller</groupId>
- <artifactId>zeromq-routingtable.implementation</artifactId>
+ <artifactId>remoterpc-routingtable.implementation</artifactId>
<!-- TODO: fix the version. Why is it not MD Sal project version?-->
<version>0.4.1-SNAPSHOT</version>
</dependency>
</dependency>
<dependency>
<groupId>org.opendaylight.controller</groupId>
- <artifactId>zeromq-routingtable.implementation</artifactId>
+ <artifactId>remoterpc-routingtable.implementation</artifactId>
<version>0.4.1-SNAPSHOT</version>
</dependency>
<dependency>
import static com.google.common.base.Preconditions.checkNotNull;
import java.io.IOException;
-import java.util.*;
+import java.net.URI;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Set;
import javax.activation.UnsupportedDataTypeException;
import org.opendaylight.controller.sal.restconf.impl.ControllerContext;
+import org.opendaylight.controller.sal.restconf.impl.IdentityValuesDTO;
+import org.opendaylight.controller.sal.restconf.impl.IdentityValuesDTO.IdentityValue;
+import org.opendaylight.controller.sal.restconf.impl.RestCodec;
import org.opendaylight.yangtools.yang.common.QName;
-import org.opendaylight.yangtools.yang.data.api.*;
-import org.opendaylight.yangtools.yang.model.api.*;
-import org.opendaylight.yangtools.yang.model.api.type.*;
+import org.opendaylight.yangtools.yang.data.api.CompositeNode;
+import org.opendaylight.yangtools.yang.data.api.Node;
+import org.opendaylight.yangtools.yang.data.api.SimpleNode;
+import org.opendaylight.yangtools.yang.model.api.ChoiceCaseNode;
+import org.opendaylight.yangtools.yang.model.api.ChoiceNode;
+import org.opendaylight.yangtools.yang.model.api.ContainerSchemaNode;
+import org.opendaylight.yangtools.yang.model.api.DataNodeContainer;
+import org.opendaylight.yangtools.yang.model.api.DataSchemaNode;
+import org.opendaylight.yangtools.yang.model.api.LeafListSchemaNode;
+import org.opendaylight.yangtools.yang.model.api.LeafSchemaNode;
+import org.opendaylight.yangtools.yang.model.api.ListSchemaNode;
+import org.opendaylight.yangtools.yang.model.api.TypeDefinition;
+import org.opendaylight.yangtools.yang.model.api.type.BooleanTypeDefinition;
+import org.opendaylight.yangtools.yang.model.api.type.DecimalTypeDefinition;
+import org.opendaylight.yangtools.yang.model.api.type.EmptyTypeDefinition;
+import org.opendaylight.yangtools.yang.model.api.type.IdentityrefTypeDefinition;
+import org.opendaylight.yangtools.yang.model.api.type.IntegerTypeDefinition;
+import org.opendaylight.yangtools.yang.model.api.type.UnsignedIntegerTypeDefinition;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
import com.google.common.base.Preconditions;
import com.google.gson.stream.JsonWriter;
private final Set<LeafListSchemaNode> foundLeafLists = new HashSet<>();
private final Set<ListSchemaNode> foundLists = new HashSet<>();
+ private final Logger logger = LoggerFactory.getLogger(JsonMapper.class);
public void write(JsonWriter writer, CompositeNode data, DataNodeContainer schema) throws IOException {
Preconditions.checkNotNull(writer);
private void writeValueOfNodeByType(JsonWriter writer, SimpleNode<?> node, TypeDefinition<?> type,
DataSchemaNode schema) throws IOException {
- String value = String.valueOf(node.getValue());
- TypeDefinition<?> baseType = resolveBaseTypeFrom(type);
+ TypeDefinition<?> baseType = RestUtil.resolveBaseTypeFrom(type);
- // TODO check InstanceIdentifierTypeDefinition,
- // IdentityrefTypeDefinition
+ // TODO check InstanceIdentifierTypeDefinition
if (baseType instanceof IdentityrefTypeDefinition) {
if (node.getValue() instanceof QName) {
- QName qName = (QName) node.getValue();
-
- ControllerContext contContext = ControllerContext.getInstance();
- String moduleName = contContext.findModuleByNamespace(qName.getNamespace());
-
- writer.value(moduleName + ":" + qName.getLocalName());
- }
-
- } else if (baseType instanceof LeafrefTypeDefinition) {
- ControllerContext contContext = ControllerContext.getInstance();
- LeafSchemaNode lfSchemaNode = contContext.resolveTypeFromLeafref((LeafrefTypeDefinition) baseType, schema);
- if (lfSchemaNode != null) {
- writeValueOfNodeByType(writer, node, lfSchemaNode.getType(), lfSchemaNode);
+ IdentityValuesDTO valueDTO = (IdentityValuesDTO) RestCodec.from(baseType).serialize(node.getValue());
+ IdentityValue valueFromDTO = valueDTO.getValuesWithNamespaces().get(0);
+ String moduleName = ControllerContext.getInstance().findModuleByNamespace(URI.create(valueFromDTO.getNamespace()));
+ writer.value(moduleName + ":" + valueFromDTO.getValue());
} else {
- writer.value(value);
+ logger.debug("Value of " + baseType.getQName().getNamespace() + ":"
+ + baseType.getQName().getLocalName() + " is not instance of " + QName.class + " but is " + node.getValue().getClass());
+ writer.value(String.valueOf(node.getValue()));
}
- } else if (baseType instanceof InstanceIdentifierTypeDefinition) {
- writer.value(((InstanceIdentifierTypeDefinition) baseType).getPathStatement().toString());
- } else if (baseType instanceof UnionTypeDefinition) {
- processTypeIsUnionType(writer, (UnionTypeDefinition) baseType, value);
} else if (baseType instanceof DecimalTypeDefinition || baseType instanceof IntegerTypeDefinition
|| baseType instanceof UnsignedIntegerTypeDefinition) {
- writer.value(new NumberForJsonWriter(value));
+ writer.value(new NumberForJsonWriter((String) RestCodec.from(baseType).serialize(node.getValue())));
} else if (baseType instanceof BooleanTypeDefinition) {
- writer.value(Boolean.parseBoolean(value));
+ writer.value(Boolean.parseBoolean((String) RestCodec.from(baseType).serialize(node.getValue())));
} else if (baseType instanceof EmptyTypeDefinition) {
writeEmptyDataTypeToJson(writer);
} else {
+ String value = String.valueOf(RestCodec.from(baseType).serialize(node.getValue()));
+ if (value == null) {
+ value = String.valueOf(node.getValue());
+ }
writer.value(value.equals("null") ? "" : value);
}
}
- private void processTypeIsUnionType(JsonWriter writer, UnionTypeDefinition unionType, String value)
- throws IOException {
- if (value == null) {
- writeEmptyDataTypeToJson(writer);
- } else if ((isNumber(value))
- && containsType(unionType, UnsignedIntegerTypeDefinition.class, IntegerTypeDefinition.class,
- DecimalTypeDefinition.class)) {
- writer.value(new NumberForJsonWriter(value));
- } else if (isBoolean(value) && containsType(unionType, BooleanTypeDefinition.class)) {
- writer.value(Boolean.parseBoolean(value));
- } else {
- writer.value(value);
- }
- }
-
- private boolean isBoolean(String value) {
- if (value.equals("true") || value.equals("false")) {
- return true;
- }
- return false;
- }
-
private void writeEmptyDataTypeToJson(JsonWriter writer) throws IOException {
writer.beginArray();
writer.nullValue();
writer.endArray();
}
- private boolean isNumber(String value) {
- try {
- Double.valueOf(value);
- } catch (NumberFormatException e) {
- return false;
- }
- return true;
- }
-
- private boolean containsType(UnionTypeDefinition unionType, Class<?>... searchedTypes) {
- List<TypeDefinition<?>> allUnionSubtypes = resolveAllUnionSubtypesFrom(unionType);
-
- for (TypeDefinition<?> unionSubtype : allUnionSubtypes) {
- for (Class<?> searchedType : searchedTypes) {
- if (searchedType.isInstance(unionSubtype)) {
- return true;
- }
- }
- }
- return false;
- }
-
- private List<TypeDefinition<?>> resolveAllUnionSubtypesFrom(UnionTypeDefinition inputType) {
- List<TypeDefinition<?>> result = new ArrayList<>();
- for (TypeDefinition<?> subtype : inputType.getTypes()) {
- TypeDefinition<?> resolvedSubtype = subtype;
-
- resolvedSubtype = resolveBaseTypeFrom(subtype);
-
- if (resolvedSubtype instanceof UnionTypeDefinition) {
- List<TypeDefinition<?>> subtypesFromRecursion = resolveAllUnionSubtypesFrom((UnionTypeDefinition) resolvedSubtype);
- result.addAll(subtypesFromRecursion);
- } else {
- result.add(resolvedSubtype);
- }
- }
-
- return result;
- }
-
- private TypeDefinition<?> resolveBaseTypeFrom(TypeDefinition<?> type) {
- return type.getBaseType() != null ? resolveBaseTypeFrom(type.getBaseType()) : type;
- }
-
private void writeName(Node<?> node, DataSchemaNode schema, JsonWriter writer) throws IOException {
String nameForOutput = node.getNodeType().getLocalName();
if (schema.isAugmenting()) {
import org.opendaylight.controller.sal.restconf.impl.CompositeNodeWrapper;
import org.opendaylight.controller.sal.restconf.impl.EmptyNodeWrapper;
import org.opendaylight.controller.sal.restconf.impl.SimpleNodeWrapper;
+import org.opendaylight.controller.sal.restconf.impl.IdentityValuesDTO;
import com.google.common.collect.Lists;
import com.google.gson.JsonElement;
}
private CompositeNodeWrapper createStructureWithRoot(String rootObjectName, JsonObject rootObject) {
- CompositeNodeWrapper firstNode = new CompositeNodeWrapper(getNamespaceFrom(rootObjectName),
- getLocalNameFrom(rootObjectName));
+ CompositeNodeWrapper firstNode = new CompositeNodeWrapper(getNamespaceFor(rootObjectName),
+ getLocalNameFor(rootObjectName));
for (Entry<String, JsonElement> childOfFirstNode : rootObject.entrySet()) {
addChildToParent(childOfFirstNode.getKey(), childOfFirstNode.getValue(), firstNode);
}
private void addChildToParent(String childName, JsonElement childType, CompositeNodeWrapper parent) {
if (childType.isJsonObject()) {
- CompositeNodeWrapper child = new CompositeNodeWrapper(getNamespaceFrom(childName),
- getLocalNameFrom(childName));
+ CompositeNodeWrapper child = new CompositeNodeWrapper(getNamespaceFor(childName),
+ getLocalNameFor(childName));
parent.addValue(child);
for (Entry<String, JsonElement> childOfChild : childType.getAsJsonObject().entrySet()) {
addChildToParent(childOfChild.getKey(), childOfChild.getValue(), child);
}
} else if (childType.isJsonArray()) {
if (childType.getAsJsonArray().size() == 1 && childType.getAsJsonArray().get(0).isJsonNull()) {
- parent.addValue(new EmptyNodeWrapper(getNamespaceFrom(childName), getLocalNameFrom(childName)));
+ parent.addValue(new EmptyNodeWrapper(getNamespaceFor(childName), getLocalNameFor(childName)));
} else {
for (JsonElement childOfChildType : childType.getAsJsonArray()) {
} else if (childType.isJsonPrimitive()) {
JsonPrimitive childPrimitive = childType.getAsJsonPrimitive();
String value = childPrimitive.getAsString();
- parent.addValue(new SimpleNodeWrapper(getNamespaceFrom(childName), getLocalNameFrom(childName), value));
+ parent.addValue(new SimpleNodeWrapper(getNamespaceFor(childName), getLocalNameFor(childName),
+ resolveValueOfElement(value)));
}
}
- private URI getNamespaceFrom(String jsonElementName) {
- int indexOfDelimeter = jsonElementName.lastIndexOf(':');
- if (indexOfDelimeter == -1) {
+ private URI getNamespaceFor(String jsonElementName) {
+ String[] moduleNameAndLocalName = jsonElementName.split(":");
+ if (moduleNameAndLocalName.length != 2) { // it is not "moduleName:localName"
return null;
}
- return URI.create(jsonElementName.substring(0, indexOfDelimeter));
+ return URI.create(moduleNameAndLocalName[0]);
}
- private String getLocalNameFrom(String jsonElementName) {
- int indexOfDelimeter = jsonElementName.lastIndexOf(':');
- if (indexOfDelimeter == -1) {
+ private String getLocalNameFor(String jsonElementName) {
+ String[] moduleNameAndLocalName = jsonElementName.split(":");
+ if (moduleNameAndLocalName.length != 2) { // it is not "moduleName:localName"
return jsonElementName;
}
- return jsonElementName.substring(indexOfDelimeter + 1, jsonElementName.length());
+ return moduleNameAndLocalName[1];
+ }
+
+ /**
+ * @param value
+ * value of json element
+ * @return if value is "moduleName:localName" then {@link IdentityValuesDTO} else
+ * the same string as parameter "value"
+ */
+ private Object resolveValueOfElement(String value) {
+ URI namespace = getNamespaceFor(value);
+ return namespace == null ? value : new IdentityValuesDTO(namespace.toString(), getLocalNameFor(value), null);
}
}
--- /dev/null
+package org.opendaylight.controller.sal.rest.impl;
+
+import org.opendaylight.yangtools.yang.model.api.TypeDefinition;
+
+public final class RestUtil {
+
+ public final static TypeDefinition<?> resolveBaseTypeFrom(TypeDefinition<?> type) {
+ TypeDefinition<?> superType = type;
+ while (superType.getBaseType() != null) {
+ superType = superType.getBaseType();
+ }
+ return superType;
+ }
+
+}
public class RestconfProvider implements BundleActivator, Provider, ServiceTrackerCustomizer<Broker, Broker> {
- public final static String NOT_INITALIZED_MSG = "Restcof is not initialized yet. Please try again later";
+ public final static String NOT_INITALIZED_MSG = "Restconf is not initialized yet. Please try again later";
private ListenerRegistration<SchemaServiceListener> listenerRegistration;
private ServiceTracker<Broker, Broker> brokerServiceTrancker;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.parsers.ParserConfigurationException;
+import org.opendaylight.controller.sal.restconf.impl.IdentityValuesDTO;
+import org.opendaylight.controller.sal.restconf.impl.IdentityValuesDTO.IdentityValue;
+import org.opendaylight.controller.sal.restconf.impl.RestCodec;
import org.opendaylight.yangtools.yang.common.QName;
import org.opendaylight.yangtools.yang.data.api.CompositeNode;
import org.opendaylight.yangtools.yang.data.api.Node;
Element itemEl = doc.createElementNS(dataType.getNamespace().toString(), dataType.getLocalName());
if (data instanceof SimpleNode<?>) {
if (schema instanceof LeafListSchemaNode) {
- writeValueOfNodeByType(itemEl, (SimpleNode<?>) data, ((LeafListSchemaNode) schema).getType());
+ writeValueOfNodeByType(itemEl, (SimpleNode<?>) data, ((LeafListSchemaNode) schema).getType(), (DataSchemaNode) schema);
} else if (schema instanceof LeafSchemaNode) {
- writeValueOfNodeByType(itemEl, (SimpleNode<?>) data, ((LeafSchemaNode) schema).getType());
+ writeValueOfNodeByType(itemEl, (SimpleNode<?>) data, ((LeafSchemaNode) schema).getType(), (DataSchemaNode) schema);
} else {
Object value = data.getValue();
if (value != null) {
return itemEl;
}
- private void writeValueOfNodeByType(Element element, SimpleNode<?> node, TypeDefinition<?> type) {
+ private void writeValueOfNodeByType(Element element, SimpleNode<?> node, TypeDefinition<?> type, DataSchemaNode schema) {
- TypeDefinition<?> baseType = resolveBaseTypeFrom(type);
+ TypeDefinition<?> baseType = RestUtil.resolveBaseTypeFrom(type);
- if (baseType instanceof IdentityrefTypeDefinition && node.getValue() instanceof QName) {
- QName value = (QName) node.getValue();
- element.setAttribute("xmlns:x", value.getNamespace().toString());
- element.setTextContent("x:" + value.getLocalName());
+ if (baseType instanceof IdentityrefTypeDefinition) {
+ if (node.getValue() instanceof QName) {
+ IdentityValuesDTO valueDTO = (IdentityValuesDTO) RestCodec.from(type).serialize(node.getValue());
+ IdentityValue value = valueDTO.getValuesWithNamespaces().get(0);
+ String prefix = "x";
+ if (value.getPrefix() != null && !value.getPrefix().isEmpty()) {
+ prefix = value.getPrefix();
+ }
+ element.setAttribute("xmlns:" + prefix, value.getNamespace());
+ element.setTextContent(prefix + ":" + value.getValue());
+ } else {
+ logger.debug("Value of " + baseType.getQName().getNamespace() + ":"
+ + baseType.getQName().getLocalName() + " is not instance of " + QName.class + " but is " + node.getValue().getClass());
+ element.setTextContent(String.valueOf(node.getValue()));
+ }
} else {
- Object value = node.getValue();
- if (value != null) {
- element.setTextContent(String.valueOf(value));
+ if (node.getValue() != null) {
+ String value = String.valueOf(RestCodec.from(baseType).serialize(node.getValue()));
+ if (value.equals("null")) {
+ value = String.valueOf(node.getValue());
+ }
+ element.setTextContent(value);
}
}
}
return null;
}
- private TypeDefinition<?> resolveBaseTypeFrom(TypeDefinition<?> type) {
- return type.getBaseType() != null ? resolveBaseTypeFrom(type.getBaseType()) : type;
- }
-
}
import javax.xml.stream.events.XMLEvent;
import org.opendaylight.controller.sal.restconf.impl.CompositeNodeWrapper;
+import org.opendaylight.controller.sal.restconf.impl.IdentityValuesDTO;
import org.opendaylight.controller.sal.restconf.impl.EmptyNodeWrapper;
import org.opendaylight.controller.sal.restconf.impl.NodeWrapper;
import org.opendaylight.controller.sal.restconf.impl.SimpleNodeWrapper;
return false;
}
+ private CompositeNodeWrapper resolveCompositeNodeFromStartElement(final StartElement startElement) {
+ checkArgument(startElement != null, "Start Element cannot be NULL!");
+ return new CompositeNodeWrapper(getNamespaceFor(startElement), getLocalNameFor(startElement));
+ }
+
private NodeWrapper<? extends Node<?>> resolveSimpleNodeFromStartElement(final StartElement startElement)
throws XMLStreamException {
checkArgument(startElement != null, "Start Element cannot be NULL!");
- String data = null;
+ String data = getValueOf(startElement);
+ if (data == null) {
+ return new EmptyNodeWrapper(getNamespaceFor(startElement), getLocalNameFor(startElement));
+ }
+ return new SimpleNodeWrapper(getNamespaceFor(startElement), getLocalNameFor(startElement),
+ resolveValueOfElement(data, startElement));
+ }
+ private String getValueOf(StartElement startElement) throws XMLStreamException {
+ String data = null;
if (eventReader.hasNext()) {
final XMLEvent innerEvent = eventReader.peek();
if (innerEvent.isCharacters()) {
}
}
}
- if(data == null) {
- return new EmptyNodeWrapper(getNamespaceFrom(startElement), getLocalNameFrom(startElement));
- }
- return new SimpleNodeWrapper(getNamespaceFrom(startElement), getLocalNameFrom(startElement), data);
+ return data;
}
- private CompositeNodeWrapper resolveCompositeNodeFromStartElement(final StartElement startElement) {
- checkArgument(startElement != null, "Start Element cannot be NULL!");
- return new CompositeNodeWrapper(getNamespaceFrom(startElement), getLocalNameFrom(startElement));
- }
-
- private String getLocalNameFrom(StartElement startElement) {
+ private String getLocalNameFor(StartElement startElement) {
return startElement.getName().getLocalPart();
}
- private URI getNamespaceFrom(StartElement startElement) {
+ private URI getNamespaceFor(StartElement startElement) {
String namespaceURI = startElement.getName().getNamespaceURI();
return namespaceURI.isEmpty() ? null : URI.create(namespaceURI);
}
+ /**
+ * @param value
+ * value of startElement
+ * @param startElement
+ * element containing value
+ * @return if value is "prefix:value" then {@link IdentityValuesDTO} else the same
+ * string as parameter "value"
+ */
+ private Object resolveValueOfElement(String value, StartElement startElement) {
+ String[] namespaceAndValue = value.split(":");
+ if (namespaceAndValue.length != 2) { // it is not "prefix:value"
+ return value;
+ }
+ String namespace = startElement.getNamespaceContext().getNamespaceURI(namespaceAndValue[0]);
+ if (namespace != null && !namespace.isEmpty()) {
+ return new IdentityValuesDTO(namespace, namespaceAndValue[1], namespaceAndValue[0]);
+ }
+ return value;
+ }
+
}
package org.opendaylight.controller.sal.restconf.impl
import com.google.common.collect.BiMap
+import com.google.common.collect.FluentIterable
import com.google.common.collect.HashBiMap
import java.net.URI
import java.net.URLDecoder
import java.util.concurrent.ConcurrentHashMap
import javax.ws.rs.core.Response
import org.opendaylight.controller.sal.core.api.model.SchemaServiceListener
+import org.opendaylight.controller.sal.rest.impl.RestUtil
import org.opendaylight.controller.sal.rest.impl.RestconfProvider
import org.opendaylight.yangtools.yang.common.QName
import org.opendaylight.yangtools.yang.data.api.InstanceIdentifier
import org.opendaylight.yangtools.yang.data.api.InstanceIdentifier.NodeIdentifier
import org.opendaylight.yangtools.yang.data.api.InstanceIdentifier.NodeIdentifierWithPredicates
import org.opendaylight.yangtools.yang.data.api.InstanceIdentifier.PathArgument
+import org.opendaylight.yangtools.yang.data.impl.codec.TypeDefinitionAwareCodec
import org.opendaylight.yangtools.yang.model.api.ChoiceCaseNode
import org.opendaylight.yangtools.yang.model.api.ChoiceNode
import org.opendaylight.yangtools.yang.model.api.ContainerSchemaNode
import org.opendaylight.yangtools.yang.model.api.ListSchemaNode
import org.opendaylight.yangtools.yang.model.api.RpcDefinition
import org.opendaylight.yangtools.yang.model.api.SchemaContext
-import org.opendaylight.yangtools.yang.model.api.SchemaNode
-import org.opendaylight.yangtools.yang.model.api.type.LeafrefTypeDefinition
-import org.opendaylight.yangtools.yang.model.util.SchemaContextUtil
+import org.opendaylight.yangtools.yang.model.api.type.IdentityrefTypeDefinition
+import org.slf4j.LoggerFactory
import static com.google.common.base.Preconditions.*
-import org.opendaylight.yangtools.yang.data.impl.codec.TypeDefinitionAwareCodec
-import org.opendaylight.yangtools.yang.model.api.type.IdentityrefTypeDefinition
class ControllerContext implements SchemaServiceListener {
-
+ val static LOG = LoggerFactory.getLogger(ControllerContext)
val static ControllerContext INSTANCE = new ControllerContext
-
val static NULL_VALUE = "null"
var SchemaContext schemas;
return getLatestModule(startModule)
}
- private def getLatestModule(String moduleName) {
+ def getLatestModule(String moduleName) {
checkPreconditions
checkArgument(moduleName !== null && !moduleName.empty)
val modules = schemas.modules.filter[m|m.name == moduleName]
var module = uriToModuleName.get(namespace)
if (module === null) {
val moduleSchemas = schemas.findModuleByNamespace(namespace);
- if(moduleSchemas === null) throw new IllegalArgumentException()
+ if(moduleSchemas === null) return null
var latestModule = moduleSchemas.head
for (m : moduleSchemas) {
if (m.revision.after(latestModule.revision)) {
latestModule = m
}
}
- if(latestModule === null) throw new IllegalArgumentException()
+ if(latestModule === null) return null
uriToModuleName.put(namespace, latestModule.name)
module = latestModule.name;
}
return module
}
+ def findNamespaceByModule(String module) {
+ var namespace = moduleNameToUri.get(module)
+ if (namespace === null) {
+ val moduleSchemas = schemas.modules.filter[it|it.name.equals(module)]
+ var latestModule = moduleSchemas.head
+ for (m : moduleSchemas) {
+ if (m.revision.after(latestModule.revision)) {
+ latestModule = m
+ }
+ }
+ if(latestModule === null) return null
+ namespace = latestModule.namespace
+ uriToModuleName.put(namespace, latestModule.name)
+ }
+ return namespace
+ }
+
def CharSequence toRestconfIdentifier(QName qname) {
checkPreconditions
var module = uriToModuleName.get(qname.namespace)
checkArgument(node instanceof LeafSchemaNode);
val urlDecoded = URLDecoder.decode(uriValue);
val typedef = (node as LeafSchemaNode).type;
+
var decoded = TypeDefinitionAwareCodec.from(typedef)?.deserialize(urlDecoded)
- if(decoded == null) {
- var baseType = typedef
- while (baseType.baseType != null) {
- baseType = baseType.baseType;
- }
+ if(decoded === null) {
+ var baseType = RestUtil.resolveBaseTypeFrom(typedef)
if(baseType instanceof IdentityrefTypeDefinition) {
decoded = toQName(urlDecoded)
}
private def QName toQName(String name) {
val module = name.toModuleName;
val node = name.toNodeName;
- val namespace = moduleNameToUri.get(module);
- return new QName(namespace, null, node);
+ val namespace = FluentIterable.from(schemas.modules.sort[o1,o2 | o1.revision.compareTo(o2.revision)]) //
+ .transform[QName.create(namespace,revision,it.name)].findFirst[module == localName]
+ ;
+ return QName.create(namespace,node);
}
def getRpcDefinition(String name) {
override onGlobalContextUpdated(SchemaContext context) {
this.schemas = context;
for (operation : context.operations) {
- val qname = new QName(operation.QName.namespace, null, operation.QName.localName);
+ val qname = operation.QName;
qnameToRpc.put(qname, operation);
}
}
- /**
- * Resolve target type from leafref type.
- *
- * According to RFC 6020 referenced element has to be leaf (chapter 9.9).
- * Therefore if other element is referenced then null value is returned.
- *
- * Currently only cases without path-predicate are supported.
- *
- * @param leafRef
- * @param schemaNode
- * data schema node which contains reference
- * @return type if leaf is referenced and it is possible to find referenced
- * node in schema context. In other cases null value is returned
- */
- def LeafSchemaNode resolveTypeFromLeafref(LeafrefTypeDefinition leafRef, DataSchemaNode schemaNode) {
- val xPath = leafRef.getPathStatement();
- val module = SchemaContextUtil.findParentModule(schemas, schemaNode);
-
- var SchemaNode foundSchemaNode
- if (xPath.isAbsolute()) {
- foundSchemaNode = SchemaContextUtil.findDataSchemaNode(schemas, module, xPath);
- } else {
- foundSchemaNode = SchemaContextUtil.findDataSchemaNodeForRelativeXPath(schemas, module, schemaNode, xPath);
- }
-
- if (foundSchemaNode instanceof LeafSchemaNode) {
- return foundSchemaNode as LeafSchemaNode;
- }
-
- return null;
- }
}
--- /dev/null
+package org.opendaylight.controller.sal.restconf.impl;
+
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.List;
+
+public final class IdentityValuesDTO {
+
+ private final List<IdentityValue> elementData = new ArrayList<>();
+
+ public IdentityValuesDTO(String namespace, String value, String prefix) {
+ elementData.add(new IdentityValue(namespace, value, prefix));
+ }
+
+ public void add(String namespace, String value, String prefix) {
+ elementData.add(new IdentityValue(namespace, value, prefix));
+ }
+
+ public List<IdentityValue> getValuesWithNamespaces() {
+ return Collections.unmodifiableList(elementData);
+ }
+
+ public static final class IdentityValue {
+
+ private String namespace;
+ private String value;
+ private String prefix;
+
+ public IdentityValue(String namespace, String value, String prefix) {
+ this.namespace = namespace;
+ this.value = value;
+ this.prefix = prefix;
+ }
+
+ public String getNamespace() {
+ return namespace;
+ }
+
+ public void setNamespace(String namespace) {
+ this.namespace = namespace;
+ }
+
+ public String getValue() {
+ return value;
+ }
+
+ public void setValue(String value) {
+ this.value = value;
+ }
+
+ public String getPrefix() {
+ return prefix;
+ }
+
+ public void setPrefix(String prefix) {
+ this.prefix = prefix;
+ }
+
+ }
+}
--- /dev/null
+package org.opendaylight.controller.sal.restconf.impl;
+
+import java.net.URI;
+
+import org.opendaylight.controller.sal.rest.impl.RestUtil;
+import org.opendaylight.controller.sal.restconf.impl.IdentityValuesDTO.IdentityValue;
+import org.opendaylight.yangtools.concepts.Codec;
+import org.opendaylight.yangtools.yang.common.QName;
+import org.opendaylight.yangtools.yang.data.api.codec.IdentityrefCodec;
+import org.opendaylight.yangtools.yang.data.api.codec.LeafrefCodec;
+import org.opendaylight.yangtools.yang.data.impl.codec.TypeDefinitionAwareCodec;
+import org.opendaylight.yangtools.yang.model.api.TypeDefinition;
+import org.opendaylight.yangtools.yang.model.api.type.IdentityrefTypeDefinition;
+import org.opendaylight.yangtools.yang.model.api.type.LeafrefTypeDefinition;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+public class RestCodec {
+
+ private RestCodec() {
+ }
+
+ public static final Codec<Object, Object> from(TypeDefinition<?> typeDefinition) {
+ return new ObjectCodec(typeDefinition);
+ }
+
+ @SuppressWarnings("rawtypes")
+ public static final class ObjectCodec implements Codec<Object, Object> {
+
+ private final Logger logger = LoggerFactory.getLogger(RestCodec.class);
+
+ public static final Codec IDENTITYREF_DEFAULT_CODEC = new IdentityrefCodecImpl();
+ public static final Codec LEAFREF_DEFAULT_CODEC = new LeafrefCodecImpl();
+
+ private TypeDefinition<?> type;
+
+ private ObjectCodec(TypeDefinition<?> typeDefinition) {
+ type = RestUtil.resolveBaseTypeFrom(typeDefinition);
+ }
+
+ @SuppressWarnings("unchecked")
+ @Override
+ public Object deserialize(Object input) {
+ try {
+ if (type instanceof IdentityrefTypeDefinition) {
+ return IDENTITYREF_DEFAULT_CODEC.deserialize(input);
+ } else if (type instanceof LeafrefTypeDefinition) {
+ return LEAFREF_DEFAULT_CODEC.deserialize(input);
+ } else {
+ TypeDefinitionAwareCodec<Object,? extends TypeDefinition<?>> typeAwarecodec = TypeDefinitionAwareCodec.from(type);
+ if (typeAwarecodec != null) {
+ return typeAwarecodec.deserialize(String.valueOf(input));
+ } else {
+ logger.debug("Codec for type \"" + type.getQName().getLocalName() + "\" is not implemented yet.");
+ return null;
+ }
+ }
+ } catch (ClassCastException e) { // TODO remove this catch when everyone use codecs
+ logger.error("ClassCastException was thrown when codec is invoked with parameter " + String.valueOf(input), e);
+ return input;
+ }
+ }
+
+ @SuppressWarnings("unchecked")
+ @Override
+ public Object serialize(Object input) {
+ try {
+ if (type instanceof IdentityrefTypeDefinition) {
+ return IDENTITYREF_DEFAULT_CODEC.serialize(input);
+ } else if (type instanceof LeafrefTypeDefinition) {
+ return LEAFREF_DEFAULT_CODEC.serialize(input);
+ } else {
+ TypeDefinitionAwareCodec<Object,? extends TypeDefinition<?>> typeAwarecodec = TypeDefinitionAwareCodec.from(type);
+ if (typeAwarecodec != null) {
+ return typeAwarecodec.serialize(input);
+ } else {
+ logger.debug("Codec for type \"" + type.getQName().getLocalName() + "\" is not implemented yet.");
+ return null;
+ }
+ }
+ } catch (ClassCastException e) { // TODO remove this catch when everyone use codecs
+ logger.error("ClassCastException was thrown when codec is invoked with parameter " + String.valueOf(input), e);
+ return input;
+ }
+ }
+
+ }
+
+ public static class IdentityrefCodecImpl implements IdentityrefCodec<IdentityValuesDTO> {
+
+ @Override
+ public IdentityValuesDTO serialize(QName data) {
+ return new IdentityValuesDTO(data.getNamespace().toString(), data.getLocalName(), data.getPrefix());
+ }
+
+ @Override
+ public QName deserialize(IdentityValuesDTO data) {
+ IdentityValue valueWithNamespace = data.getValuesWithNamespaces().get(0);
+ String namespace = valueWithNamespace.getNamespace();
+ URI validNamespace = ControllerContext.getInstance().findNamespaceByModule(namespace);
+ if (validNamespace == null) {
+ validNamespace = URI.create(namespace);
+ }
+ return QName.create(validNamespace, null, valueWithNamespace.getValue());
+ }
+
+ }
+
+ public static class LeafrefCodecImpl implements LeafrefCodec<String> {
+
+ @Override
+ public String serialize(Object data) {
+ return String.valueOf(data);
+ }
+
+ @Override
+ public Object deserialize(String data) {
+ return data;
+ }
+
+ }
+
+}
import javax.ws.rs.core.Response
import org.opendaylight.controller.md.sal.common.api.TransactionStatus
import org.opendaylight.controller.sal.rest.api.RestconfService
+import org.opendaylight.yangtools.yang.common.QName
import org.opendaylight.yangtools.yang.data.api.CompositeNode
import org.opendaylight.yangtools.yang.data.api.Node
import org.opendaylight.yangtools.yang.data.impl.NodeFactory
import org.opendaylight.yangtools.yang.model.api.ChoiceNode
+import org.opendaylight.yangtools.yang.model.api.ContainerSchemaNode
import org.opendaylight.yangtools.yang.model.api.DataNodeContainer
import org.opendaylight.yangtools.yang.model.api.DataSchemaNode
-import org.opendaylight.yangtools.yang.data.impl.codec.TypeDefinitionAwareCodec
-import org.opendaylight.yangtools.yang.model.api.TypeDefinition
-import org.opendaylight.yangtools.yang.model.api.LeafSchemaNode
import org.opendaylight.yangtools.yang.model.api.LeafListSchemaNode
-import org.opendaylight.yangtools.yang.common.QName
-import org.opendaylight.yangtools.yang.model.api.ContainerSchemaNode
+import org.opendaylight.yangtools.yang.model.api.LeafSchemaNode
+import org.opendaylight.yangtools.yang.model.api.ListSchemaNode
+import org.opendaylight.yangtools.yang.model.api.TypeDefinition
+import org.opendaylight.yangtools.yang.model.api.type.IdentityrefTypeDefinition
+
import static javax.ws.rs.core.Response.Status.*
class RestconfImpl implements RestconfService {
}
val moduleName = controllerContext.findModuleByNamespace(validQName.namespace);
if (nodeBuilder.namespace === null || nodeBuilder.namespace == validQName.namespace ||
- nodeBuilder.namespace.path == moduleName) {
+ nodeBuilder.namespace.toString == moduleName) {
nodeBuilder.qname = validQName
} else {
throw new ResponseException(BAD_REQUEST,
findFirstSchemaByLocalName(child.localName, (schema as DataNodeContainer).childNodes),
currentAugment)
}
+ if(schema instanceof ListSchemaNode) {
+ val listKeys = (schema as ListSchemaNode).keyDefinition
+ for (listKey : listKeys) {
+ var foundKey = false
+ for (child : children) {
+ if (child.unwrap.nodeType.localName == listKey.localName) {
+ foundKey = true;
+ }
+ }
+ if (!foundKey) {
+ throw new ResponseException(BAD_REQUEST,
+ "Missing key \"" + listKey.localName + "\" of list \"" + schema.QName.localName + "\"")
+ }
+ }
+ }
} else if (nodeBuilder instanceof SimpleNodeWrapper) {
val simpleNode = (nodeBuilder as SimpleNodeWrapper)
- val stringValue = simpleNode.value as String;
-
- val objectValue = TypeDefinitionAwareCodec.from(schema.typeDefinition)?.deserialize(stringValue);
- simpleNode.setValue(objectValue)
+ val value = simpleNode.value
+ var inputValue = value;
+
+ if (schema.typeDefinition instanceof IdentityrefTypeDefinition) {
+ if (value instanceof String) {
+ inputValue = new IdentityValuesDTO(validQName.namespace.toString, value as String, null)
+ } // else value is instance of ValuesDTO
+ }
+
+ val outputValue = RestCodec.from(schema.typeDefinition)?.deserialize(inputValue);
+ simpleNode.setValue(outputValue)
} else if (nodeBuilder instanceof EmptyNodeWrapper) {
val emptyNodeBuilder = nodeBuilder as EmptyNodeWrapper
if (schema instanceof LeafSchemaNode) {
}
private def dispatch TypeDefinition<?> typeDefinition(LeafSchemaNode node) {
- node.type
+ var baseType = node.type
+ while (baseType.baseType !== null) {
+ baseType = baseType.baseType;
+ }
+ baseType
}
private def dispatch TypeDefinition<?> typeDefinition(LeafListSchemaNode node) {
- node.type
+ var TypeDefinition<?> baseType = node.type
+ while (baseType.baseType !== null) {
+ baseType = baseType.baseType;
+ }
+ baseType
}
private def DataSchemaNode findFirstSchemaByLocalName(String localName, Set<DataSchemaNode> schemas) {
public final class SimpleNodeWrapper implements NodeWrapper<SimpleNode<?>>, SimpleNode<Object> {
- private SimpleNode<?> simpleNode;
+ private SimpleNode<Object> simpleNode;
private String localName;
private Object value;
this.value = value;
}
- public SimpleNodeWrapper(URI namespace, String localName, String value) {
+ public SimpleNodeWrapper(URI namespace, String localName, Object value) {
this(localName, value);
this.namespace = namespace;
}
--- /dev/null
+package org.opendaylight.controller.sal.restconf.impl.cnsn.to.json.test;
+
+import static org.junit.Assert.*;
+
+import java.io.IOException;
+import java.io.StringReader;
+import java.math.BigDecimal;
+import java.net.URI;
+import java.net.URISyntaxException;
+import java.util.*;
+
+import javax.ws.rs.WebApplicationException;
+import javax.xml.bind.DatatypeConverter;
+
+import org.junit.Test;
+import org.opendaylight.controller.sal.restconf.impl.test.TestUtils;
+import org.opendaylight.yangtools.yang.common.QName;
+import org.opendaylight.yangtools.yang.data.api.*;
+import org.opendaylight.yangtools.yang.data.impl.NodeFactory;
+import org.opendaylight.yangtools.yang.model.api.DataSchemaNode;
+import org.opendaylight.yangtools.yang.model.api.Module;
+
+import com.google.gson.stream.JsonReader;
+import com.google.gson.stream.JsonToken;
+
+public class ToJsonBasicDataTypesTest {
+
+ @Test
+ public void simpleYangDataTest() {
+ String jsonOutput = "";
+ CompositeNode compositeNode = TestUtils.loadCompositeNode("/cnsn-to-json/simple-data-types/xml/data.xml");
+
+ Set<Module> modules = TestUtils.resolveModules("/cnsn-to-json/simple-data-types");
+ assertEquals(1, modules.size());
+ Module module = TestUtils.resolveModule(null, modules);
+ assertNotNull(module);
+ DataSchemaNode dataSchemaNode = TestUtils.resolveDataSchemaNode(module, null);
+ assertNotNull(dataSchemaNode);
+
+ TestUtils.normalizeCompositeNode(compositeNode, modules, dataSchemaNode, "simple-data-types:cont");
+
+ try {
+ jsonOutput = TestUtils.writeCompNodeWithSchemaContextToJson(compositeNode, modules, dataSchemaNode);
+ } catch (WebApplicationException | IOException e) {
+ assertTrue(false); // shouldn't get here
+ }
+
+ System.out.println(jsonOutput);
+ verifyJsonOutput(jsonOutput);
+ }
+
+ private CompositeNode prepareData() {
+ MutableCompositeNode cont = NodeFactory.createMutableCompositeNode(TestUtils.buildQName("cont"), null, null,
+ ModifyAction.CREATE, null);
+
+ List<Node<?>> childNodes = new ArrayList<>();
+ childNodes.add(NodeFactory.createMutableSimpleNode(TestUtils.buildQName("lfnint8Min"), cont, (byte) -128,
+ ModifyAction.CREATE, null));
+ childNodes.add(NodeFactory.createMutableSimpleNode(TestUtils.buildQName("lfnint8Max"), cont, (byte) 127,
+ ModifyAction.CREATE, null));
+ childNodes.add(NodeFactory.createMutableSimpleNode(TestUtils.buildQName("lfnint16Min"), cont, (short) -32768,
+ ModifyAction.CREATE, null));
+ childNodes.add(NodeFactory.createMutableSimpleNode(TestUtils.buildQName("lfnint16Max"), cont, (short) 32767,
+ ModifyAction.CREATE, null));
+ childNodes.add(NodeFactory.createMutableSimpleNode(TestUtils.buildQName("lfnint32Min"), cont,
+ (int) -2147483648, ModifyAction.CREATE, null));
+ childNodes.add(NodeFactory.createMutableSimpleNode(TestUtils.buildQName("lfnint32Max"), cont, (int) 2147483647,
+ ModifyAction.CREATE, null));
+ childNodes.add(NodeFactory.createMutableSimpleNode(TestUtils.buildQName("lfnint64Min"), cont, new Long(
+ "-9223372036854775807"), ModifyAction.CREATE, null));
+ childNodes.add(NodeFactory.createMutableSimpleNode(TestUtils.buildQName("lfnint64Max"), cont, new Long(
+ "9223372036854775807"), ModifyAction.CREATE, null));
+ childNodes.add(NodeFactory.createMutableSimpleNode(TestUtils.buildQName("lfnuint8Max"), cont, (short) 255,
+ ModifyAction.CREATE, null));
+ childNodes.add(NodeFactory.createMutableSimpleNode(TestUtils.buildQName("lfnuint16Max"), cont, (int) 65535,
+ ModifyAction.CREATE, null));
+ childNodes.add(NodeFactory.createMutableSimpleNode(TestUtils.buildQName("lfnuint32Max"), cont, new Long(
+ "4294967295"), ModifyAction.CREATE, null));
+ childNodes.add(NodeFactory.createMutableSimpleNode(TestUtils.buildQName("lfstr"), cont, "lfstr",
+ ModifyAction.CREATE, null));
+ childNodes.add(NodeFactory.createMutableSimpleNode(TestUtils.buildQName("lfstr1"), cont, "",
+ ModifyAction.CREATE, null));
+ childNodes.add(NodeFactory.createMutableSimpleNode(TestUtils.buildQName("lfbool1"), cont, Boolean.TRUE,
+ ModifyAction.CREATE, null));
+ childNodes.add(NodeFactory.createMutableSimpleNode(TestUtils.buildQName("lfbool2"), cont, Boolean.FALSE,
+ ModifyAction.CREATE, null));
+ childNodes.add(NodeFactory.createMutableSimpleNode(TestUtils.buildQName("lfdecimal1"), cont, new BigDecimal(
+ "43.32"), ModifyAction.CREATE, null));
+ childNodes.add(NodeFactory.createMutableSimpleNode(TestUtils.buildQName("lfdecimal2"), cont, new BigDecimal(
+ "-0.43"), ModifyAction.CREATE, null));
+ childNodes.add(NodeFactory.createMutableSimpleNode(TestUtils.buildQName("lfdecimal3"), cont, new BigDecimal(
+ "43"), ModifyAction.CREATE, null));
+ childNodes.add(NodeFactory.createMutableSimpleNode(TestUtils.buildQName("lfdecimal4"), cont, new BigDecimal(
+ "43E3"), ModifyAction.CREATE, null));
+ childNodes.add(NodeFactory.createMutableSimpleNode(TestUtils.buildQName("lfdecimal6"), cont, new BigDecimal(
+ "33.12345"), ModifyAction.CREATE, null));
+ childNodes.add(NodeFactory.createMutableSimpleNode(TestUtils.buildQName("lfenum"), cont, "enum3",
+ ModifyAction.CREATE, null));
+
+ HashSet<String> bits = new HashSet<String>();
+ bits.add("bit3");
+ childNodes.add(NodeFactory.createMutableSimpleNode(TestUtils.buildQName("lfbits"), cont, bits,
+ ModifyAction.CREATE, null));
+
+ childNodes.add(NodeFactory.createMutableSimpleNode(TestUtils.buildQName("lfbinary"), cont, DatatypeConverter
+ .parseBase64Binary("AAaacdabcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789"),
+ ModifyAction.CREATE, null));
+ childNodes.add(NodeFactory.createMutableSimpleNode(TestUtils.buildQName("lfempty"), cont, null,
+ ModifyAction.CREATE, null));
+ childNodes.add(NodeFactory.createMutableSimpleNode(TestUtils.buildQName("lfunion1"), cont, (int) 324,
+ ModifyAction.CREATE, null));
+ childNodes.add(NodeFactory.createMutableSimpleNode(TestUtils.buildQName("lfunion2"), cont, new BigDecimal(
+ "33.3"), ModifyAction.CREATE, null));
+ childNodes.add(NodeFactory.createMutableSimpleNode(TestUtils.buildQName("lfunion3"), cont, "55",
+ ModifyAction.CREATE, null));
+ childNodes.add(NodeFactory.createMutableSimpleNode(TestUtils.buildQName("lfunion4"), cont, Boolean.TRUE,
+ ModifyAction.CREATE, null));
+ childNodes.add(NodeFactory.createMutableSimpleNode(TestUtils.buildQName("lfunion5"), cont, "true",
+ ModifyAction.CREATE, null));
+ childNodes.add(NodeFactory.createMutableSimpleNode(TestUtils.buildQName("lfunion6"), cont, "false",
+ ModifyAction.CREATE, null));
+ childNodes.add(NodeFactory.createMutableSimpleNode(TestUtils.buildQName("lfunion7"), cont, null,
+ ModifyAction.CREATE, null));
+ childNodes.add(NodeFactory.createMutableSimpleNode(TestUtils.buildQName("lfunion8"), cont, "",
+ ModifyAction.CREATE, null));
+ childNodes.add(NodeFactory.createMutableSimpleNode(TestUtils.buildQName("lfunion9"), cont, "",
+ ModifyAction.CREATE, null));
+
+ HashSet<String> bits2 = new HashSet<String>();
+ bits2.add("bt1");
+ childNodes.add(NodeFactory.createMutableSimpleNode(TestUtils.buildQName("lfunion10"), cont, bits2,
+ ModifyAction.CREATE, null));
+
+ childNodes.add(NodeFactory.createMutableSimpleNode(TestUtils.buildQName("lfunion11"), cont, (short) 33,
+ ModifyAction.CREATE, null));
+ childNodes.add(NodeFactory.createMutableSimpleNode(TestUtils.buildQName("lfunion12"), cont, Boolean.FALSE,
+ ModifyAction.CREATE, null));
+ try {
+ childNodes.add(NodeFactory.createMutableSimpleNode(TestUtils.buildQName("identityref1"), cont, new QName(
+ new URI("simple:data:types"), "iden"), ModifyAction.CREATE, null));
+ } catch (URISyntaxException e) {
+ }
+
+ cont.getChildren().addAll(childNodes);
+
+ cont.init();
+
+ return cont;
+ }
+
+ private void verifyJsonOutput(String jsonOutput) {
+ StringReader strReader = new StringReader(jsonOutput);
+ JsonReader jReader = new JsonReader(strReader);
+
+ String exception = null;
+ try {
+ jsonReadCont(jReader);
+ } catch (IOException e) {
+ exception = e.getMessage();
+ }
+
+ assertNull("Error during reading Json output: " + exception, exception);
+ }
+
+ private void jsonReadCont(JsonReader jReader) throws IOException {
+ jReader.beginObject();
+ assertNotNull("cont1 is missing.", jReader.hasNext());
+
+ // Cont dataFromJson = new Cont(jReader.nextName());
+ jReader.nextName();
+ jsonReadContElements(jReader);
+
+ assertFalse("cont shouldn't have other element.", jReader.hasNext());
+ jReader.endObject();
+ // return dataFromJson;
+ }
+
+ private void jsonReadContElements(JsonReader jReader) throws IOException {
+ jReader.beginObject();
+ List<String> loadedLfs = new ArrayList<>();
+ boolean exceptForDecimal5Raised = false;
+ boolean enumChecked = false;
+ boolean bitsChecked = false;
+ boolean lfdecimal6Checked = false;
+ boolean lfdecimal4Checked = false;
+ boolean lfdecimal3Checked = false;
+ boolean lfdecimal2Checked = false;
+ boolean lfdecimal1Checked = false;
+ boolean lfbool1Checked = false;
+ boolean lfbool2Checked = false;
+ boolean lfstrChecked = false;
+ boolean lfbinaryChecked = false;
+ // boolean lfref1Checked = false;
+ boolean lfemptyChecked = false;
+ boolean lfstr1Checked = false;
+ boolean lfidentityrefChecked = false;
+
+ while (jReader.hasNext()) {
+ String keyName = jReader.nextName();
+ JsonToken peek = null;
+ try {
+ peek = jReader.peek();
+ } catch (IOException e) {
+ if (keyName.equals("lfdecimal5")) {
+ exceptForDecimal5Raised = true;
+ } else {
+ assertTrue("Key " + keyName + " has incorrect value for specifed type", false);
+ }
+ }
+
+ if (keyName.startsWith("lfnint") || keyName.startsWith("lfnuint")) {
+ assertEquals("Key " + keyName + " has incorrect type", JsonToken.NUMBER, peek);
+ try {
+ jReader.nextLong();
+ } catch (NumberFormatException e) {
+ assertTrue("Key " + keyName + " has incorrect value - " + e.getMessage(), false);
+ }
+ loadedLfs.add(keyName.substring(3));
+ } else if (keyName.equals("identityref1")) {
+ assertEquals("Key " + keyName + " has incorrect type", JsonToken.STRING, peek);
+ assertEquals("simple-data-types:iden", jReader.nextString());
+ lfidentityrefChecked = true;
+ } else if (keyName.equals("lfstr")) {
+ assertEquals("Key " + keyName + " has incorrect type", JsonToken.STRING, peek);
+ assertEquals("lfstr", jReader.nextString());
+ lfstrChecked = true;
+ } else if (keyName.equals("lfstr1")) {
+ assertEquals("Key " + keyName + " has incorrect type", JsonToken.STRING, peek);
+ assertEquals("", jReader.nextString());
+ lfstr1Checked = true;
+ } else if (keyName.equals("lfbool1")) {
+ assertEquals("Key " + keyName + " has incorrect type", JsonToken.BOOLEAN, peek);
+ assertEquals(true, jReader.nextBoolean());
+ lfbool1Checked = true;
+ } else if (keyName.equals("lfbool2")) {
+ assertEquals("Key " + keyName + " has incorrect type", JsonToken.BOOLEAN, peek);
+ assertEquals(false, jReader.nextBoolean());
+ lfbool2Checked = true;
+ } else if (keyName.equals("lfbool3")) {
+ assertEquals("Key " + keyName + " has incorrect type", JsonToken.BOOLEAN, peek);
+ assertEquals(false, jReader.nextBoolean());
+ } else if (keyName.equals("lfdecimal1")) {
+ assertEquals("Key " + keyName + " has incorrect type", JsonToken.NUMBER, peek);
+ assertEquals(new Double(43.32), (Double) jReader.nextDouble());
+ lfdecimal1Checked = true;
+ } else if (keyName.equals("lfdecimal2")) {
+ assertEquals("Key " + keyName + " has incorrect type", JsonToken.NUMBER, peek);
+ assertEquals(new Double(-0.43), (Double) jReader.nextDouble());
+ lfdecimal2Checked = true;
+ } else if (keyName.equals("lfdecimal3")) {
+ assertEquals("Key " + keyName + " has incorrect type", JsonToken.NUMBER, peek);
+ assertEquals(new Double(43), (Double) jReader.nextDouble());
+ lfdecimal3Checked = true;
+ } else if (keyName.equals("lfdecimal4")) {
+ assertEquals("Key " + keyName + " has incorrect type", JsonToken.NUMBER, peek);
+ assertEquals(new Double(43E3), (Double) jReader.nextDouble());
+ lfdecimal4Checked = true;
+ } else if (keyName.equals("lfdecimal6")) {
+ assertEquals("Key " + keyName + " has incorrect type", JsonToken.NUMBER, peek);
+ assertEquals(new Double(33.12345), (Double) jReader.nextDouble());
+ lfdecimal6Checked = true;
+ } else if (keyName.equals("lfenum")) {
+ assertEquals("enum3", jReader.nextString());
+ enumChecked = true;
+ } else if (keyName.equals("lfbits")) {
+ assertEquals("bit3 bit2", jReader.nextString());
+ bitsChecked = true;
+ } else if (keyName.equals("lfbinary")) {
+ assertEquals("ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz", jReader.nextString());
+ lfbinaryChecked = true;
+ } else if (keyName.equals("lfempty")) {
+ jReader.beginArray();
+ jReader.nextNull();
+ jReader.endArray();
+ lfemptyChecked = true;
+ } else if (keyName.startsWith("lfunion")) {
+ checkLfUnion(jReader, keyName, peek);
+ } else {
+ assertTrue("Key " + keyName + " doesn't exists in yang file.", false);
+ }
+
+ }
+ Collections.sort(loadedLfs);
+ String expectedLfsStr = "[int16Max, int16Min, int32Max, int32Min, int64Max, int64Min, int8Max, int8Min, uint16Max, uint32Max, uint8Max]";
+ String actualLfsStr = loadedLfs.toString();
+ assertEquals("Some leaves are missing", expectedLfsStr, actualLfsStr);
+ assertTrue("Enum wasn't checked", enumChecked);
+ assertTrue("Bits wasn't checked", bitsChecked);
+ assertTrue("Decimal1 wasn't checked", lfdecimal1Checked);
+ assertTrue("Decimal2 wasn't checked", lfdecimal2Checked);
+ assertTrue("Decimal3 wasn't checked", lfdecimal3Checked);
+ assertTrue("Decimal4 wasn't checked", lfdecimal4Checked);
+ assertTrue("Decimal5 wasn't checked", lfdecimal6Checked);
+ assertTrue("lfbool1 wasn't checked", lfbool1Checked);
+ assertTrue("lfbool2 wasn't checked", lfbool2Checked);
+ assertTrue("lfstr wasn't checked", lfstrChecked);
+ assertTrue("lfstr1 wasn't checked", lfstr1Checked);
+ assertTrue("lfbinary wasn't checked", lfbinaryChecked);
+ assertTrue("lfempty wasn't checked", lfemptyChecked);
+ assertTrue("lfidentityref wasn't checked", lfidentityrefChecked);
+ jReader.endObject();
+ }
+
+ private void checkLfUnion(JsonReader jReader, String keyName, JsonToken peek) throws IOException {
+ if (keyName.equals("lfunion1")) {
+ assertEquals("Key " + keyName + " has incorrect type", JsonToken.STRING, peek);
+ assertEquals("324", jReader.nextString());
+ } else if (keyName.equals("lfunion2")) {
+ assertEquals("Key " + keyName + " has incorrect type", JsonToken.STRING, peek);
+ assertEquals("33.3", jReader.nextString());
+ } else if (keyName.equals("lfunion3")) {
+ assertEquals("Key " + keyName + " has incorrect type", JsonToken.STRING, peek);
+ assertEquals("55", jReader.nextString());
+ } else if (keyName.equals("lfunion4")) {
+ assertEquals("Key " + keyName + " has incorrect type", JsonToken.STRING, peek);
+ assertEquals("true", jReader.nextString());
+ } else if (keyName.equals("lfunion5")) {
+ assertEquals("Key " + keyName + " has incorrect type", JsonToken.STRING, peek);
+ assertEquals("true", jReader.nextString());
+ } else if (keyName.equals("lfunion6")) {
+ assertEquals("Key " + keyName + " has incorrect type", JsonToken.STRING, peek);
+ assertEquals("false", jReader.nextString());
+ } else if (keyName.equals("lfunion7")) {
+ assertEquals("Key " + keyName + " has incorrect type", JsonToken.STRING, peek);
+ assertEquals("", jReader.nextString());
+ } else if (keyName.equals("lfunion8")) {
+ assertEquals("Key " + keyName + " has incorrect type", JsonToken.STRING, peek);
+ assertEquals("", jReader.nextString());
+ } else if (keyName.equals("lfunion9")) {
+ assertEquals("Key " + keyName + " has incorrect type", JsonToken.STRING, peek);
+ assertEquals("", jReader.nextString());
+ } else if (keyName.equals("lfunion10")) {
+ assertEquals("Key " + keyName + " has incorrect type", JsonToken.STRING, peek);
+ assertEquals("bt1", jReader.nextString());
+ } else if (keyName.equals("lfunion11")) {
+ assertEquals("Key " + keyName + " has incorrect type", JsonToken.STRING, peek);
+ assertEquals("33", jReader.nextString());
+ } else if (keyName.equals("lfunion12")) {
+ assertEquals("Key " + keyName + " has incorrect type", JsonToken.STRING, peek);
+ assertEquals("false", jReader.nextString());
+ } else if (keyName.equals("lfunion13")) {
+ assertEquals("Key " + keyName + " has incorrect type", JsonToken.STRING, peek);
+ assertEquals("44", jReader.nextString());
+ } else if (keyName.equals("lfunion14")) {
+ assertEquals("Key " + keyName + " has incorrect type", JsonToken.STRING, peek);
+ assertEquals("21", jReader.nextString());
+ }
+ }
+}
-package org.opendaylight.controller.sal.restconf.impl.test;
+package org.opendaylight.controller.sal.restconf.impl.cnsn.to.json.test;
-import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertFalse;
-import static org.junit.Assert.assertNotNull;
-import static org.junit.Assert.assertNull;
-import static org.junit.Assert.assertTrue;
+import static org.junit.Assert.*;
-import java.io.*;
-import java.util.*;
+import java.io.IOException;
+import java.io.StringReader;
+import java.util.Map;
+import java.util.Set;
import org.junit.Test;
+import org.opendaylight.controller.sal.restconf.impl.test.TestUtils;
import org.opendaylight.controller.sal.restconf.impl.test.structures.*;
import org.opendaylight.yangtools.yang.data.api.*;
import org.opendaylight.yangtools.yang.data.impl.NodeFactory;
-import com.google.gson.stream.*;
+import com.google.gson.stream.JsonReader;
+import com.google.gson.stream.JsonToken;
public class ToJsonBasicYangTypesTest {
@Test
public void compositeNodeAndYangWithJsonReaderEmptyDataTest() {
String jsonOutput = TestUtils.convertCompositeNodeDataAndYangToJson(prepareCompositeNodeWithEmpties(),
- "/yang-to-json-conversion/simple-yang-types", "/yang-to-json-conversion/simple-yang-types/xml");
+ "/cnsn-to-json/simple-yang-types", "/cnsn-to-json/simple-yang-types/xml", "simple-yang-types", "cont1");
verifyJsonOutputForEmpty(jsonOutput);
}
@Test
public void xmlAndYangTypesWithJsonReaderTest() {
String jsonOutput = TestUtils.convertCompositeNodeDataAndYangToJson(
- TestUtils.loadCompositeNode("/yang-to-json-conversion/simple-yang-types/xml/data.xml"),
- "/yang-to-json-conversion/simple-yang-types", "/yang-to-json-conversion/simple-yang-types/xml");
+ TestUtils.loadCompositeNode("/cnsn-to-json/simple-yang-types/xml/data.xml"),
+ "/cnsn-to-json/simple-yang-types", "/cnsn-to-json/simple-yang-types/xml", "simple-yang-types", "cont1");
verifyJsonOutput(jsonOutput);
}
return lstItem;
}
- private String nextValue(JsonReader jReader) throws IOException {
+ private Object nextValue(JsonReader jReader) throws IOException {
if (jReader.peek().equals(JsonToken.NULL)) {
jReader.nextNull();
return null;
+ } else if (jReader.peek().equals(JsonToken.NUMBER)) {
+ return jReader.nextInt();
} else {
return jReader.nextString();
}
LstItem lst11_2 = null;
LstItem lst11_3 = null;
for (LstItem lstItem : lstItems) {
- if (lstItem.getLfs().get("lf111").getValue().equals("1")) {
+ if (lstItem.getLfs().get("lf111").getValue().equals(1)) {
lst11_1 = lstItem;
- } else if (lstItem.getLfs().get("lf111").getValue().equals("2")) {
+ } else if (lstItem.getLfs().get("lf111").getValue().equals(2)) {
lst11_2 = lstItem;
- } else if (lstItem.getLfs().get("lf111").getValue().equals("3")) {
+ } else if (lstItem.getLfs().get("lf111").getValue().equals(3)) {
lst11_3 = lstItem;
}
}
assertEquals(1, lst11_1.getLfs().size());
assertEquals(1, lst11_1.getConts().size());
assertEquals(1, lst11_1.getLsts().size());
- assertEquals(lst11_1.getLsts().get("lst111"), new Lst("lst111").addLstItem(new LstItem().addLf("lf1111", "35"))
- .addLstItem(new LstItem().addLf("lf1111", "34")).addLstItem(new LstItem()).addLstItem(new LstItem()));
+ assertEquals(
+ lst11_1.getLsts().get("lst111"),
+ new Lst("lst111").addLstItem(new LstItem().addLf("lf1111", (int) 35))
+ .addLstItem(new LstItem().addLf("lf1111", (int) 34)).addLstItem(new LstItem())
+ .addLstItem(new LstItem()));
assertEquals(lst11_1.getConts().get("cont111"), new Cont("cont111"));
// : lst11_1
assertEquals(1, lst11_2_cont111.getLsts().size());
assertTrue(lst11_2_cont111.getConts().isEmpty());
- assertEquals(new LfLst("lflst1111").addLf("1024").addLf("4096"), lst11_2_cont111.getLfLsts().get("lflst1111"));
+ assertEquals(new LfLst("lflst1111").addLf((int) 1024).addLf((int) 4096),
+ lst11_2_cont111.getLfLsts().get("lflst1111"));
assertEquals(
- new Lst("lst1111").addLstItem(new LstItem().addLf("lf1111B", "4")).addLstItem(
+ new Lst("lst1111").addLstItem(new LstItem().addLf("lf1111B", (int) 4)).addLstItem(
new LstItem().addLf("lf1111A", "lf1111A str12")), lst11_2_cont111.getLsts().get("lst1111"));
// :-cont111
assertEquals(lst11_2.getLsts().get("lst112"), new Lst("lst112").addLstItem(new LstItem()));
assertNotNull(lflst12);
assertEquals(3, lflst11.getLfs().size());
- assertTrue(lflst11.getLfs().contains(new Lf("55")));
- assertTrue(lflst11.getLfs().contains(new Lf("56")));
- assertTrue(lflst11.getLfs().contains(new Lf("57")));
+ assertTrue(lflst11.getLfs().contains(new Lf(55)));
+ assertTrue(lflst11.getLfs().contains(new Lf(56)));
+ assertTrue(lflst11.getLfs().contains(new Lf(57)));
assertEquals(3, lflst12.getLfs().size());
assertTrue(lflst12.getLfs().contains(new Lf("lflst12 str1")));
LstItem lst11_2 = null;
for (LstItem lstItem : lst11.getLstItems()) {
Lf lf = lstItem.getLfs().get("lf111");
- if (lf != null && lf.getValue().equals("140")) {
+ if (lf != null && lf.getValue().equals(140)) {
lst11_1 = lstItem;
- } else if (lf != null && lf.getValue().equals("141")) {
+ } else if (lf != null && lf.getValue().equals(141)) {
lst11_2 = lstItem;
}
}
// cont111 check
assertEquals(new Lf("lf1111", "lf1111 str2"), lst11_2_cont.getLfs().get("lf1111"));
- assertEquals(new LfLst("lflst1111").addLf(new Lf("2049")).addLf(new Lf("1025")).addLf(new Lf("4097")),
- lst11_2_cont.getLfLsts().get("lflst1111"));
+ assertEquals(new LfLst("lflst1111").addLf(new Lf(2049)).addLf(new Lf(1025)).addLf(new Lf(4097)), lst11_2_cont
+ .getLfLsts().get("lflst1111"));
assertNotNull(lst11_2_cont.getLsts().get("lst1111"));
checkLst1111(lst11_2_cont.getLsts().get("lst1111").getLstItems(), new Lf("lf1111A", "lf1111A str21"), new Lf(
- "lf1111B", "5"), new Lf("lf1111A", "lf1111A str22"), new Lf("lf1111B", "8"));
+ "lf1111B", 5), new Lf("lf1111A", "lf1111A str22"), new Lf("lf1111B", 8));
- checkLst11x(lst11_2.getLsts().get("lst111"), new LstItem().addLf(new Lf("lf1111", "55")),
- new LstItem().addLf(new Lf("lf1111", "56")));
+ checkLst11x(lst11_2.getLsts().get("lst111"), new LstItem().addLf(new Lf("lf1111", 55)),
+ new LstItem().addLf(new Lf("lf1111", 56)));
checkLst11x(lst11_2.getLsts().get("lst112"), new LstItem().addLf(new Lf("lf1121", "lf1121 str22")),
new LstItem().addLf(new Lf("lf1121", "lf1121 str21")));
}
// cont111 check
assertEquals(new Lf("lf1111", "lf1111 str"), lst11_1_cont.getLfs().get("lf1111"));
- assertEquals(new LfLst("lflst1111").addLf(new Lf("2048")).addLf(new Lf("1024")).addLf(new Lf("4096")),
- lst11_1_cont.getLfLsts().get("lflst1111"));
+ assertEquals(new LfLst("lflst1111").addLf(new Lf(2048)).addLf(new Lf(1024)).addLf(new Lf(4096)), lst11_1_cont
+ .getLfLsts().get("lflst1111"));
assertNotNull(lst11_1_cont.getLsts().get("lst1111"));
checkLst1111(lst11_1_cont.getLsts().get("lst1111").getLstItems(), new Lf("lf1111A", "lf1111A str11"), new Lf(
- "lf1111B", "4"), new Lf("lf1111A", "lf1111A str12"), new Lf("lf1111B", "7"));
+ "lf1111B", 4), new Lf("lf1111A", "lf1111A str12"), new Lf("lf1111B", 7));
- checkLst11x(lst11_1.getLsts().get("lst111"), new LstItem().addLf(new Lf("lf1111", "65")));
+ checkLst11x(lst11_1.getLsts().get("lst111"), new LstItem().addLf(new Lf("lf1111", 65)));
checkLst11x(lst11_1.getLsts().get("lst112"), new LstItem().addLf(new Lf("lf1121", "lf1121 str11")));
}
null, ModifyAction.CREATE, null);
cont1.getChildren().add(lst11_1);
- MutableSimpleNode<?> lf111_1 = NodeFactory.createMutableSimpleNode(TestUtils.buildQName("lf111"), lst11_1, "1",
- ModifyAction.CREATE, null);
+ MutableSimpleNode<?> lf111_1 = NodeFactory.createMutableSimpleNode(TestUtils.buildQName("lf111"), lst11_1,
+ (short) 1, ModifyAction.CREATE, null);
lst11_1.getChildren().add(lf111_1);
// lst111_1_1
lst11_1, null, ModifyAction.CREATE, null);
lst11_1.getChildren().add(lst111_1_1);
MutableSimpleNode<?> lf1111_1_1 = NodeFactory.createMutableSimpleNode(TestUtils.buildQName("lf1111"),
- lst111_1_1, "34", ModifyAction.CREATE, null);
+ lst111_1_1, (int) 34, ModifyAction.CREATE, null);
lst111_1_1.getChildren().add(lf1111_1_1);
lst111_1_1.init();
// :lst111_1_1
lst11_1, null, ModifyAction.CREATE, null);
lst11_1.getChildren().add(lst111_1_2);
MutableSimpleNode<?> lf1111_1_2 = NodeFactory.createMutableSimpleNode(TestUtils.buildQName("lf1111"),
- lst111_1_2, "35", ModifyAction.CREATE, null);
+ lst111_1_2, (int) 35, ModifyAction.CREATE, null);
lst111_1_2.getChildren().add(lf1111_1_2);
lst111_1_2.init();
// :lst111_1_2
null, ModifyAction.CREATE, null);
cont1.getChildren().add(lst11_2);
- MutableSimpleNode<?> lf111_2 = NodeFactory.createMutableSimpleNode(TestUtils.buildQName("lf111"), lst11_2, "2",
- ModifyAction.CREATE, null);
+ MutableSimpleNode<?> lf111_2 = NodeFactory.createMutableSimpleNode(TestUtils.buildQName("lf111"), lst11_2,
+ (short) 2, ModifyAction.CREATE, null);
lst11_2.getChildren().add(lf111_2);
// cont111_2
lst11_2.getChildren().add(cont111_2);
MutableSimpleNode<?> lflst1111_2_2 = NodeFactory.createMutableSimpleNode(TestUtils.buildQName("lflst1111"),
- cont111_2, "1024", ModifyAction.CREATE, null);
+ cont111_2, (int) 1024, ModifyAction.CREATE, null);
cont111_2.getChildren().add(lflst1111_2_2);
MutableSimpleNode<?> lflst1111_2_3 = NodeFactory.createMutableSimpleNode(TestUtils.buildQName("lflst1111"),
- cont111_2, "4096", ModifyAction.CREATE, null);
+ cont111_2, (int) 4096, ModifyAction.CREATE, null);
cont111_2.getChildren().add(lflst1111_2_3);
// lst1111_2
cont111_2, null, ModifyAction.CREATE, null);
cont111_2.getChildren().add(lst1111_2_1);
MutableSimpleNode<?> lf1111B_2_1 = NodeFactory.createMutableSimpleNode(TestUtils.buildQName("lf1111B"),
- lst1111_2_1, "4", ModifyAction.CREATE, null);
+ lst1111_2_1, (short) 4, ModifyAction.CREATE, null);
lst1111_2_1.getChildren().add(lf1111B_2_1);
lst1111_2_1.init();
MutableCompositeNode lst1111_2_2 = NodeFactory.createMutableCompositeNode(TestUtils.buildQName("lst1111"),
cont111_2, null, ModifyAction.CREATE, null);
cont111_2.getChildren().add(lst1111_2_2);
- MutableSimpleNode<?> lf1111B_2_2 = NodeFactory.createMutableSimpleNode(TestUtils.buildQName("lf1111A"),
+ MutableSimpleNode<?> lf1111A_2_2 = NodeFactory.createMutableSimpleNode(TestUtils.buildQName("lf1111A"),
lst1111_2_2, "lf1111A str12", ModifyAction.CREATE, null);
- lst1111_2_2.getChildren().add(lf1111B_2_2);
+ lst1111_2_2.getChildren().add(lf1111A_2_2);
lst1111_2_2.init();
// :lst1111_2
null, ModifyAction.CREATE, null);
cont1.getChildren().add(lst11_3);
- MutableSimpleNode<?> lf111_3 = NodeFactory.createMutableSimpleNode(TestUtils.buildQName("lf111"), lst11_3, "3",
- ModifyAction.CREATE, null);
+ MutableSimpleNode<?> lf111_3 = NodeFactory.createMutableSimpleNode(TestUtils.buildQName("lf111"), lst11_3,
+ (short) 3, ModifyAction.CREATE, null);
lst11_3.getChildren().add(lf111_3);
// cont111_3
--- /dev/null
+package org.opendaylight.controller.sal.restconf.impl.cnsn.to.json.test;
+
+import static org.junit.Assert.assertTrue;
+
+import java.io.IOException;
+
+import javax.ws.rs.WebApplicationException;
+
+import org.junit.BeforeClass;
+import org.junit.Test;
+import org.opendaylight.controller.sal.restconf.impl.test.TestUtils;
+import org.opendaylight.controller.sal.restconf.impl.test.YangAndXmlAndDataSchemaLoader;
+import org.opendaylight.yangtools.yang.data.api.CompositeNode;
+
+public class ToJsonChoiceCaseTest extends YangAndXmlAndDataSchemaLoader {
+
+ @BeforeClass
+ public static void initialization() {
+ dataLoad("/cnsn-to-json/choice");
+ }
+
+ /**
+ * Test when some data are in one case node and other in another. This isn't
+ * correct. Next Json validator should return error because nodes has to be
+ * from one case below concrete choice.
+ *
+ */
+ @Test
+ public void nodeSchemasOnVariousChoiceCasePathTest() {
+ testWrapper("/cnsn-to-json/choice/xml/data_various_path_err.xml", "choice-case-test:cont");
+ }
+
+ /**
+ * Test when some data are in one case node and other in another.
+ * Additionally data are loadef from various choices. This isn't correct.
+ * Next Json validator should return error because nodes has to be from one
+ * case below concrete choice.
+ *
+ */
+ @Test
+ public void nodeSchemasOnVariousChoiceCasePathAndMultipleChoicesTest() {
+ testWrapper("/cnsn-to-json/choice/xml/data_more_choices_same_level_various_paths_err.xml",
+ "choice-case-test:cont");
+ }
+
+ /**
+ * Test when second level data are red first, then first and at the end
+ * third level. Level represents pass through couple choice-case
+ */
+
+ @Test
+ public void nodeSchemasWithRandomOrderAccordingLevel() {
+ testWrapper("/cnsn-to-json/choice/xml/data_random_level.xml", "choice-case-test:cont");
+ }
+
+ /**
+ * Test when element from no first case is used
+ */
+ @Test
+ public void nodeSchemasNotInFirstCase() {
+ testWrapper("/cnsn-to-json/choice/xml/data_no_first_case.xml", "choice-case-test:cont");
+ }
+
+ /**
+ * Test when element in case is list
+ */
+ @Test
+ public void nodeSchemaAsList() {
+ testWrapper("/cnsn-to-json/choice/xml/data_list.xml", "choice-case-test:cont");
+ }
+
+ /**
+ * Test when element in case is container
+ */
+ @Test
+ public void nodeSchemaAsContainer() {
+ testWrapper("/cnsn-to-json/choice/xml/data_container.xml", "choice-case-test:cont");
+ }
+
+ /**
+ * Test when element in case is leaflist
+ */
+ @Test
+ public void nodeSchemaAsLeafList() {
+ testWrapper("/cnsn-to-json/choice/xml/data_leaflist.xml", "choice-case-test:cont");
+ }
+
+ /**
+ *
+ */
+ @Test
+ public void nodeSchemasInMultipleChoicesTest() {
+ testWrapper("/cnsn-to-json/choice/xml/data_more_choices_same_level.xml", "choice-case-test:cont");
+ }
+
+ /**
+ * Test whether is possible to find data schema for node which is specified
+ * as dirrect subnode of choice (case without CASE key word)
+ */
+ @Test
+ public void nodeSchemasInCaseNotDefinedWithCaseKeyword() {
+ testWrapper("/cnsn-to-json/choice/xml/data_case_defined_without_case.xml", "choice-case-test:cont");
+ }
+
+ /**
+ * Test of multiple use of choices
+ */
+ @Test
+ public void nodeSchemasInThreeChoicesAtSameLevel() {
+ testWrapper("/cnsn-to-json/choice/xml/data_three_choices_same_level.xml", "choice-case-test:cont");
+ }
+
+ private void testWrapper(String xmlPath, String pathToSchemaNode) {
+ CompositeNode compNode = TestUtils.loadCompositeNode(xmlPath);
+ TestUtils.normalizeCompositeNode(compNode, modules, dataSchemaNode, pathToSchemaNode);
+ try {
+ TestUtils.writeCompNodeWithSchemaContextToJson(compNode, modules, dataSchemaNode);
+ } catch (WebApplicationException | IOException e) {
+ // shouldn't end here
+ assertTrue(false);
+ }
+ }
+}
-package org.opendaylight.controller.sal.restconf.impl.test;
+package org.opendaylight.controller.sal.restconf.impl.cnsn.to.json.test;
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertTrue;
import java.io.IOException;
-import java.util.regex.*;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
import javax.ws.rs.WebApplicationException;
-import org.junit.*;
+import org.junit.BeforeClass;
+import org.junit.Test;
+import org.opendaylight.controller.sal.restconf.impl.test.TestUtils;
+import org.opendaylight.controller.sal.restconf.impl.test.YangAndXmlAndDataSchemaLoader;
import org.opendaylight.yangtools.yang.data.api.*;
import org.opendaylight.yangtools.yang.data.impl.NodeFactory;
@BeforeClass
public static void initialization() {
- dataLoad("/yang-to-json-conversion/identityref", 2, "identityref-module", "cont");
+ dataLoad("/cnsn-to-json/identityref", 2, "identityref-module", "cont");
}
@Test
public void identityrefToJsonTest() {
String json = null;
try {
- json = TestUtils
- .writeCompNodeWithSchemaContextToJson(prepareCompositeNode(), null, modules, dataSchemaNode);
+ json = TestUtils.writeCompNodeWithSchemaContextToJson(prepareCompositeNode(), modules, dataSchemaNode);
} catch (WebApplicationException | IOException e) {
// shouldn't end here
assertTrue(false);
private CompositeNode prepareCompositeNode() {
MutableCompositeNode cont = NodeFactory.createMutableCompositeNode(TestUtils.buildQName("cont"), null, null,
ModifyAction.CREATE, null);
- MutableSimpleNode<?> lf1 = NodeFactory.createMutableSimpleNode(TestUtils.buildQName("lf1"), cont,
+ MutableCompositeNode cont1 = NodeFactory.createMutableCompositeNode(TestUtils.buildQName("cont1"), cont, null,
+ ModifyAction.CREATE, null);
+ cont.getChildren().add(cont1);
+
+ MutableSimpleNode<?> lf1 = NodeFactory.createMutableSimpleNode(TestUtils.buildQName("lf1"), cont1,
TestUtils.buildQName("name_test", "identityref:module", "2013-12-2"), ModifyAction.CREATE, null);
- cont.getChildren().add(lf1);
+ cont1.getChildren().add(lf1);
+ cont1.init();
cont.init();
return cont;
-package org.opendaylight.controller.sal.restconf.impl.test;
+package org.opendaylight.controller.sal.restconf.impl.cnsn.to.json.test;
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertTrue;
import javax.ws.rs.WebApplicationException;
import org.junit.*;
+import org.opendaylight.controller.sal.restconf.impl.test.TestUtils;
+import org.opendaylight.controller.sal.restconf.impl.test.YangAndXmlAndDataSchemaLoader;
+
+/**
+ *
+ * All tests are commented now because leafref isn't supported now
+ *
+ */
public class ToJsonLeafrefType extends YangAndXmlAndDataSchemaLoader {
@BeforeClass
public static void initialization() {
- dataLoad("/yang-to-json-conversion/leafref", 2, "main-module", "cont");
+ dataLoad("/cnsn-to-json/leafref", 2, "main-module", "cont");
}
+ @Ignore
@Test
public void leafrefAbsolutePathToExistingLeafTest() {
String json = null;
try {
- json = TestUtils.writeCompNodeWithSchemaContextToJson(TestUtils
- .loadCompositeNode("/yang-to-json-conversion/leafref/xml/data_absolut_ref_to_existing_leaf.xml"),
- "/yang-to-json-conversion/leafref/xml", modules, dataSchemaNode);
+ json = TestUtils.writeCompNodeWithSchemaContextToJson(
+ TestUtils.loadCompositeNode("/cnsn-to-json/leafref/xml/data_absolut_ref_to_existing_leaf.xml"),
+ modules, dataSchemaNode);
} catch (WebApplicationException | IOException e) {
// shouldn't end here
assertTrue(false);
assertTrue(mtch.matches());
}
+ @Ignore
@Test
public void leafrefRelativePathToExistingLeafTest() {
String json = null;
try {
- json = TestUtils.writeCompNodeWithSchemaContextToJson(TestUtils
- .loadCompositeNode("/yang-to-json-conversion/leafref/xml/data_relativ_ref_to_existing_leaf.xml"),
- "/yang-to-json-conversion/leafref/xml", modules, dataSchemaNode);
+ json = TestUtils.writeCompNodeWithSchemaContextToJson(
+ TestUtils.loadCompositeNode("/cnsn-to-json/leafref/xml/data_relativ_ref_to_existing_leaf.xml"),
+ modules, dataSchemaNode);
} catch (WebApplicationException | IOException e) {
// shouldn't end here
assertTrue(false);
* Tests case when reference to not existing element is present. In this
* case value from single node is printed as string.
*/
+ @Ignore
@Test
public void leafrefToNonExistingLeafTest() {
String json = null;
try {
- json = TestUtils.writeCompNodeWithSchemaContextToJson(TestUtils
- .loadCompositeNode("/yang-to-json-conversion/leafref/xml/data_ref_to_non_existing_leaf.xml"),
- "/yang-to-json-conversion/leafref/xml", modules, dataSchemaNode);
+ json = TestUtils.writeCompNodeWithSchemaContextToJson(
+ TestUtils.loadCompositeNode("/cnsn-to-json/leafref/xml/data_ref_to_non_existing_leaf.xml"),
+ modules, dataSchemaNode);
} catch (WebApplicationException | IOException e) {
// shouldn't end here
assertTrue(false);
* Tests case when non leaf element is referenced. In this case value from
* single node is printed as string.
*/
+ @Ignore
@Test
public void leafrefToNotLeafTest() {
String json = null;
try {
json = TestUtils.writeCompNodeWithSchemaContextToJson(
- TestUtils.loadCompositeNode("/yang-to-json-conversion/leafref/xml/data_ref_to_not_leaf.xml"),
- "/yang-to-json-conversion/leafref/xml", modules, dataSchemaNode);
+ TestUtils.loadCompositeNode("/cnsn-to-json/leafref/xml/data_ref_to_not_leaf.xml"), modules,
+ dataSchemaNode);
} catch (WebApplicationException | IOException e) {
// shouldn't end here
assertTrue(false);
/**
* Tests case when leaflist element is refers to leaf.
*/
+ @Ignore
@Test
public void leafrefFromLeafListToLeafTest() {
String json = null;
json = TestUtils
.writeCompNodeWithSchemaContextToJson(
TestUtils
- .loadCompositeNode("/yang-to-json-conversion/leafref/xml/data_relativ_ref_from_leaflist_to_existing_leaf.xml"),
- "/yang-to-json-conversion/leafref/xml", modules, dataSchemaNode);
+ .loadCompositeNode("/cnsn-to-json/leafref/xml/data_relativ_ref_from_leaflist_to_existing_leaf.xml"),
+ modules, dataSchemaNode);
} catch (WebApplicationException | IOException e) {
// shouldn't end here
assertTrue(false);
/**
* Tests case when leaflist element is refers to leaf.
*/
+ @Ignore
@Test
public void leafrefFromLeafrefToLeafrefTest() {
String json = null;
try {
- json = TestUtils.writeCompNodeWithSchemaContextToJson(TestUtils
- .loadCompositeNode("/yang-to-json-conversion/leafref/xml/data_from_leafref_to_leafref.xml"),
- "/yang-to-json-conversion/leafref/xml", modules, dataSchemaNode);
+ json = TestUtils.writeCompNodeWithSchemaContextToJson(
+ TestUtils.loadCompositeNode("/cnsn-to-json/leafref/xml/data_from_leafref_to_leafref.xml"), modules,
+ dataSchemaNode);
} catch (WebApplicationException | IOException e) {
// shouldn't end here
assertTrue(false);
-package org.opendaylight.controller.sal.restconf.impl.test;
+package org.opendaylight.controller.sal.restconf.impl.cnsn.to.json.test;
import static org.junit.Assert.assertTrue;
import org.junit.Test;
+import org.opendaylight.controller.sal.restconf.impl.test.TestUtils;
+import org.opendaylight.yangtools.yang.data.api.CompositeNode;
public class ToJsonWithAugmentTest {
*/
@Test
public void augmentedElementsToJson() {
- String jsonOutput = TestUtils.convertCompositeNodeDataAndYangToJson(
- TestUtils.loadCompositeNode("/yang-to-json-conversion/augmentation/xml/data.xml"),
- "/yang-to-json-conversion/augmentation", "/yang-to-json-conversion/augmentation/xml", "yang", "cont");
+
+ CompositeNode compositeNode = TestUtils.loadCompositeNode("/cnsn-to-json/augmentation/xml/data.xml");
+ String jsonOutput = TestUtils.convertCompositeNodeDataAndYangToJson(compositeNode,
+ "/cnsn-to-json/augmentation", "/cnsn-to-json/augmentation/xml", "yang", "cont");
assertTrue(jsonOutput.contains("\"augment-leaf:lf2\": \"lf2\""));
assertTrue(jsonOutput.contains("\"augment-container:cont1\": {"));
--- /dev/null
+package org.opendaylight.controller.sal.restconf.impl.cnsn.to.xml.test;
+
+import static org.junit.Assert.*;
+
+import java.io.StringWriter;
+import java.util.Set;
+
+import javax.activation.UnsupportedDataTypeException;
+import javax.xml.transform.*;
+import javax.xml.transform.dom.DOMSource;
+import javax.xml.transform.stream.StreamResult;
+
+import org.junit.BeforeClass;
+import org.junit.Test;
+import org.opendaylight.controller.sal.rest.impl.XmlMapper;
+import org.opendaylight.controller.sal.restconf.impl.test.TestUtils;
+import org.opendaylight.yangtools.yang.data.api.*;
+import org.opendaylight.yangtools.yang.data.impl.NodeFactory;
+import org.opendaylight.yangtools.yang.data.impl.codec.TypeDefinitionAwareCodec;
+import org.opendaylight.yangtools.yang.model.api.*;
+import org.w3c.dom.Document;
+
+/**
+ *
+ * CnSn = Composite node and Simple node data structure Class contains test of
+ * serializing simple nodes data values according data types from YANG schema to
+ * XML file
+ *
+ */
+public class CnSnToXmlTest {
+
+ private static Set<Module> modules;
+ private static DataSchemaNode dataSchemaNode;
+
+ @BeforeClass
+ public static void initialization() {
+ modules = TestUtils.resolveModules("/cnsn-to-xml/yang");
+ assertEquals(2, modules.size());
+ Module module = TestUtils.resolveModule("basic-module", modules);
+ assertNotNull(module);
+ dataSchemaNode = TestUtils.resolveDataSchemaNode(module, "cont");
+ assertNotNull(dataSchemaNode);
+
+ }
+
+ @Test
+ public void snAsYangIdentityrefToXMLTest() {
+ serializeToXml(prepareIdentityrefData(), "<lf11 xmlns:x=\"referenced:module\">x:iden</lf11>");
+ }
+
+ @Test
+ public void snAsYangStringToXmlTest() {
+ serializeToXml(
+ prepareCnStructForYangData(TypeDefinitionAwareCodec.STRING_DEFAULT_CODEC.deserialize("lfStr value"),
+ "lfStr"), "<lfStr>lfStr value</lfStr>");
+ }
+
+ @Test
+ public void snAsYangInt8ToXmlTest() {
+ String elName = "lfInt8";
+ serializeToXml(
+ prepareCnStructForYangData(TypeDefinitionAwareCodec.INT8_DEFAULT_CODEC.deserialize("14"), elName), "<"
+ + elName + ">14</" + elName + ">");
+ }
+
+ @Test
+ public void snAsYangInt16ToXmlTest() {
+ String elName = "lfInt16";
+ serializeToXml(
+ prepareCnStructForYangData(TypeDefinitionAwareCodec.INT16_DEFAULT_CODEC.deserialize("3000"), elName),
+ "<" + elName + ">3000</" + elName + ">");
+ }
+
+ @Test
+ public void snAsYangInt32ToXmlTest() {
+ String elName = "lfInt32";
+ serializeToXml(
+ prepareCnStructForYangData(TypeDefinitionAwareCodec.INT32_DEFAULT_CODEC.deserialize("201234"), elName),
+ "<" + elName + ">201234</" + elName + ">");
+ }
+
+ @Test
+ public void snAsYangInt64ToXmlTest() {
+ String elName = "lfInt64";
+ serializeToXml(
+ prepareCnStructForYangData(TypeDefinitionAwareCodec.INT64_DEFAULT_CODEC.deserialize("5123456789"),
+ elName), "<" + elName + ">5123456789</" + elName + ">");
+ }
+
+ @Test
+ public void snAsYangUint8ToXmlTest() {
+ String elName = "lfUint8";
+ serializeToXml(
+ prepareCnStructForYangData(TypeDefinitionAwareCodec.UINT8_DEFAULT_CODEC.deserialize("200"), elName),
+ "<" + elName + ">200</" + elName + ">");
+ }
+
+ @Test
+ public void snAsYangUint16ToXmlTest() {
+ String elName = "lfUint16";
+ serializeToXml(
+ prepareCnStructForYangData(TypeDefinitionAwareCodec.UINT16_DEFAULT_CODEC.deserialize("4000"), elName),
+ "<" + elName + ">4000</" + elName + ">");
+ }
+
+ @Test
+ public void snAsYangUint32ToXmlTest() {
+ String elName = "lfUint32";
+ serializeToXml(
+ prepareCnStructForYangData(TypeDefinitionAwareCodec.UINT32_DEFAULT_CODEC.deserialize("4123456789"),
+ elName), "<" + elName + ">4123456789</" + elName + ">");
+ }
+
+ @Test
+ public void snAsYangUint64ToXmlTest() {
+ String elName = "lfUint64";
+ serializeToXml(
+ prepareCnStructForYangData(TypeDefinitionAwareCodec.UINT64_DEFAULT_CODEC.deserialize("5123456789"),
+ elName), "<" + elName + ">5123456789</" + elName + ">");
+ }
+
+ @Test
+ public void snAsYangBinaryToXmlTest() {
+ String elName = "lfBinary";
+ serializeToXml(
+ prepareCnStructForYangData(
+ TypeDefinitionAwareCodec.BINARY_DEFAULT_CODEC
+ .deserialize("ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz01234567"),
+ elName), "<" + elName + ">ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz01234567</"
+ + elName + ">");
+ }
+
+ @Test
+ public void snAsYangBitsToXmlTest() {
+ String elName = "lfBits";
+ serializeToXml(
+ prepareCnStructForYangData(TypeDefinitionAwareCodec.BITS_DEFAULT_CODEC.deserialize("one two"), elName),
+ "<" + elName + ">one two</" + elName + ">", "<" + elName + ">two one</" + elName + ">");
+ }
+
+ @Test
+ public void snAsYangEnumerationToXmlTest() {
+ String elName = "lfEnumeration";
+ serializeToXml(
+ prepareCnStructForYangData(TypeDefinitionAwareCodec.ENUMERATION_DEFAULT_CODEC.deserialize("enum2"),
+ elName), "<" + elName + ">enum2</" + elName + ">");
+ }
+
+ @Test
+ public void snAsYangEmptyToXmlTest() {
+ String elName = "lfEmpty";
+ serializeToXml(
+ prepareCnStructForYangData(TypeDefinitionAwareCodec.EMPTY_DEFAULT_CODEC.deserialize(null), elName), "<"
+ + elName + "/>");
+ }
+
+ @Test
+ public void snAsYangBooleanToXmlTest() {
+ String elName = "lfBoolean";
+ serializeToXml(
+ prepareCnStructForYangData(TypeDefinitionAwareCodec.BOOLEAN_DEFAULT_CODEC.deserialize("str"), elName),
+ "<" + elName + ">false</" + elName + ">");
+ serializeToXml(
+ prepareCnStructForYangData(TypeDefinitionAwareCodec.BOOLEAN_DEFAULT_CODEC.deserialize("true"), elName),
+ "<" + elName + ">true</" + elName + ">");
+ }
+
+ @Test
+ public void snAsYangUnionToXmlTest() {
+ String elName = "lfUnion";
+ String int8 = "15";
+ serializeToXml(
+ prepareCnStructForYangData(TypeDefinitionAwareCodec.UNION_DEFAULT_CODEC.deserialize(int8), elName), "<"
+ + elName + ">15</" + elName + ">");
+
+ String bits = "first second";
+ serializeToXml(
+ prepareCnStructForYangData(TypeDefinitionAwareCodec.UNION_DEFAULT_CODEC.deserialize(bits), elName), "<"
+ + elName + ">first second</" + elName + ">");
+
+ String bool = "str";
+ serializeToXml(
+ prepareCnStructForYangData(TypeDefinitionAwareCodec.UNION_DEFAULT_CODEC.deserialize(bool), elName), "<"
+ + elName + ">str</" + elName + ">");
+ }
+
+ private void serializeToXml(CompositeNode compositeNode, String... xmlRepresentation)
+ throws TransformerFactoryConfigurationError {
+ XmlMapper xmlMapper = new XmlMapper();
+ String xmlString = null;
+ if (dataSchemaNode instanceof DataNodeContainer) {
+ try {
+ Document doc = xmlMapper.write(compositeNode, (DataNodeContainer) dataSchemaNode);
+ DOMSource domSource = new DOMSource(doc);
+ StringWriter writer = new StringWriter();
+ StreamResult result = new StreamResult(writer);
+ TransformerFactory tf = TransformerFactory.newInstance();
+ Transformer transformer = tf.newTransformer();
+ transformer.transform(domSource, result);
+ xmlString = writer.toString();
+ } catch (UnsupportedDataTypeException | TransformerException e) {
+ }
+ }
+ assertNotNull(xmlMapper);
+ boolean containSearchedStr = false;
+ String strRepresentation = "";
+ for (String searchedStr : xmlRepresentation) {
+ if (xmlString.contains(searchedStr)) {
+ containSearchedStr = true;
+ break;
+ }
+ strRepresentation = strRepresentation + "[" + searchedStr + "]";
+ }
+ assertTrue("At least one of specified strings " + strRepresentation + " wasn't found.", containSearchedStr);
+
+ }
+
+ private CompositeNode prepareIdentityrefData() {
+ MutableCompositeNode cont = NodeFactory.createMutableCompositeNode(
+ TestUtils.buildQName("cont", "basic:module", "2013-12-2"), null, null, ModifyAction.CREATE, null);
+ MutableCompositeNode cont1 = NodeFactory.createMutableCompositeNode(
+ TestUtils.buildQName("cont1", "basic:module", "2013-12-2"), cont, null, ModifyAction.CREATE, null);
+ cont.getChildren().add(cont1);
+
+ MutableSimpleNode<Object> lf11 = NodeFactory.createMutableSimpleNode(
+ TestUtils.buildQName("lf11", "basic:module", "2013-12-2"), cont1,
+ TestUtils.buildQName("iden", "referenced:module", "2013-12-2"), ModifyAction.CREATE, null);
+ cont1.getChildren().add(lf11);
+ cont1.init();
+ cont.init();
+
+ return cont;
+ }
+
+ private CompositeNode prepareCnStructForYangData(Object data, String leafName) {
+ MutableCompositeNode cont = NodeFactory.createMutableCompositeNode(TestUtils.buildQName("cont"), null, null,
+ ModifyAction.CREATE, null);
+
+ MutableSimpleNode<Object> lf1 = NodeFactory.createMutableSimpleNode(TestUtils.buildQName(leafName), cont, data,
+ ModifyAction.CREATE, null);
+ cont.getChildren().add(lf1);
+ cont.init();
+
+ return cont;
+ }
+
+}
-package org.opendaylight.controller.sal.restconf.impl.test;
+package org.opendaylight.controller.sal.restconf.impl.json.to.cnsn.test;
-import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertNotNull;
-import static org.junit.Assert.assertTrue;
+import static org.junit.Assert.*;
-import java.io.FileNotFoundException;
-import java.io.IOException;
-import java.io.InputStream;
+import java.io.*;
import java.net.URISyntaxException;
import java.util.List;
+import java.util.Set;
import javax.ws.rs.WebApplicationException;
import org.junit.Test;
import org.opendaylight.controller.sal.rest.impl.JsonToCompositeNodeProvider;
import org.opendaylight.controller.sal.restconf.impl.CompositeNodeWrapper;
-import org.opendaylight.yangtools.yang.data.api.CompositeNode;
-import org.opendaylight.yangtools.yang.data.api.Node;
-import org.opendaylight.yangtools.yang.data.api.SimpleNode;
+import org.opendaylight.controller.sal.restconf.impl.test.TestUtils;
+import org.opendaylight.yangtools.yang.common.QName;
+import org.opendaylight.yangtools.yang.data.api.*;
import org.opendaylight.yangtools.yang.model.api.DataSchemaNode;
+import org.opendaylight.yangtools.yang.model.api.Module;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import com.google.gson.JsonSyntaxException;
-public class FromJsonToCompositeNodeTest {
+public class JsonToCnSnTest {
- private static final Logger LOG = LoggerFactory.getLogger(FromJsonToCompositeNodeTest.class);
+ private static final Logger LOG = LoggerFactory.getLogger(JsonToCnSnTest.class);
@Test
public void simpleListTest() {
- simpleTest("/json-to-composite-node/simple-list.json", "/json-to-composite-node/simple-list-yang", "lst",
- "simple:list:yang1", "simple-list-yang1");
+ simpleTest("/json-to-cnsn/simple-list.json", "/json-to-cnsn/simple-list-yang", "lst", "simple:list:yang1",
+ "simple-list-yang1");
}
@Test
public void simpleContainerTest() {
- simpleTest("/json-to-composite-node/simple-container.json", "/json-to-composite-node/simple-container-yang",
- "cont", "simple:container:yang", "simple-container-yang");
+ simpleTest("/json-to-cnsn/simple-container.json", "/json-to-cnsn/simple-container-yang", "cont",
+ "simple:container:yang", "simple-container-yang");
}
/**
*/
@Test
public void multipleItemsInLeafList() {
- CompositeNode compositeNode = compositeContainerFromJson(
- "/json-to-composite-node/multiple-leaflist-items.json", true);
+ CompositeNode compositeNode = compositeContainerFromJson("/json-to-cnsn/multiple-leaflist-items.json", true);
assertNotNull(compositeNode);
assertEquals(3, compositeNode.getChildren().size());
*/
@Test
public void multipleItemsInListTest() {
- CompositeNode compositeNode = compositeContainerFromJson("/json-to-composite-node/multiple-items-in-list.json",
- true);
+ CompositeNode compositeNode = compositeContainerFromJson("/json-to-cnsn/multiple-items-in-list.json", true);
assertNotNull(compositeNode);
assertEquals("lst", compositeNode.getNodeType().getLocalName());
@Test
public void nullArrayToSimpleNodeWithNullValueTest() {
- CompositeNode compositeNode = compositeContainerFromJson("/json-to-composite-node/array-with-null.json", true);
+ CompositeNode compositeNode = compositeContainerFromJson("/json-to-cnsn/array-with-null.json", true);
assertNotNull(compositeNode);
assertEquals("cont", compositeNode.getNodeType().getLocalName());
public void incorrectTopLevelElementsTest() {
Throwable cause1 = null;
try {
- compositeContainerFromJson("/json-to-composite-node/wrong-top-level1.json", true);
+ compositeContainerFromJson("/json-to-cnsn/wrong-top-level1.json", true);
} catch (WebApplicationException e) {
cause1 = e;
}
Throwable cause2 = null;
try {
- compositeContainerFromJson("/json-to-composite-node/wrong-top-level2.json", true);
+ compositeContainerFromJson("/json-to-cnsn/wrong-top-level2.json", true);
} catch (WebApplicationException e) {
cause2 = e;
}
Throwable cause3 = null;
try {
- compositeContainerFromJson("/json-to-composite-node/wrong-top-level3.json", true);
+ compositeContainerFromJson("/json-to-cnsn/wrong-top-level3.json", true);
} catch (WebApplicationException e) {
cause3 = e;
}
*/
@Test
public void emptyDataReadTest() {
- CompositeNode compositeNode = compositeContainerFromJson("/json-to-composite-node/empty-data.json", true);
+ CompositeNode compositeNode = compositeContainerFromJson("/json-to-cnsn/empty-data.json", true);
assertNotNull(compositeNode);
String reason = null;
try {
- compositeContainerFromJson("/json-to-composite-node/empty-data1.json", true);
+ compositeContainerFromJson("/json-to-cnsn/empty-data1.json", true);
} catch (JsonSyntaxException e) {
reason = e.getMessage();
}
@Test
public void notSupplyNamespaceIfAlreadySupplied() {
- CompositeNode compositeNode = compositeContainerFromJson("/json-to-composite-node/simple-list.json");
+ CompositeNode compositeNode = compositeContainerFromJson("/json-to-cnsn/simple-list.json");
assertNotNull(compositeNode);
DataSchemaNode dataSchemaNode1 = null;
DataSchemaNode dataSchemaNode2 = null;
try {
- dataSchemaNode1 = TestUtils.obtainSchemaFromYang("/json-to-composite-node/simple-list-yang",
- "simple-list-yang1");
- dataSchemaNode2 = TestUtils.obtainSchemaFromYang("/json-to-composite-node/simple-list-yang",
- "simple-list-yang2");
+ dataSchemaNode1 = TestUtils.obtainSchemaFromYang("/json-to-cnsn/simple-list-yang", "simple-list-yang1");
+ dataSchemaNode2 = TestUtils.obtainSchemaFromYang("/json-to-cnsn/simple-list-yang", "simple-list-yang2");
} catch (FileNotFoundException e) {
LOG.error(e.getMessage());
assertTrue(false);
}
+ @Test
+ public void jsonIdentityrefToCompositeNode() {
+ CompositeNode compositeNode = compositeContainerFromJson("/json-to-cnsn/identityref/json/data.json");
+ assertNotNull(compositeNode);
+
+ Set<Module> modules = TestUtils.resolveModules("/json-to-cnsn/identityref");
+ assertEquals(2, modules.size());
+ Module module = TestUtils.resolveModule("identityref-module", modules);
+ assertNotNull(module);
+ DataSchemaNode dataSchemaNode = TestUtils.resolveDataSchemaNode(module, null);
+ assertNotNull(dataSchemaNode);
+
+ TestUtils.normalizeCompositeNode(compositeNode, modules, dataSchemaNode, "identityref-module:cont");
+
+ assertEquals("cont", compositeNode.getNodeType().getLocalName());
+
+ List<Node<?>> childs = compositeNode.getChildren();
+ assertEquals(1, childs.size());
+ Node<?> nd = childs.iterator().next();
+ assertTrue(nd instanceof CompositeNode);
+ assertEquals("cont1", nd.getNodeType().getLocalName());
+
+ childs = ((CompositeNode) nd).getChildren();
+ assertEquals(4, childs.size());
+ SimpleNode<?> lf11 = null;
+ SimpleNode<?> lf12 = null;
+ SimpleNode<?> lf13 = null;
+ SimpleNode<?> lf14 = null;
+ for (Node<?> child : childs) {
+ assertTrue(child instanceof SimpleNode);
+ if (child.getNodeType().getLocalName().equals("lf11")) {
+ lf11 = (SimpleNode<?>) child;
+ } else if (child.getNodeType().getLocalName().equals("lf12")) {
+ lf12 = (SimpleNode<?>) child;
+ } else if (child.getNodeType().getLocalName().equals("lf13")) {
+ lf13 = (SimpleNode<?>) child;
+ } else if (child.getNodeType().getLocalName().equals("lf14")) {
+ lf14 = (SimpleNode<?>) child;
+ }
+ }
+
+ assertTrue(lf11.getValue() instanceof QName);
+ assertEquals("iden", ((QName) lf11.getValue()).getLocalName());
+ assertEquals("identity:module", ((QName) lf11.getValue()).getNamespace().toString());
+
+ assertTrue(lf12.getValue() instanceof QName);
+ assertEquals("iden_local", ((QName) lf12.getValue()).getLocalName());
+ assertEquals("identityref:module", ((QName) lf12.getValue()).getNamespace().toString());
+
+ assertTrue(lf13.getValue() instanceof QName);
+ assertEquals("iden_local", ((QName) lf13.getValue()).getLocalName());
+ assertEquals("identityref:module", ((QName) lf13.getValue()).getNamespace().toString());
+
+ assertTrue(lf14.getValue() instanceof QName);
+ assertEquals("iden_local", ((QName) lf14.getValue()).getLocalName());
+ assertEquals("identity:module", ((QName) lf14.getValue()).getNamespace().toString());
+ }
+
private void simpleTest(String jsonPath, String yangPath, String topLevelElementName, String namespace,
String moduleName) {
CompositeNode compositeNode = compositeContainerFromJson(jsonPath);
throws WebApplicationException {
JsonToCompositeNodeProvider jsonToCompositeNodeProvider = JsonToCompositeNodeProvider.INSTANCE;
- InputStream jsonStream = FromJsonToCompositeNodeTest.class.getResourceAsStream(jsonPath);
+ InputStream jsonStream = JsonToCnSnTest.class.getResourceAsStream(jsonPath);
try {
CompositeNode compositeNode = jsonToCompositeNodeProvider
.readFrom(null, null, null, null, null, jsonStream);
--- /dev/null
+package org.opendaylight.controller.sal.restconf.impl.test;
+
+import static org.junit.Assert.assertEquals;
+import static org.mockito.Matchers.any;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.when;
+
+import java.io.FileNotFoundException;
+import java.io.UnsupportedEncodingException;
+import java.net.URI;
+import java.net.URLEncoder;
+import java.util.List;
+import java.util.Set;
+import java.util.logging.Level;
+import java.util.logging.LogRecord;
+
+import javax.ws.rs.core.Application;
+import javax.ws.rs.core.MediaType;
+import javax.ws.rs.core.Response;
+
+import org.glassfish.jersey.server.ResourceConfig;
+import org.glassfish.jersey.test.JerseyTest;
+import org.glassfish.jersey.test.TestProperties;
+import org.junit.Before;
+import org.junit.BeforeClass;
+import org.junit.Test;
+import org.opendaylight.controller.sal.rest.impl.StructuredDataToXmlProvider;
+import org.opendaylight.controller.sal.rest.impl.XmlToCompositeNodeProvider;
+import org.opendaylight.controller.sal.restconf.impl.BrokerFacade;
+import org.opendaylight.controller.sal.restconf.impl.ControllerContext;
+import org.opendaylight.controller.sal.restconf.impl.RestconfImpl;
+import org.opendaylight.yangtools.yang.data.api.CompositeNode;
+import org.opendaylight.yangtools.yang.data.api.InstanceIdentifier;
+import org.opendaylight.yangtools.yang.model.api.Module;
+import org.opendaylight.yangtools.yang.model.api.SchemaContext;
+
+import com.google.common.base.Charsets;
+
+public class ReadConfAndOperDataTest extends JerseyTest {
+
+ private static ControllerContext controllerContext;
+ private static BrokerFacade brokerFacade;
+ private static RestconfImpl restconfImpl;
+ private static final MediaType MEDIA_TYPE_DRAFT02 = new MediaType("application", "yang.data+xml");
+
+ @BeforeClass
+ public static void init() throws FileNotFoundException {
+ Set<Module> allModules = TestUtils.loadModules(RestconfImplTest.class.getResource("/full-versions/yangs")
+ .getPath());
+ SchemaContext schemaContext = TestUtils.loadSchemaContext(allModules);
+ controllerContext = ControllerContext.getInstance();
+ controllerContext.setSchemas(schemaContext);
+ brokerFacade = mock(BrokerFacade.class);
+ restconfImpl = RestconfImpl.getInstance();
+ restconfImpl.setBroker(brokerFacade);
+ restconfImpl.setControllerContext(controllerContext);
+ }
+
+ @Before
+ public void logs() {
+ List<LogRecord> loggedRecords = getLoggedRecords();
+ for (LogRecord l : loggedRecords) {
+ System.out.println(l.getMessage());
+ }
+ }
+
+ @Test
+ public void testReadConfigurationData() throws UnsupportedEncodingException, FileNotFoundException {
+
+ String uri = createUri("/config/", "ietf-interfaces:interfaces/interface/eth0");
+
+ CompositeNode loadedCompositeNode = TestUtils.loadCompositeNodeWithXmlTreeBuilder("/parts/ietf-interfaces_interfaces.xml");
+ when(brokerFacade.readConfigurationData(any(InstanceIdentifier.class))).thenReturn(loadedCompositeNode);
+
+ Response response = target(uri).request(MEDIA_TYPE_DRAFT02).get();
+ assertEquals(200, response.getStatus());
+
+ uri = createUri("/config/", "ietf-interfaces:interfaces/interface/example");
+ when(brokerFacade.readConfigurationData(any(InstanceIdentifier.class))).thenReturn(null);
+
+ response = target(uri).request(MEDIA_TYPE_DRAFT02).get();
+ assertEquals(404, response.getStatus());
+ }
+
+ @Test
+ public void testReadOperationalData() throws UnsupportedEncodingException, FileNotFoundException {
+ String uri = createUri("/operational/", "ietf-interfaces:interfaces/interface/eth0");
+
+ CompositeNode loadedCompositeNode = TestUtils.loadCompositeNodeWithXmlTreeBuilder("/parts/ietf-interfaces_interfaces.xml");
+ when(brokerFacade.readOperationalData(any(InstanceIdentifier.class))).thenReturn(loadedCompositeNode);
+
+ Response response = target(uri).request(MEDIA_TYPE_DRAFT02).get();
+ assertEquals(200, response.getStatus());
+
+ uri = createUri("/config/", "ietf-interfaces:interfaces/interface/example");
+ when(brokerFacade.readConfigurationData(any(InstanceIdentifier.class))).thenReturn(null);
+
+ response = target(uri).request(MEDIA_TYPE_DRAFT02).get();
+ assertEquals(404, response.getStatus());
+ }
+
+ private String createUri(String prefix, String encodedPart) throws UnsupportedEncodingException {
+ return URI.create(prefix + URLEncoder.encode(encodedPart, Charsets.US_ASCII.name()).toString()).toASCIIString();
+ }
+
+ @Override
+ protected Application configure() {
+ enable(TestProperties.LOG_TRAFFIC);
+ enable(TestProperties.DUMP_ENTITY);
+ enable(TestProperties.RECORD_LOG_LEVEL);
+ set(TestProperties.RECORD_LOG_LEVEL, Level.ALL.intValue());
+
+ ResourceConfig resourceConfig = new ResourceConfig();
+ resourceConfig = resourceConfig.registerInstances(restconfImpl, StructuredDataToXmlProvider.INSTANCE,
+ XmlToCompositeNodeProvider.INSTANCE);
+ return resourceConfig;
+ }
+}
package org.opendaylight.controller.sal.restconf.impl.test;
-import static org.mockito.Mockito.*;
-import static org.junit.Assert.*;
+import static org.junit.Assert.assertEquals;
+import static org.mockito.Matchers.any;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.when;
import java.io.FileNotFoundException;
import java.io.InputStream;
import org.junit.BeforeClass;
import org.junit.Test;
-import org.opendaylight.controller.sal.restconf.impl.BrokerFacade;
-import org.opendaylight.controller.sal.restconf.impl.ControllerContext;
-import org.opendaylight.controller.sal.restconf.impl.RestconfImpl;
+import org.opendaylight.controller.sal.restconf.impl.*;
import org.opendaylight.yangtools.yang.data.api.CompositeNode;
import org.opendaylight.yangtools.yang.data.api.InstanceIdentifier;
import org.opendaylight.yangtools.yang.model.api.Module;
@BeforeClass
public static void init() throws FileNotFoundException {
- Set<Module> allModules = TestUtils.loadModules(RestconfImplTest.class.getResource("/full-versions/yangs").getPath());
+ Set<Module> allModules = TestUtils.loadModules(RestconfImplTest.class.getResource("/full-versions/yangs")
+ .getPath());
SchemaContext schemaContext = TestUtils.loadSchemaContext(allModules);
ControllerContext controllerContext = ControllerContext.getInstance();
controllerContext.setSchemas(schemaContext);
@Test
public void testExample() throws FileNotFoundException {
InputStream xmlStream = RestconfImplTest.class.getResourceAsStream("/parts/ietf-interfaces_interfaces.xml");
- CompositeNode loadedCompositeNode = TestUtils.loadCompositeNode(xmlStream);
+ CompositeNode loadedCompositeNode = TestUtils.loadCompositeNodeWithXmlTreeBuilder(xmlStream);
BrokerFacade brokerFacade = mock(BrokerFacade.class);
when(brokerFacade.readOperationalData(any(InstanceIdentifier.class))).thenReturn(loadedCompositeNode);
assertEquals(loadedCompositeNode, brokerFacade.readOperationalData(null));
package org.opendaylight.controller.sal.restconf.impl.test;
-import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertNotNull;
import static org.mockito.Matchers.any;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.when;
import java.io.*;
-import java.net.*;
+import java.net.URI;
+import java.net.URISyntaxException;
import java.sql.Date;
import java.util.*;
import java.util.concurrent.Future;
import javax.xml.transform.stream.StreamResult;
import org.opendaylight.controller.md.sal.common.api.TransactionStatus;
-import org.opendaylight.controller.sal.rest.impl.StructuredDataToJsonProvider;
+import org.opendaylight.controller.sal.rest.impl.*;
import org.opendaylight.controller.sal.restconf.impl.*;
-import org.opendaylight.yangtools.yang.common.*;
+import org.opendaylight.yangtools.yang.common.QName;
+import org.opendaylight.yangtools.yang.common.RpcResult;
import org.opendaylight.yangtools.yang.data.api.*;
import org.opendaylight.yangtools.yang.data.impl.XmlTreeBuilder;
import org.opendaylight.yangtools.yang.model.api.*;
import org.opendaylight.yangtools.yang.model.parser.api.YangModelParser;
import org.opendaylight.yangtools.yang.parser.impl.YangParserImpl;
-import org.slf4j.*;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
import org.w3c.dom.Document;
import org.xml.sax.SAXException;
import com.google.common.base.Preconditions;
-final class TestUtils {
+public final class TestUtils {
private static final Logger logger = LoggerFactory.getLogger(TestUtils.class);
return result;
}
- public static CompositeNode loadCompositeNode(InputStream xmlInputStream) throws FileNotFoundException {
- if (xmlInputStream == null) {
- throw new IllegalArgumentException();
- }
- Node<?> dataTree;
- try {
- dataTree = XmlTreeBuilder.buildDataTree(xmlInputStream);
- } catch (XMLStreamException e) {
- logger.error("Error during building data tree from XML", e);
- return null;
- }
- if (dataTree == null) {
- logger.error("data tree is null");
- return null;
- }
- if (dataTree instanceof SimpleNode) {
- logger.error("RPC XML was resolved as SimpleNode");
- return null;
- }
- return (CompositeNode) dataTree;
- }
+
public static Document loadDocumentFrom(InputStream inputStream) {
try {
}
- static String convertCompositeNodeDataAndYangToJson(CompositeNode compositeNode, String yangPath, String outputPath) {
- return convertCompositeNodeDataAndYangToJson(compositeNode, yangPath, outputPath, null, null);
- }
-
- static String convertCompositeNodeDataAndYangToJson(CompositeNode compositeNode, String yangPath,
+ public static String convertCompositeNodeDataAndYangToJson(CompositeNode compositeNode, String yangPath,
String outputPath, String searchedModuleName, String searchedDataSchemaName) {
Set<Module> modules = resolveModules(yangPath);
Module module = resolveModule(searchedModuleName, modules);
DataSchemaNode dataSchemaNode = resolveDataSchemaNode(module, searchedDataSchemaName);
+ normalizeCompositeNode(compositeNode, modules, dataSchemaNode, searchedModuleName + ":"
+ + searchedDataSchemaName);
+
try {
- return writeCompNodeWithSchemaContextToJson(compositeNode, outputPath, modules, dataSchemaNode);
+ return writeCompNodeWithSchemaContextToJson(compositeNode, modules, dataSchemaNode);
} catch (WebApplicationException | IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
- static Module resolveModule(String searchedModuleName, Set<Module> modules) {
+ public static void normalizeCompositeNode(CompositeNode compositeNode, Set<Module> modules,
+ DataSchemaNode dataSchemaNode, String schemaNodePath) {
+ RestconfImpl restconf = RestconfImpl.getInstance();
+ ControllerContext.getInstance().setSchemas(TestUtils.loadSchemaContext(modules));
+
+ TestUtils.prepareMockForRestconfBeforeNormalization(modules, dataSchemaNode, restconf);
+ restconf.createConfigurationData(schemaNodePath, compositeNode);
+ }
+
+ public static Module resolveModule(String searchedModuleName, Set<Module> modules) {
assertNotNull("modules can't be null.", modules);
Module module = null;
if (searchedModuleName != null) {
return module;
}
- static Set<Module> resolveModules(String yangPath) {
+ public static Set<Module> resolveModules(String yangPath) {
Set<Module> modules = null;
try {
- modules = TestUtils.loadModules(ToJsonBasicDataTypesTest.class.getResource(yangPath).getPath());
+ modules = TestUtils.loadModules(TestUtils.class.getResource(yangPath).getPath());
} catch (FileNotFoundException e) {
e.printStackTrace();
}
return modules;
}
- static DataSchemaNode resolveDataSchemaNode(Module module, String searchedDataSchemaName) {
+ public static DataSchemaNode resolveDataSchemaNode(Module module, String searchedDataSchemaName) {
assertNotNull("Module is missing", module);
DataSchemaNode dataSchemaNode = null;
return dataSchemaNode;
}
- static String writeCompNodeWithSchemaContextToJson(CompositeNode compositeNode, String outputPath,
- Set<Module> modules, DataSchemaNode dataSchemaNode) throws IOException, WebApplicationException {
+ public static String writeCompNodeWithSchemaContextToJson(CompositeNode compositeNode, Set<Module> modules,
+ DataSchemaNode dataSchemaNode) throws IOException, WebApplicationException {
String jsonResult;
assertNotNull(dataSchemaNode);
assertNotNull("Composite node can't be null", compositeNode);
ByteArrayOutputStream byteArrayOS = new ByteArrayOutputStream();
- ControllerContext contContext = ControllerContext.getInstance();
- contContext.setSchemas(loadSchemaContext(modules));
+ ControllerContext.getInstance().setSchemas(loadSchemaContext(modules));
StructuredDataToJsonProvider structuredDataToJsonProvider = StructuredDataToJsonProvider.INSTANCE;
structuredDataToJsonProvider.writeTo(new StructuredData(compositeNode, dataSchemaNode), null, null, null, null,
null, byteArrayOS);
jsonResult = byteArrayOS.toString();
- if (outputPath != null) {
- try {
- outputToFile(byteArrayOS, outputPath);
- } catch (IOException e) {
- System.out.println("Output file wasn't cloased sucessfuly.");
- }
- }
return jsonResult;
}
- static CompositeNode loadCompositeNode(String xmlDataPath) {
- InputStream xmlStream = ToJsonBasicDataTypesTest.class.getResourceAsStream(xmlDataPath);
+ public static CompositeNode loadCompositeNode(String xmlDataPath) {
+ InputStream xmlStream = TestUtils.class.getResourceAsStream(xmlDataPath);
CompositeNode compositeNode = null;
try {
- compositeNode = TestUtils.loadCompositeNode(xmlStream);
- } catch (FileNotFoundException e) {
+ XmlReader xmlReader = new XmlReader();
+ compositeNode = xmlReader.read(xmlStream);
+
+ } catch (UnsupportedFormatException | XMLStreamException e) {
e.printStackTrace();
}
return compositeNode;
static void outputToFile(ByteArrayOutputStream outputStream, String outputDir) throws IOException {
FileOutputStream fileOS = null;
try {
- String path = ToJsonBasicDataTypesTest.class.getResource(outputDir).getPath();
+ String path = TestUtils.class.getResource(outputDir).getPath();
File outFile = new File(path + "/data.json");
fileOS = new FileOutputStream(outFile);
try {
}
private static FileReader getFileReader(String path) {
- String fullPath = ToJsonBasicDataTypesTest.class.getResource(path).getPath();
+ String fullPath = TestUtils.class.getResource(path).getPath();
assertNotNull("Path to file can't be null.", fullPath);
File file = new File(fullPath);
assertNotNull("File can't be null", file);
return strBuilder.toString();
}
- static QName buildQName(String name, String uri, String date) {
+ public static QName buildQName(String name, String uri, String date) {
try {
URI u = new URI(uri);
Date dt = null;
}
}
- static QName buildQName(String name) {
+ public static QName buildQName(String name) {
return buildQName(name, "", null);
}
- static void supplementNamespace(DataSchemaNode dataSchemaNode, CompositeNode compositeNode) {
+ public static void supplementNamespace(DataSchemaNode dataSchemaNode, CompositeNode compositeNode) {
RestconfImpl restconf = RestconfImpl.getInstance();
InstanceIdWithSchemaNode instIdAndSchema = new InstanceIdWithSchemaNode(mock(InstanceIdentifier.class),
restconf.createConfigurationData("something", compositeNode);
}
- static DataSchemaNode obtainSchemaFromYang(String yangFolder) throws FileNotFoundException {
+ public static DataSchemaNode obtainSchemaFromYang(String yangFolder) throws FileNotFoundException {
return obtainSchemaFromYang(yangFolder, null);
}
- static DataSchemaNode obtainSchemaFromYang(String yangFolder, String moduleName) throws FileNotFoundException {
+ public static DataSchemaNode obtainSchemaFromYang(String yangFolder, String moduleName)
+ throws FileNotFoundException {
Set<Module> modules = null;
- modules = TestUtils.loadModules(ToJsonBasicDataTypesTest.class.getResource(yangFolder).getPath());
+ modules = TestUtils.loadModules(TestUtils.class.getResource(yangFolder).getPath());
if (modules == null) {
return null;
}
- static void addDummyNamespaceToAllNodes(NodeWrapper<?> wrappedNode) throws URISyntaxException {
+ public static void addDummyNamespaceToAllNodes(NodeWrapper<?> wrappedNode) throws URISyntaxException {
wrappedNode.setNamespace(new URI(""));
if (wrappedNode instanceof CompositeNodeWrapper) {
for (NodeWrapper<?> childNodeWrapper : ((CompositeNodeWrapper) wrappedNode).getValues()) {
}
}
+ public static void prepareMockForRestconfBeforeNormalization(Set<Module> modules, DataSchemaNode dataSchemaNode,
+ RestconfImpl restconf) {
+ ControllerContext instance = ControllerContext.getInstance();
+ instance.setSchemas(TestUtils.loadSchemaContext(modules));
+ restconf.setControllerContext(ControllerContext.getInstance());
+
+ BrokerFacade mockedBrokerFacade = mock(BrokerFacade.class);
+ when(mockedBrokerFacade.commitConfigurationDataPut(any(InstanceIdentifier.class), any(CompositeNode.class)))
+ .thenReturn(
+ new DummyFuture.Builder().rpcResult(
+ new DummyRpcResult.Builder<TransactionStatus>().result(TransactionStatus.COMMITED)
+ .build()).build());
+ restconf.setBroker(mockedBrokerFacade);
+ }
+
+ static CompositeNode loadCompositeNodeWithXmlTreeBuilder(String xmlDataPath) {
+ InputStream xmlStream = TestUtils.class.getResourceAsStream(xmlDataPath);
+ CompositeNode compositeNode = null;
+ try {
+ compositeNode = TestUtils.loadCompositeNodeWithXmlTreeBuilder(xmlStream);
+ } catch (FileNotFoundException e) {
+ e.printStackTrace();
+ }
+ return compositeNode;
+
+
+
+ }
+
+
+ public static CompositeNode loadCompositeNodeWithXmlTreeBuilder(InputStream xmlInputStream) throws FileNotFoundException {
+ if (xmlInputStream == null) {
+ throw new IllegalArgumentException();
+ }
+ Node<?> dataTree;
+ try {
+ dataTree = XmlTreeBuilder.buildDataTree(xmlInputStream);
+ } catch (XMLStreamException e) {
+ logger.error("Error during building data tree from XML", e);
+ return null;
+ }
+ if (dataTree == null) {
+ logger.error("data tree is null");
+ return null;
+ }
+ if (dataTree instanceof SimpleNode) {
+ logger.error("RPC XML was resolved as SimpleNode");
+ return null;
+ }
+ return (CompositeNode) dataTree;
+ }
+
}
+++ /dev/null
-package org.opendaylight.controller.sal.restconf.impl.test;
-
-import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertFalse;
-import static org.junit.Assert.assertNotNull;
-import static org.junit.Assert.assertNull;
-import static org.junit.Assert.assertTrue;
-
-import java.io.*;
-import java.util.*;
-
-import org.junit.Test;
-
-import com.google.gson.stream.*;
-
-public class ToJsonBasicDataTypesTest {
-
- @Test
- public void simpleYangDataTest() {
- String jsonOutput;
- jsonOutput = TestUtils.convertCompositeNodeDataAndYangToJson(
- TestUtils.loadCompositeNode("/yang-to-json-conversion/simple-data-types/xml/data.xml"),
- "/yang-to-json-conversion/simple-data-types", "/yang-to-json-conversion/simple-data-types/xml");
- verifyJsonOutput(jsonOutput);
- }
-
- private void verifyJsonOutput(String jsonOutput) {
- StringReader strReader = new StringReader(jsonOutput);
- JsonReader jReader = new JsonReader(strReader);
-
- String exception = null;
- try {
- jsonReadCont(jReader);
- } catch (IOException e) {
- exception = e.getMessage();
- }
-
- assertNull("Error during reading Json output: " + exception, exception);
- }
-
- private void jsonReadCont(JsonReader jReader) throws IOException {
- jReader.beginObject();
- assertNotNull("cont1 is missing.", jReader.hasNext());
-
- // Cont dataFromJson = new Cont(jReader.nextName());
- jReader.nextName();
- jsonReadContElements(jReader);
-
- assertFalse("cont shouldn't have other element.", jReader.hasNext());
- jReader.endObject();
- // return dataFromJson;
- }
-
- private void jsonReadContElements(JsonReader jReader) throws IOException {
- jReader.beginObject();
- List<String> loadedLfs = new ArrayList<>();
- boolean exceptForDecimal5Raised = false;
- boolean enumChecked = false;
- boolean bitsChecked = false;
- boolean lfdecimal6Checked = false;
- boolean lfdecimal4Checked = false;
- boolean lfdecimal3Checked = false;
- boolean lfdecimal2Checked = false;
- boolean lfdecimal1Checked = false;
- boolean lfbool1Checked = false;
- boolean lfbool2Checked = false;
- boolean lfstrChecked = false;
- boolean lfbinaryChecked = false;
- // boolean lfref1Checked = false;
- boolean lfemptyChecked = false;
- boolean lfstr1Checked = false;
-
- while (jReader.hasNext()) {
- String keyName = jReader.nextName();
- JsonToken peek = null;
- try {
- peek = jReader.peek();
- } catch (IOException e) {
- if (keyName.equals("lfdecimal5")) {
- exceptForDecimal5Raised = true;
- } else {
- assertTrue("Key " + keyName + " has incorrect value for specifed type", false);
- }
- }
-
- if (keyName.startsWith("lfnint") || keyName.startsWith("lfnuint")) {
- assertEquals("Key " + keyName + " has incorrect type", JsonToken.NUMBER, peek);
- try {
- jReader.nextLong();
- } catch (NumberFormatException e) {
- assertTrue("Key " + keyName + " has incorrect value - " + e.getMessage(), false);
- }
- loadedLfs.add(keyName.substring(3));
- } else if (keyName.equals("lfstr")) {
- assertEquals("Key " + keyName + " has incorrect type", JsonToken.STRING, peek);
- assertEquals("lfstr", jReader.nextString());
- lfstrChecked = true;
- } else if (keyName.equals("lfstr1")) {
- assertEquals("Key " + keyName + " has incorrect type", JsonToken.STRING, peek);
- assertEquals("", jReader.nextString());
- lfstr1Checked = true;
- } else if (keyName.equals("lfbool1")) {
- assertEquals("Key " + keyName + " has incorrect type", JsonToken.BOOLEAN, peek);
- assertEquals(true, jReader.nextBoolean());
- lfbool1Checked = true;
- } else if (keyName.equals("lfbool2")) {
- assertEquals("Key " + keyName + " has incorrect type", JsonToken.BOOLEAN, peek);
- assertEquals(false, jReader.nextBoolean());
- lfbool2Checked = true;
- } else if (keyName.equals("lfbool3")) {
- assertEquals("Key " + keyName + " has incorrect type", JsonToken.BOOLEAN, peek);
- assertEquals(false, jReader.nextBoolean());
- } else if (keyName.equals("lfdecimal1")) {
- assertEquals("Key " + keyName + " has incorrect type", JsonToken.NUMBER, peek);
- assertEquals(new Double(43.32), (Double) jReader.nextDouble());
- lfdecimal1Checked = true;
- } else if (keyName.equals("lfdecimal2")) {
- assertEquals("Key " + keyName + " has incorrect type", JsonToken.NUMBER, peek);
- assertEquals(new Double(-0.43), (Double) jReader.nextDouble());
- lfdecimal2Checked = true;
- } else if (keyName.equals("lfdecimal3")) {
- assertEquals("Key " + keyName + " has incorrect type", JsonToken.NUMBER, peek);
- assertEquals(new Double(43), (Double) jReader.nextDouble());
- lfdecimal3Checked = true;
- } else if (keyName.equals("lfdecimal4")) {
- assertEquals("Key " + keyName + " has incorrect type", JsonToken.NUMBER, peek);
- assertEquals(new Double(43E3), (Double) jReader.nextDouble());
- lfdecimal4Checked = true;
- } else if (keyName.equals("lfdecimal6")) {
- assertEquals("Key " + keyName + " has incorrect type", JsonToken.NUMBER, peek);
- assertEquals(new Double(33.12345), (Double) jReader.nextDouble());
- lfdecimal6Checked = true;
- } else if (keyName.equals("lfenum")) {
- assertEquals("enum3", jReader.nextString());
- enumChecked = true;
- } else if (keyName.equals("lfbits")) {
- assertEquals("bit3", jReader.nextString());
- bitsChecked = true;
- } else if (keyName.equals("lfbinary")) {
- assertEquals("AAaacdabcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ%%-#^", jReader.nextString());
- lfbinaryChecked = true;
- } else if (keyName.equals("lfempty")) {
- jReader.beginArray();
- jReader.nextNull();
- jReader.endArray();
- lfemptyChecked = true;
- } else if (keyName.startsWith("lfunion")) {
- checkLfUnion(jReader, keyName, peek);
- } else {
- assertTrue("Key " + keyName + " doesn't exists in yang file.", false);
- }
-
- }
- Collections.sort(loadedLfs);
- String expectedLfsStr = "[int16Max, int16Min, int32Max, int32Min, int64Max, int64Min, int8Max, int8Min, uint16Max, uint32Max, uint8Max]";
- String actualLfsStr = loadedLfs.toString();
- assertEquals("Some leaves are missing", expectedLfsStr, actualLfsStr);
- // assertTrue("For lfdecimal5 wasn't catch error",exceptForDecimal5Raised);
- assertTrue("Enum wasn't checked", enumChecked);
- assertTrue("Bits wasn't checked", bitsChecked);
- assertTrue("Decimal1 wasn't checked", lfdecimal1Checked);
- assertTrue("Decimal2 wasn't checked", lfdecimal2Checked);
- assertTrue("Decimal3 wasn't checked", lfdecimal3Checked);
- assertTrue("Decimal4 wasn't checked", lfdecimal4Checked);
- assertTrue("Decimal5 wasn't checked", lfdecimal6Checked);
- assertTrue("lfbool1 wasn't checked", lfbool1Checked);
- assertTrue("lfbool2 wasn't checked", lfbool2Checked);
- assertTrue("lfstr wasn't checked", lfstrChecked);
- assertTrue("lfstr1 wasn't checked", lfstr1Checked);
- assertTrue("lfbinary wasn't checked", lfbinaryChecked);
- assertTrue("lfempty wasn't checked", lfemptyChecked);
- // assertTrue("lfref1 wasn't checked", lfref1Checked);
-
- jReader.endObject();
-
- }
-
- private void checkLfUnion(JsonReader jReader, String keyName, JsonToken peek) throws IOException {
- if (keyName.equals("lfunion1")) {
- assertEquals("Key " + keyName + " has incorrect type", JsonToken.NUMBER, peek);
- jReader.nextString();
- } else if (keyName.equals("lfunion2")) {
- assertEquals("Key " + keyName + " has incorrect type", JsonToken.NUMBER, peek);
- jReader.nextString();
- } else if (keyName.equals("lfunion3")) {
- assertEquals("Key " + keyName + " has incorrect type", JsonToken.STRING, peek);
- jReader.nextInt();
- } else if (keyName.equals("lfunion4")) {
- assertEquals("Key " + keyName + " has incorrect type", JsonToken.BOOLEAN, peek);
- jReader.nextBoolean();
- } else if (keyName.equals("lfunion5")) {
- assertEquals("Key " + keyName + " has incorrect type", JsonToken.STRING, peek);
- jReader.nextString();
- } else if (keyName.equals("lfunion6")) {
- assertEquals("Key " + keyName + " has incorrect type", JsonToken.STRING, peek);
- jReader.nextString();
- } else if (keyName.equals("lfunion7")) {
- assertEquals("Key " + keyName + " has incorrect type", JsonToken.STRING, peek);
- jReader.nextString();
- } else if (keyName.equals("lfunion8")) {
- assertEquals("Key " + keyName + " has incorrect type", JsonToken.STRING, peek);
- jReader.nextString();
- } else if (keyName.equals("lfunion9")) {
- assertEquals("Key " + keyName + " has incorrect type", JsonToken.STRING, peek);
- jReader.nextString();
- } else if (keyName.equals("lfunion10")) {
- assertEquals("Key " + keyName + " has incorrect type", JsonToken.STRING, peek);
- jReader.nextString();
- } else if (keyName.equals("lfunion11")) {
- assertEquals("Key " + keyName + " has incorrect type", JsonToken.NUMBER, peek);
- jReader.nextString();
- } else if (keyName.equals("lfunion12")) {
- assertEquals("Key " + keyName + " has incorrect type", JsonToken.BOOLEAN, peek);
- jReader.nextBoolean();
- }
- }
-}
+++ /dev/null
-package org.opendaylight.controller.sal.restconf.impl.test;
-
-import static org.junit.Assert.assertTrue;
-
-import java.io.IOException;
-
-import javax.ws.rs.WebApplicationException;
-
-import org.junit.*;
-
-public class ToJsonChoiceCaseTest extends YangAndXmlAndDataSchemaLoader {
-
- @BeforeClass
- public static void initialization() {
- dataLoad("/yang-to-json-conversion/choice");
- }
-
- /**
- * Test when some data are in one case node and other in another. This isn't
- * correct. Next Json validator should return error because nodes has to be
- * from one case below concrete choice.
- *
- */
- @Test
- public void nodeSchemasOnVariousChoiceCasePathTest() {
- try {
- TestUtils.writeCompNodeWithSchemaContextToJson(
- TestUtils.loadCompositeNode("/yang-to-json-conversion/choice/xml/data_various_path_err.xml"),
- "/yang-to-json-conversion/choice/xml", modules, dataSchemaNode);
- } catch (WebApplicationException | IOException e) {
- // shouldn't end here
- assertTrue(false);
- }
- }
-
- /**
- * Test when some data are in one case node and other in another.
- * Additionally data are loadef from various choices. This isn't correct.
- * Next Json validator should return error because nodes has to be from one
- * case below concrete choice.
- *
- */
- @Test
- public void nodeSchemasOnVariousChoiceCasePathAndMultipleChoicesTest() {
- try {
- TestUtils
- .writeCompNodeWithSchemaContextToJson(
- TestUtils
- .loadCompositeNode("/yang-to-json-conversion/choice/xml/data_more_choices_same_level_various_paths_err.xml"),
- "/yang-to-json-conversion/choice/xml", modules, dataSchemaNode);
- } catch (WebApplicationException | IOException e) {
- // shouldn't end here
- assertTrue(false);
- }
- }
-
- /**
- * Test when second level data are red first, then first and at the end
- * third level. Level represents pass through couple choice-case
- */
-
- @Test
- public void nodeSchemasWithRandomOrderAccordingLevel() {
- try {
- TestUtils.writeCompNodeWithSchemaContextToJson(
- TestUtils.loadCompositeNode("/yang-to-json-conversion/choice/xml/data_random_level.xml"),
- "/yang-to-json-conversion/choice/xml", modules, dataSchemaNode);
-
- } catch (WebApplicationException | IOException e) {
- // shouldn't end here
- assertTrue(false);
- }
- }
-
- /**
- * Test when element from no first case is used
- */
- @Test
- public void nodeSchemasNotInFirstCase() {
- try {
- TestUtils.writeCompNodeWithSchemaContextToJson(
- TestUtils.loadCompositeNode("/yang-to-json-conversion/choice/xml/data_no_first_case.xml"),
- "/yang-to-json-conversion/choice/xml", modules, dataSchemaNode);
- } catch (WebApplicationException | IOException e) {
- // shouldn't end here
- assertTrue(false);
- }
- }
-
- /**
- * Test when element in case is list
- */
- @Test
- public void nodeSchemaAsList() {
- try {
- TestUtils.writeCompNodeWithSchemaContextToJson(
- TestUtils.loadCompositeNode("/yang-to-json-conversion/choice/xml/data_list.xml"),
- "/yang-to-json-conversion/choice/xml", modules, dataSchemaNode);
- } catch (WebApplicationException | IOException e) {
- // shouldn't end here
- assertTrue(false);
- }
- }
-
- /**
- * Test when element in case is container
- */
- @Test
- public void nodeSchemaAsContainer() {
- try {
- TestUtils.writeCompNodeWithSchemaContextToJson(
- TestUtils.loadCompositeNode("/yang-to-json-conversion/choice/xml/data_container.xml"),
- "/yang-to-json-conversion/choice/xml", modules, dataSchemaNode);
- } catch (WebApplicationException | IOException e) {
- // shouldn't end here
- assertTrue(false);
- }
- }
-
- /**
- * Test when element in case is leaflist
- */
- @Test
- public void nodeSchemaAsLeafList() {
- try {
- TestUtils.writeCompNodeWithSchemaContextToJson(
- TestUtils.loadCompositeNode("/yang-to-json-conversion/choice/xml/data_leaflist.xml"),
- "/yang-to-json-conversion/choice/xml", modules, dataSchemaNode);
- } catch (WebApplicationException | IOException e) {
- // shouldn't end here
- assertTrue(false);
- }
- }
-
- /**
- *
- */
- @Test
- public void nodeSchemasInMultipleChoicesTest() {
- try {
- TestUtils
- .writeCompNodeWithSchemaContextToJson(TestUtils
- .loadCompositeNode("/yang-to-json-conversion/choice/xml/data_more_choices_same_level.xml"),
- "/yang-to-json-conversion/choice/xml", modules, dataSchemaNode);
- } catch (WebApplicationException | IOException e) {
- // shouldn't end here
- assertTrue(false);
- }
- }
-
- /**
- * Test whether is possible to find data schema for node which is specified
- * as dirrect subnode of choice (case without CASE key word)
- */
- @Test
- public void nodeSchemasInCaseNotDefinedWithCaseKeyword() {
- try {
- TestUtils.writeCompNodeWithSchemaContextToJson(TestUtils
- .loadCompositeNode("/yang-to-json-conversion/choice/xml/data_case_defined_without_case.xml"),
- "/yang-to-json-conversion/choice/xml", modules, dataSchemaNode);
- } catch (WebApplicationException | IOException e) {
- // shouldn't end here
- assertTrue(false);
- }
- }
-
- /**
- * Test of multiple use of choices
- */
- @Test
- public void nodeSchemasInThreeChoicesAtSameLevel() {
- try {
- TestUtils.writeCompNodeWithSchemaContextToJson(TestUtils
- .loadCompositeNode("/yang-to-json-conversion/choice/xml/data_three_choices_same_level.xml"),
- "/yang-to-json-conversion/choice/xml", modules, dataSchemaNode);
- } catch (WebApplicationException | IOException e) {
- // shouldn't end here
- assertTrue(false);
- }
- }
-}
import java.net.URI;
import java.net.URISyntaxException;
import java.net.URLEncoder;
-import java.util.List;
-import java.util.Set;
+import java.util.*;
import java.util.concurrent.Future;
import java.util.logging.Level;
import java.util.logging.LogRecord;
import org.opendaylight.controller.sal.rest.api.RestconfService;
import org.opendaylight.controller.sal.rest.impl.StructuredDataToXmlProvider;
import org.opendaylight.controller.sal.rest.impl.XmlToCompositeNodeProvider;
-import org.opendaylight.controller.sal.restconf.impl.BrokerFacade;
-import org.opendaylight.controller.sal.restconf.impl.ControllerContext;
-import org.opendaylight.controller.sal.restconf.impl.RestconfImpl;
+import org.opendaylight.controller.sal.restconf.impl.*;
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.*;
+import org.opendaylight.yangtools.yang.data.impl.NodeFactory;
import org.opendaylight.yangtools.yang.model.api.Module;
import org.opendaylight.yangtools.yang.model.api.SchemaContext;
public void testStructuredDataToXmlProvider() throws FileNotFoundException, UnsupportedEncodingException {
String uri = createUri("/datastore/", "ietf-interfaces:interfaces/interface/eth0");
- InputStream xmlStream = RestconfImplTest.class.getResourceAsStream("/parts/ietf-interfaces_interfaces.xml");
- CompositeNode loadedCompositeNode = TestUtils.loadCompositeNode(xmlStream);
+ CompositeNode loadedCompositeNode = prepareCompositeNodeWithIetfInterfacesInterfacesData();
when(brokerFacade.readOperationalData(any(InstanceIdentifier.class))).thenReturn(loadedCompositeNode);
Response response = target(uri).request(MEDIA_TYPE).get();
assertEquals(200, response.getStatus());
}
+ private CompositeNode prepareCompositeNodeWithIetfInterfacesInterfacesData() {
+ CompositeNode intface;
+ try {
+ intface = new CompositeNodeWrapper(new URI("interface"), "interface");
+ List<Node<?>> childs = new ArrayList<>();
+
+ childs.add(new SimpleNodeWrapper(new URI("name"), "name", "eth0"));
+ childs.add(new SimpleNodeWrapper(new URI("type"), "type", "ethernetCsmacd"));
+ childs.add(new SimpleNodeWrapper(new URI("enabled"), "enabled", Boolean.FALSE));
+ childs.add(new SimpleNodeWrapper(new URI("description"), "description", "some interface"));
+ intface.setValue(childs);
+ return intface;
+ } catch (URISyntaxException e) {
+ }
+
+ return null;
+ }
+
@Test
public void testBadFormatXmlToCompositeNodeProvider() throws UnsupportedEncodingException, URISyntaxException {
String uri = createUri("/operations/", "ietf-interfaces:interfaces/interface/eth0");
package org.opendaylight.controller.sal.restconf.impl.test.structures;
public class Lf extends YangElement {
- private String value;
+ private Object value;
private int numOfEqualItems = 0;
-
- public Lf(String name, String value) {
+ public Lf(String name, Object value) {
super(name);
this.value = value;
}
- public Lf(String value) {
+ public Lf(Object value) {
super("");
this.value = value;
}
- public String getValue() {
+ public Object getValue() {
return value;
}
}
return true;
}
-
+
public void incNumOfEqualItems() {
this.numOfEqualItems++;
}
-
@Override
public int hashCode() {
package org.opendaylight.controller.sal.restconf.impl.test.structures;
-import java.util.*;
+import java.util.HashSet;
+import java.util.Set;
public class LfLst extends YangElement {
Set<Lf> lfs;
lfs = new HashSet<>();
}
- public LfLst addLf(String value) {
+ public LfLst addLf(Object value) {
return addLf(new Lf(value));
}
-
public LfLst addLf(Lf lf) {
while (this.lfs.contains(lf)) {
lf.incNumOfEqualItems();
package org.opendaylight.controller.sal.restconf.impl.test.structures;
-import java.util.*;
+import java.util.HashMap;
+import java.util.Map;
public class LstItem {
String lstName;
return this;
}
- public LstItem addLf(String name, String value) {
+ public LstItem addLf(String name, Object value) {
lfs.put(name, new Lf(name, value));
return this;
}
-package org.opendaylight.controller.sal.restconf.impl.test;
+package org.opendaylight.controller.sal.restconf.impl.xml.to.cnsn.test;
-import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertNotNull;
-import static org.junit.Assert.assertTrue;
+import static org.junit.Assert.*;
import java.io.*;
import java.net.URISyntaxException;
+import java.util.List;
+import java.util.Set;
import javax.ws.rs.WebApplicationException;
-import org.junit.*;
+import org.junit.Test;
import org.opendaylight.controller.sal.rest.impl.XmlToCompositeNodeProvider;
-import org.opendaylight.controller.sal.restconf.impl.*;
+import org.opendaylight.controller.sal.restconf.impl.CompositeNodeWrapper;
+import org.opendaylight.controller.sal.restconf.impl.test.TestUtils;
+import org.opendaylight.yangtools.yang.common.QName;
import org.opendaylight.yangtools.yang.data.api.*;
import org.opendaylight.yangtools.yang.model.api.DataSchemaNode;
-import org.slf4j.*;
+import org.opendaylight.yangtools.yang.model.api.Module;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
-public class FromXmlToCompositeNodeTest {
- private static final Logger LOG = LoggerFactory.getLogger(FromXmlToCompositeNodeTest.class);
+public class XmlToCnSnTest {
+ private static final Logger LOG = LoggerFactory.getLogger(XmlToCnSnTest.class);
/**
* top level element represents container. second level element is list with
*/
@Test
public void testXmlDataContainer() {
- CompositeNode compNode = compositeContainerFromXml("/xml-to-composite-node/data-container.xml", false);
+ CompositeNode compNode = compositeNodeFromXml("/xml-to-cnsn/data-container.xml", false);
assertNotNull(compNode);
DataSchemaNode dataSchemaNode = null;
try {
- dataSchemaNode = TestUtils.obtainSchemaFromYang("/xml-to-composite-node/data-container-yang");
+ dataSchemaNode = TestUtils.obtainSchemaFromYang("/xml-to-cnsn/data-container-yang");
} catch (FileNotFoundException e) {
LOG.error(e.getMessage());
assertTrue(false);
@Test
public void testXmlDataList() {
- CompositeNode compNode = compositeContainerFromXml("/xml-to-composite-node/data-list.xml", false);
+ CompositeNode compNode = compositeNodeFromXml("/xml-to-cnsn/data-list.xml", false);
assertNotNull(compNode);
DataSchemaNode dataSchemaNode = null;
try {
- dataSchemaNode = TestUtils.obtainSchemaFromYang("/xml-to-composite-node/data-list-yang",
- "data-container-yang");
+ dataSchemaNode = TestUtils.obtainSchemaFromYang("/xml-to-cnsn/data-list-yang", "data-container-yang");
} catch (FileNotFoundException e) {
LOG.error(e.getMessage());
}
@Test
public void testXmlEmptyData() {
- CompositeNode compNode = compositeContainerFromXml("/xml-to-composite-node/empty-data.xml", true);
+ CompositeNode compNode = compositeNodeFromXml("/xml-to-cnsn/empty-data.xml", true);
assertEquals("cont", compNode.getNodeType().getLocalName());
SimpleNode<?> lf1 = null;
SimpleNode<?> lflst1_1 = null;
}
+ /**
+ * Test case like this <lf11 xmlns:x="namespace">x:identity</lf11>
+ */
+ @Test
+ public void testIdentityrefNmspcInElement() {
+ testIdentityrefToCnSn("/xml-to-cnsn/identityref/xml/data-nmspc-in-element.xml", "/xml-to-cnsn/identityref",
+ "identityref-module", "cont", 2, "iden", "identity:module");
+ }
+
+ /**
+ *
+ * Test case like <lf11 xmlns="namespace1"
+ * xmlns:x="namespace">identity</lf11>
+ */
+
+ @Test
+ public void testIdentityrefDefaultNmspcInElement() {
+ testIdentityrefToCnSn("/xml-to-cnsn/identityref/xml/data-default-nmspc-in-element.xml",
+ "/xml-to-cnsn/identityref/yang-augments", "general-module", "cont", 3, "iden", "identityref:module");
+ }
+
+ /**
+ *
+ * Test case like <cont1 xmlns="namespace1"> <lf11
+ * xmlns:x="namespace">identity</lf11> </cont1>
+ */
+ @Test
+ public void testIdentityrefDefaultNmspcInParrentElement() {
+ testIdentityrefToCnSn("/xml-to-cnsn/identityref/xml/data-default-nmspc-in-parrent-element.xml",
+ "/xml-to-cnsn/identityref", "identityref-module", "cont", 2, "iden", "identityref:module");
+ }
+
+ /**
+ *
+ * Test case like <cont1 xmlns="namespace1" xmlns:x="namespace">
+ * <lf11>x:identity</lf11> </cont1>
+ */
+ @Test
+ public void testIdentityrefNmspcInParrentElement() {
+ testIdentityrefToCnSn("/xml-to-cnsn/identityref/xml/data-nmspc-in-parrent-element.xml",
+ "/xml-to-cnsn/identityref", "identityref-module", "cont", 2, "iden", "z:namespace");
+
+ }
+
+ /**
+ *
+ * Test case like (without namespace in xml) <cont1> <lf11>x:identity</lf11>
+ * </cont1>
+ */
+ @Test
+ public void testIdentityrefNoNmspcValueWithPrefix() {
+ testIdentityrefToCnSn("/xml-to-cnsn/identityref/xml/data-no-nmspc-value-with-prefix.xml",
+ "/xml-to-cnsn/identityref", "identityref-module", "cont", 2, "x:iden", "identityref:module");
+ }
+
+ /**
+ *
+ * Test case like (without namespace in xml) <cont1> <lf11>identity</lf11>
+ * </cont1>
+ */
+ @Test
+ public void testIdentityrefNoNmspcValueWithoutPrefix() {
+ testIdentityrefToCnSn("/xml-to-cnsn/identityref/xml/data-no-nmspc-value-without-prefix.xml",
+ "/xml-to-cnsn/identityref", "identityref-module", "cont", 2, "iden", "identityref:module");
+ }
+
private void verifyCommonPartAOfXml(CompositeNode compNode, String suf, String nameSpace) {
SimpleNode<?> lf1suf = null;
SimpleNode<?> lflst1suf_1 = null;
assertEquals((short) 100, cont1_lf11.getValue());
}
- private CompositeNode compositeContainerFromXml(String xmlPath, boolean dummyNamespaces) {
+ private CompositeNode compositeNodeFromXml(String xmlPath, boolean dummyNamespaces) {
XmlToCompositeNodeProvider xmlToCompositeNodeProvider = XmlToCompositeNodeProvider.INSTANCE;
try {
- InputStream xmlStream = FromXmlToCompositeNodeTest.class.getResourceAsStream(xmlPath);
+ InputStream xmlStream = XmlToCnSnTest.class.getResourceAsStream(xmlPath);
CompositeNode compositeNode = xmlToCompositeNodeProvider.readFrom(null, null, null, null, null, xmlStream);
if (dummyNamespaces) {
try {
return null;
}
+ private void testIdentityrefToCnSn(String xmlPath, String yangPath, String moduleName, String schemaName,
+ int moduleCount, String resultLocalName, String resultNamespace) {
+ CompositeNode compositeNode = compositeNodeFromXml(xmlPath, false);
+ assertNotNull(compositeNode);
+
+ Set<Module> modules = TestUtils.resolveModules(yangPath);
+ assertEquals(moduleCount, modules.size());
+ Module module = TestUtils.resolveModule(moduleName, modules);
+ assertNotNull(module);
+ DataSchemaNode dataSchemaNode = TestUtils.resolveDataSchemaNode(module, null);
+ assertNotNull(dataSchemaNode);
+
+ TestUtils.normalizeCompositeNode(compositeNode, modules, dataSchemaNode, moduleName + ":" + schemaName);
+
+ SimpleNode<?> lf11 = getLf11(compositeNode);
+ assertTrue(lf11.getValue() instanceof QName);
+ QName qName = (QName) lf11.getValue();
+ assertEquals(resultLocalName, qName.getLocalName());
+ assertEquals(resultNamespace, qName.getNamespace().toString());
+
+ }
+
+ private SimpleNode<?> getLf11(CompositeNode compositeNode) {
+ assertEquals("cont", compositeNode.getNodeType().getLocalName());
+
+ List<Node<?>> childs = compositeNode.getChildren();
+ assertEquals(1, childs.size());
+ Node<?> nd = childs.iterator().next();
+ assertTrue(nd instanceof CompositeNode);
+ assertEquals("cont1", nd.getNodeType().getLocalName());
+
+ childs = ((CompositeNode) nd).getChildren();
+ SimpleNode<?> lf11 = null;
+ for (Node<?> child : childs) {
+ assertTrue(child instanceof SimpleNode);
+ if (child.getNodeType().getLocalName().equals("lf11")) {
+ lf11 = (SimpleNode<?>) child;
+ }
+ }
+ assertNotNull(lf11);
+ return lf11;
+ }
+
}
--- /dev/null
+module identityref-module {
+ namespace "identityref:module";
+
+ prefix "iderefmod";
+
+ import identity-module {prefix idemo; revision-date 2013-12-2;}
+
+ revision 2013-12-2 {
+ }
+
+ container cont {
+ container cont1 {
+ leaf lf1 {
+ type identityref {
+ base "idemo:iden";
+ }
+ }
+ }
+ }
+
+}
\ No newline at end of file
revision 2013-11-12 {
}
+ identity iden {
+ }
+
typedef tpdfempty {
type empty;
}
leaf lfunion12 {
type tpdfun2;
}
+
+ leaf lfunion13 {
+ type tpdfbit;
+ }
+
+ leaf lfunion14 {
+ type union {
+ type enumeration {
+ enum zero;
+ enum one;
+ }
+ type uint16;
+ }
+ }
+
+ leaf identityref1 {
+ type identityref {
+ base iden;
+ }
+ }
}
<lfdecimal4>43E3</lfdecimal4>
<lfdecimal6>33.12345</lfdecimal6>
<lfenum>enum3</lfenum>
- <lfbits>bit3</lfbits>
- <lfbinary>AAaacdabcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ%%-#^</lfbinary>
- <lfempty></lfempty>
+ <lfbits>bit3 bit2</lfbits>
+ <lfbinary>ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz</lfbinary>
+ <lfempty />
<lfunion1>324</lfunion1>
<lfunion2>33.3</lfunion2>
<lfunion3>55</lfunion3>
<lfunion10>bt1</lfunion10>
<lfunion11>33</lfunion11>
<lfunion12>false</lfunion12>
+ <lfunion13>44</lfunion13>
+ <lfunion14>21</lfunion14>
+ <lfempty />
+ <identityref1 xmlns:x="simple:data:types">x:iden</identityref1>
</cont>
\ No newline at end of file
--- /dev/null
+module aug-referenced-elements-module {
+ namespace "aug:referenced:elements:module";
+
+ prefix "augrefelmo";
+
+ import referenced-elements-module {prefix refelmo; revision-date 2013-12-3;}
+
+ revision 2013-12-3 {
+ }
+
+ augment "/refelmo:cont" {
+ leaf lf2 {
+ type boolean;
+ }
+ }
+
+
+}
\ No newline at end of file
--- /dev/null
+module referenced-elements-module {
+ namespace "referenced:elements:module";
+
+ prefix "refelmo";
+
+ revision 2013-12-3 {
+ }
+
+ container cont {
+ leaf lf1 {
+ type string;
+ }
+ }
+ leaf-list lflst1 {
+ type uint32;
+ }
+
+ }
+
+}
\ No newline at end of file
--- /dev/null
+module instance-identifier-module {
+ namespace "instance:identifier:module";
+
+ prefix "inidmod";
+
+ revision 2013-12-3 {
+ }
+
+ container cont {
+ leaf lf1 {
+ type instance-identifier {
+ }
+ }
+ }
+
+}
\ No newline at end of file
--- /dev/null
+module basic-module {
+ namespace "basic:module";
+
+ prefix "basmod";
+
+ import referenced-module {prefix refmo; revision-date 2013-12-2;}
+
+ revision 2013-12-2 {
+ }
+
+ container cont {
+ container cont1 {
+ leaf lf11 {
+ type identityref {
+ base "refmo:iden";
+ }
+ }
+ }
+ leaf lfStr {
+ type string;
+ }
+ leaf lfInt8 {
+ type int8;
+ }
+
+ leaf lfInt16 {
+ type int16;
+ }
+
+ leaf lfInt32 {
+ type int32;
+ }
+
+ leaf lfInt64 {
+ type int64;
+ }
+
+ leaf lfUint8 {
+ type uint8;
+ }
+
+ leaf lfUint16 {
+ type uint16;
+ }
+
+ leaf lfUint32 {
+ type uint32;
+ }
+
+ leaf lfUint64 {
+ type uint64;
+ }
+
+ leaf lfBinary {
+ type binary;
+ }
+
+ leaf lfBits {
+ type bits {
+ bit one;
+ bit two;
+ bit three;
+ }
+ }
+
+ leaf lfEnumeration {
+ type enumeration {
+ enum enum1;
+ enum enum2;
+ enum enum3;
+ }
+ }
+
+ leaf lfEmpty {
+ type empty;
+ }
+
+ leaf lfBoolean {
+ type boolean;
+ }
+
+ leaf lfUnion {
+ type union {
+ type int8;
+ type string;
+ type bits {
+ bit first;
+ bit second;
+ }
+ type boolean;
+ }
+ }
+
+ }
+
+}
\ No newline at end of file
--- /dev/null
+module referenced-module {
+ namespace "referenced:module";
+
+ prefix "refmod";
+ revision 2013-12-2 {
+ }
+
+ identity iden {
+ }
+}
\ No newline at end of file
--- /dev/null
+module identity-module {
+ namespace "identity:module";
+
+ prefix "idemod";
+ revision 2013-12-2 {
+ }
+
+ identity iden {
+ }
+}
\ No newline at end of file
--- /dev/null
+module identityref-module {
+ namespace "identityref:module";
+
+ prefix "iderefmod";
+
+ import identity-module {prefix idemo; revision-date 2013-12-2;}
+
+ revision 2013-12-2 {
+ }
+
+ identity iden_local {
+ }
+
+ container cont {
+ container cont1 {
+ leaf lf11 {
+ type identityref {
+ base "idemo:iden";
+ }
+ }
+ leaf lf12 {
+ type identityref {
+ base "iden_local";
+ }
+ }
+ leaf lf13 {
+ type identityref {
+ base "iden_local";
+ }
+ }
+ leaf lf14 {
+ type identityref {
+ base "iden_local";
+ }
+ }
+ }
+ }
+
+}
\ No newline at end of file
--- /dev/null
+{
+ "cont":{
+ "cont1":{
+ "lf11":"identity-module:iden",
+ "lf12":"iden_local",
+ "identityref-module:lf13":"iden_local",
+ "identityref-module:lf14":"identity-module:iden_local"
+ }
+ }
+}
\ No newline at end of file
--- /dev/null
+<cont xmlns:x="x:namespace" xmlns:y="y:namespace">
+ <cont1 xmlns:z="z:namespace" xmlns:a="a:namespace" xmlns:b="b:namespace">
+ <lf11 xmlns:c="identity:module">c:iden</lf11>
+ </cont1>
+</cont>
\ No newline at end of file
--- /dev/null
+module identity-module {
+ namespace "identity:module";
+
+ prefix "idemod";
+ revision 2013-12-2 {
+ }
+
+ identity iden {
+ }
+}
\ No newline at end of file
--- /dev/null
+module identityref-module {
+ namespace "identityref:module";
+
+ prefix "iderefmod";
+
+ import identity-module {prefix idemo; revision-date 2013-12-2;}
+
+ revision 2013-12-2 {
+ }
+
+ container cont {
+ container cont1 {
+ leaf lf11 {
+ type identityref {
+ base "idemo:iden";
+ }
+ }
+ }
+ }
+
+}
\ No newline at end of file
--- /dev/null
+<cont xmlns="general:module" xmlns:x="x:namespace" xmlns:y="y:namespace">
+ <cont1 xmlns:z="z:namespace" xmlns:a="a:namespace" xmlns:b="b:namespace">
+ <lf11 xmlns="identityref:module" xmlns:c="c:namespace">iden</lf11>
+ </cont1>
+</cont>
\ No newline at end of file
--- /dev/null
+<cont xmlns:x="x:namespace" xmlns:y="y:namespace">
+ <cont1 xmlns="identityref:module" xmlns:z="z:namespace" xmlns:a="a:namespace" xmlns:b="b:namespace">
+ <lf11 xmlns:c="c:namespace">iden</lf11>
+ </cont1>
+</cont>
\ No newline at end of file
--- /dev/null
+<cont xmlns="identityref:module" xmlns:x="x:namespace" xmlns:y="y:namespace">
+ <cont1 xmlns:z="z:namespace" xmlns:a="a:namespace" xmlns:b="b:namespace">
+ <lf11 xmlns:c="identity:module">c:iden</lf11>
+ </cont1>
+</cont>
\ No newline at end of file
--- /dev/null
+<cont xmlns="identityref:module" xmlns:x="x:namespace" xmlns:y="y:namespace">
+ <cont1 xmlns:c="identity:module" xmlns:z="z:namespace" xmlns:a="a:namespace" xmlns:b="b:namespace">
+ <lf11>z:iden</lf11>
+ </cont1>
+</cont>
\ No newline at end of file
--- /dev/null
+<cont>
+ <cont1>
+ <lf11>x:iden</lf11>
+ </cont1>
+</cont>
\ No newline at end of file
--- /dev/null
+<cont>
+ <cont1>
+ <lf11>iden</lf11>
+ </cont1>
+</cont>
\ No newline at end of file
--- /dev/null
+module general-module {
+ namespace "general:module";
+
+ prefix "genmod";
+ revision 2013-12-12 {
+ }
+
+ container cont {
+ container cont1 {
+ }
+ }
+
+
+}
\ No newline at end of file
--- /dev/null
+module identity-module {
+ namespace "identity:module";
+
+ prefix "idemod";
+ revision 2013-12-2 {
+ }
+
+ identity iden {
+ }
+}
\ No newline at end of file
prefix "iderefmod";
import identity-module {prefix idemo; revision-date 2013-12-2;}
+ import general-module {prefix gmo; revision-date 2013-12-12;}
revision 2013-12-2 {
}
- container cont {
- leaf lf1 {
+ augment "/gmo:cont/gmo:cont1" {
+ leaf lf11 {
type identityref {
base "idemo:iden";
}
--- /dev/null
+/*
+ * Copyright IBM Corporation, 2013. All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+package org.opendaylight.controller.md.statistics.manager;
+
+import java.util.Map;
+import java.util.concurrent.ConcurrentHashMap;
+
+import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.transaction.rev131103.TransactionId;
+
+/**
+ * Main responsibility of the class is to manage multipart response
+ * for multipart request. It also handles the flow aggregate request
+ * and response mapping.
+ * @author avishnoi@in.ibm.com
+ *
+ */
+public class MultipartMessageManager {
+
+ /*
+ * Map for tx id and type of request, to keep track of all the request sent
+ * by Statistics Manager. Statistics Manager won't entertain any multipart
+ * response for which it didn't send the request.
+ */
+
+ private static Map<TransactionId,StatsRequestType> txIdToRequestTypeMap = new ConcurrentHashMap<TransactionId,StatsRequestType>();
+ /*
+ * Map to keep track of the request tx id for flow table statistics request.
+ * Because flow table statistics multi part response do not contains the table id.
+ */
+ private static Map<TransactionId,Short> txIdTotableIdMap = new ConcurrentHashMap<TransactionId,Short>();
+
+ public MultipartMessageManager(){}
+
+ public Short getTableIdForTxId(TransactionId id){
+
+ return txIdTotableIdMap.get(id);
+
+ }
+
+ public void setTxIdAndTableIdMapEntry(TransactionId id,Short tableId){
+ txIdTotableIdMap.put(id, tableId);
+ }
+
+ public void addTxIdToRequestTypeEntry (TransactionId id,StatsRequestType type){
+ txIdToRequestTypeMap.put(id, type);
+ }
+ public StatsRequestType removeTxId(TransactionId id){
+ return txIdToRequestTypeMap.remove(id);
+ }
+
+ public enum StatsRequestType{
+ ALL_FLOW,
+ AGGR_FLOW,
+ ALL_PORT,
+ ALL_FLOW_TABLE,
+ ALL_QUEUE_STATS,
+ ALL_GROUP,
+ ALL_METER,
+ GROUP_DESC,
+ METER_CONFIG
+ }
+}
*/
package org.opendaylight.controller.md.statistics.manager;
+import java.util.HashMap;
import java.util.List;
+import java.util.Map;
+import java.util.concurrent.ConcurrentHashMap;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.tables.table.Flow;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.statistics.rev130819.aggregate.flow.statistics.AggregateFlowStatistics;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.types.queue.rev130925.QueueId;
import org.opendaylight.yang.gen.v1.urn.opendaylight.group.statistics.rev131111.group.features.GroupFeatures;
import org.opendaylight.yang.gen.v1.urn.opendaylight.group.types.rev131018.group.desc.stats.reply.GroupDescStats;
import org.opendaylight.yang.gen.v1.urn.opendaylight.group.types.rev131018.group.statistics.reply.GroupStats;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.NodeConnectorId;
import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.NodeRef;
import org.opendaylight.yang.gen.v1.urn.opendaylight.meter.statistics.rev131111.nodes.node.MeterFeatures;
import org.opendaylight.yang.gen.v1.urn.opendaylight.meter.types.rev130918.meter.config.stats.reply.MeterConfigStats;
import org.opendaylight.yang.gen.v1.urn.opendaylight.meter.types.rev130918.meter.statistics.reply.MeterStats;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.model.statistics.types.rev130925.GenericQueueStatistics;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.model.statistics.types.rev130925.GenericStatistics;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.model.statistics.types.rev130925.GenericTableStatistics;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.model.statistics.types.rev130925.NodeConnectorStatistics;
public class NodeStatistics {
private MeterFeatures meterFeatures;
+ private final Map<Short,Map<Flow,GenericStatistics>> flowAndStatsMap=
+ new HashMap<Short,Map<Flow,GenericStatistics>>();
+
+ private final Map<Short,AggregateFlowStatistics> tableAndAggregateFlowStatsMap =
+ new HashMap<Short,AggregateFlowStatistics>();
+
+ private final Map<NodeConnectorId,NodeConnectorStatistics> nodeConnectorStats =
+ new ConcurrentHashMap<NodeConnectorId,NodeConnectorStatistics>();
+
+ private final Map<Short,GenericTableStatistics> flowTableAndStatisticsMap =
+ new HashMap<Short,GenericTableStatistics>();
+
+ private final Map<NodeConnectorId,Map<QueueId,GenericQueueStatistics>> NodeConnectorAndQueuesStatsMap =
+ new HashMap<NodeConnectorId,Map<QueueId,GenericQueueStatistics>>();
+
public NodeStatistics(){
}
public void setMeterFeatures(MeterFeatures meterFeatures) {
this.meterFeatures = meterFeatures;
}
-
+
+ public Map<Short,Map<Flow,GenericStatistics>> getFlowAndStatsMap() {
+ return flowAndStatsMap;
+ }
+
+ public Map<Short, GenericTableStatistics> getFlowTableAndStatisticsMap() {
+ return flowTableAndStatisticsMap;
+ }
+
+ public Map<Short, AggregateFlowStatistics> getTableAndAggregateFlowStatsMap() {
+ return tableAndAggregateFlowStatsMap;
+ }
+ public Map<NodeConnectorId, NodeConnectorStatistics> getNodeConnectorStats() {
+ return nodeConnectorStats;
+ }
+
+ public Map<NodeConnectorId, Map<QueueId, GenericQueueStatistics>> getNodeConnectorAndQueuesStatsMap() {
+ return NodeConnectorAndQueuesStatsMap;
+ }
}
*/
package org.opendaylight.controller.md.statistics.manager;
+import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentMap;
+import java.util.concurrent.ExecutionException;
import java.util.concurrent.Future;
import org.eclipse.xtext.xbase.lib.Exceptions;
+import org.opendaylight.controller.md.statistics.manager.MultipartMessageManager.StatsRequestType;
import org.opendaylight.controller.sal.binding.api.NotificationProviderService;
import org.opendaylight.controller.sal.binding.api.data.DataModificationTransaction;
import org.opendaylight.controller.sal.binding.api.data.DataProviderService;
import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.FlowCapableNode;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.tables.Table;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.statistics.rev130819.GetAggregateFlowStatisticsFromFlowTableForAllFlowsInputBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.statistics.rev130819.GetAggregateFlowStatisticsFromFlowTableForAllFlowsOutput;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.statistics.rev130819.GetAllFlowsStatisticsFromAllFlowTablesInputBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.statistics.rev130819.GetAllFlowsStatisticsFromAllFlowTablesOutput;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.statistics.rev130819.OpendaylightFlowStatisticsService;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.table.statistics.rev131215.GetFlowTablesStatisticsInputBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.table.statistics.rev131215.GetFlowTablesStatisticsOutput;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.table.statistics.rev131215.OpendaylightFlowTableStatisticsService;
import org.opendaylight.yang.gen.v1.urn.opendaylight.group.statistics.rev131111.GetAllGroupStatisticsInputBuilder;
import org.opendaylight.yang.gen.v1.urn.opendaylight.group.statistics.rev131111.GetAllGroupStatisticsOutput;
import org.opendaylight.yang.gen.v1.urn.opendaylight.group.statistics.rev131111.GetGroupDescriptionInputBuilder;
import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.NodeRef;
import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.Nodes;
import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.nodes.Node;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.nodes.NodeKey;
import org.opendaylight.yang.gen.v1.urn.opendaylight.meter.statistics.rev131111.GetAllMeterConfigStatisticsInputBuilder;
import org.opendaylight.yang.gen.v1.urn.opendaylight.meter.statistics.rev131111.GetAllMeterConfigStatisticsOutput;
import org.opendaylight.yang.gen.v1.urn.opendaylight.meter.statistics.rev131111.GetAllMeterStatisticsInputBuilder;
import org.opendaylight.yang.gen.v1.urn.opendaylight.meter.statistics.rev131111.GetAllMeterStatisticsOutput;
import org.opendaylight.yang.gen.v1.urn.opendaylight.meter.statistics.rev131111.OpendaylightMeterStatisticsService;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.port.statistics.rev131214.GetAllPortsStatisticsInputBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.port.statistics.rev131214.GetAllPortsStatisticsOutput;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.port.statistics.rev131214.OpendaylightPortStatisticsService;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.queue.statistics.rev131216.GetAllQueuesStatisticsFromAllPortsInputBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.queue.statistics.rev131216.GetAllQueuesStatisticsFromAllPortsOutput;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.queue.statistics.rev131216.OpendaylightQueueStatisticsService;
import org.opendaylight.yangtools.concepts.Registration;
import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
import org.opendaylight.yangtools.yang.binding.NotificationListener;
private OpendaylightMeterStatisticsService meterStatsService;
+ private OpendaylightFlowStatisticsService flowStatsService;
+
+ private OpendaylightPortStatisticsService portStatsService;
+
+ private OpendaylightFlowTableStatisticsService flowTableStatsService;
+
+ private OpendaylightQueueStatisticsService queueStatsService;
+
+ private final MultipartMessageManager multipartMessageManager = new MultipartMessageManager();
+
private Thread statisticsRequesterThread;
private final InstanceIdentifier<Nodes> nodesIdentifier = InstanceIdentifier.builder(Nodes.class).toInstance();
this.nps = notificationService;
}
+ public MultipartMessageManager getMultipartMessageManager() {
+ return multipartMessageManager;
+ }
+
private final StatisticsUpdateCommiter updateCommiter = new StatisticsUpdateCommiter(StatisticsProvider.this);
private Registration<NotificationListener> listenerRegistration;
meterStatsService = StatisticsManagerActivator.getProviderContext().
getRpcService(OpendaylightMeterStatisticsService.class);
+
+ flowStatsService = StatisticsManagerActivator.getProviderContext().
+ getRpcService(OpendaylightFlowStatisticsService.class);
+ portStatsService = StatisticsManagerActivator.getProviderContext().
+ getRpcService(OpendaylightPortStatisticsService.class);
+
+ flowTableStatsService = StatisticsManagerActivator.getProviderContext().
+ getRpcService(OpendaylightFlowTableStatisticsService.class);
+
+ queueStatsService = StatisticsManagerActivator.getProviderContext().
+ getRpcService(OpendaylightQueueStatisticsService.class);
+
statisticsRequesterThread = new Thread( new Runnable(){
@Override
private void statsRequestSender(){
- //Need to call API to receive all the nodes connected to controller.
List<Node> targetNodes = getAllConnectedNodes();
if(targetNodes == null)
return;
+
for (Node targetNode : targetNodes){
+
+ InstanceIdentifier<Node> targetInstanceId = InstanceIdentifier.builder(Nodes.class).child(Node.class,targetNode.getKey()).toInstance();
+ NodeRef targetNodeRef = new NodeRef(targetInstanceId);
+
+ System.out.println("ANIL: Target Node object ::"+targetNode.toString());
+
+ System.out.println("ANIL: FlowCapableNode augmentations ::"+targetNode.getAugmentation(FlowCapableNode.class));
+
+ try {
+
+ sendAggregateFlowsStatsFromAllTablesRequest(targetNode.getKey());
- if(targetNode.getAugmentation(FlowCapableNode.class) != null){
+ sendAllFlowsStatsFromAllTablesRequest(targetNodeRef);
- spLogger.info("Send request for stats collection to node : {})",targetNode.getId());
+ sendAllPortStatisticsRequest(targetNodeRef);
- InstanceIdentifier<Node> targetInstanceId = InstanceIdentifier.builder(Nodes.class).child(Node.class,targetNode.getKey()).toInstance();
- NodeRef targetNodeRef = new NodeRef(targetInstanceId);
+ sendAllFlowTablesStatisticsRequest(targetNodeRef);
+ sendAllQueueStatsFromAllNodeConnector (targetNodeRef);
+
+ }catch(Exception e){
+ spLogger.error("Exception occured while sending statistics requests : {}",e);
+ }
+
+ if(targetNode.getAugmentation(FlowCapableNode.class) != null){
+
+ spLogger.info("Send request for stats collection to node : {})",targetNode.getId());
+
try{
sendAllGroupStatisticsRequest(targetNodeRef);
Thread.sleep(1000);
sendMeterConfigStatisticsRequest(targetNodeRef);
Thread.sleep(1000);
}catch(Exception e){
- spLogger.error("Exception occured while sending statistics request : {}", e);
+ spLogger.error("Exception occured while sending statistics requests : {}", e);
}
}
}
}
+
+ private void sendAllFlowTablesStatisticsRequest(NodeRef targetNodeRef) throws InterruptedException, ExecutionException {
+ final GetFlowTablesStatisticsInputBuilder input =
+ new GetFlowTablesStatisticsInputBuilder();
+
+ input.setNode(targetNodeRef);
+
+ Future<RpcResult<GetFlowTablesStatisticsOutput>> response =
+ flowTableStatsService.getFlowTablesStatistics(input.build());
+
+ this.multipartMessageManager.addTxIdToRequestTypeEntry(response.get().getResult().getTransactionId()
+ , StatsRequestType.ALL_FLOW_TABLE);
+
+ }
+
+ private void sendAllFlowsStatsFromAllTablesRequest(NodeRef targetNode) throws InterruptedException, ExecutionException{
+ final GetAllFlowsStatisticsFromAllFlowTablesInputBuilder input =
+ new GetAllFlowsStatisticsFromAllFlowTablesInputBuilder();
+
+ input.setNode(targetNode);
+
+ Future<RpcResult<GetAllFlowsStatisticsFromAllFlowTablesOutput>> response =
+ flowStatsService.getAllFlowsStatisticsFromAllFlowTables(input.build());
+
+ this.multipartMessageManager.addTxIdToRequestTypeEntry(response.get().getResult().getTransactionId()
+ , StatsRequestType.ALL_FLOW);
+
+ }
- private void sendAllGroupStatisticsRequest(NodeRef targetNode){
+ private void sendAggregateFlowsStatsFromAllTablesRequest(NodeKey targetNodeKey) throws InterruptedException, ExecutionException{
- final GetAllGroupStatisticsInputBuilder input = new GetAllGroupStatisticsInputBuilder();
+ List<Short> tablesId = getTablesFromNode(targetNodeKey);
+
+ if(tablesId.size() != 0){
+ for(Short id : tablesId){
+
+ spLogger.info("Send aggregate stats request for flow table {} to node {}",id,targetNodeKey);
+ GetAggregateFlowStatisticsFromFlowTableForAllFlowsInputBuilder input =
+ new GetAggregateFlowStatisticsFromFlowTableForAllFlowsInputBuilder();
+
+ input.setNode(new NodeRef(InstanceIdentifier.builder(Nodes.class).child(Node.class, targetNodeKey).toInstance()));
+ input.setTableId(new org.opendaylight.yang.gen.v1.urn.opendaylight.table.types.rev131026.TableId(id));
+ Future<RpcResult<GetAggregateFlowStatisticsFromFlowTableForAllFlowsOutput>> response =
+ flowStatsService.getAggregateFlowStatisticsFromFlowTableForAllFlows(input.build());
+
+ multipartMessageManager.setTxIdAndTableIdMapEntry(response.get().getResult().getTransactionId(), id);
+ this.multipartMessageManager.addTxIdToRequestTypeEntry(response.get().getResult().getTransactionId()
+ , StatsRequestType.AGGR_FLOW);
+ }
+ }
+
+ //Note: Just for testing, because i am not able to fetch table list from datastore
+ // Bug-225 is raised for investigation.
+
+// spLogger.info("Send aggregate stats request for flow table {} to node {}",1,targetNodeKey);
+// GetAggregateFlowStatisticsFromFlowTableForAllFlowsInputBuilder input =
+// new GetAggregateFlowStatisticsFromFlowTableForAllFlowsInputBuilder();
+//
+// input.setNode(new NodeRef(InstanceIdentifier.builder(Nodes.class).child(Node.class, targetNodeKey).toInstance()));
+// input.setTableId(new TableId((short)1));
+// Future<RpcResult<GetAggregateFlowStatisticsFromFlowTableForAllFlowsOutput>> response =
+// flowStatsService.getAggregateFlowStatisticsFromFlowTableForAllFlows(input.build());`
+//
+// multipartMessageManager.setTxIdAndTableIdMapEntry(response.get().getResult().getTransactionId(), (short)1);
+
+ }
+
+ private void sendAllPortStatisticsRequest(NodeRef targetNode) throws InterruptedException, ExecutionException{
+
+ final GetAllPortsStatisticsInputBuilder input = new GetAllPortsStatisticsInputBuilder();
input.setNode(targetNode);
+
+ Future<RpcResult<GetAllPortsStatisticsOutput>> response =
+ portStatsService.getAllPortsStatistics(input.build());
+ this.multipartMessageManager.addTxIdToRequestTypeEntry(response.get().getResult().getTransactionId()
+ , StatsRequestType.ALL_PORT);
+
+ }
+
+ private void sendAllGroupStatisticsRequest(NodeRef targetNode) throws InterruptedException, ExecutionException{
+
+ final GetAllGroupStatisticsInputBuilder input = new GetAllGroupStatisticsInputBuilder();
+
input.setNode(targetNode);
- @SuppressWarnings("unused")
Future<RpcResult<GetAllGroupStatisticsOutput>> response =
groupStatsService.getAllGroupStatistics(input.build());
+
+ this.multipartMessageManager.addTxIdToRequestTypeEntry(response.get().getResult().getTransactionId()
+ , StatsRequestType.ALL_GROUP);
+
}
- private void sendGroupDescriptionRequest(NodeRef targetNode){
+ private void sendGroupDescriptionRequest(NodeRef targetNode) throws InterruptedException, ExecutionException{
final GetGroupDescriptionInputBuilder input = new GetGroupDescriptionInputBuilder();
input.setNode(targetNode);
- @SuppressWarnings("unused")
Future<RpcResult<GetGroupDescriptionOutput>> response =
groupStatsService.getGroupDescription(input.build());
+
+ this.multipartMessageManager.addTxIdToRequestTypeEntry(response.get().getResult().getTransactionId()
+ , StatsRequestType.GROUP_DESC);
+
}
- private void sendAllMeterStatisticsRequest(NodeRef targetNode){
+ private void sendAllMeterStatisticsRequest(NodeRef targetNode) throws InterruptedException, ExecutionException{
GetAllMeterStatisticsInputBuilder input = new GetAllMeterStatisticsInputBuilder();
input.setNode(targetNode);
- @SuppressWarnings("unused")
Future<RpcResult<GetAllMeterStatisticsOutput>> response =
meterStatsService.getAllMeterStatistics(input.build());
+
+ this.multipartMessageManager.addTxIdToRequestTypeEntry(response.get().getResult().getTransactionId()
+ , StatsRequestType.ALL_METER);;
+
}
- private void sendMeterConfigStatisticsRequest(NodeRef targetNode){
+ private void sendMeterConfigStatisticsRequest(NodeRef targetNode) throws InterruptedException, ExecutionException{
GetAllMeterConfigStatisticsInputBuilder input = new GetAllMeterConfigStatisticsInputBuilder();
input.setNode(targetNode);
- @SuppressWarnings("unused")
Future<RpcResult<GetAllMeterConfigStatisticsOutput>> response =
meterStatsService.getAllMeterConfigStatistics(input.build());
+ this.multipartMessageManager.addTxIdToRequestTypeEntry(response.get().getResult().getTransactionId()
+ , StatsRequestType.METER_CONFIG);;
+
}
+ private void sendAllQueueStatsFromAllNodeConnector(NodeRef targetNode) throws InterruptedException, ExecutionException {
+ GetAllQueuesStatisticsFromAllPortsInputBuilder input = new GetAllQueuesStatisticsFromAllPortsInputBuilder();
+
+ input.setNode(targetNode);
+
+ Future<RpcResult<GetAllQueuesStatisticsFromAllPortsOutput>> response =
+ queueStatsService.getAllQueuesStatisticsFromAllPorts(input.build());
+
+ this.multipartMessageManager.addTxIdToRequestTypeEntry(response.get().getResult().getTransactionId()
+ , StatsRequestType.ALL_QUEUE_STATS);;
+
+ }
+
public ConcurrentMap<NodeId, NodeStatistics> getStatisticsCache() {
return statisticsCache;
}
spLogger.info("Number of connected nodes : {}",nodes.getNode().size());
return nodes.getNode();
}
+
+ private List<Short> getTablesFromNode(NodeKey nodeKey){
+ InstanceIdentifier<FlowCapableNode> nodesIdentifier = InstanceIdentifier.builder(Nodes.class).child(Node.class,nodeKey).augmentation(FlowCapableNode.class).toInstance();
+
+ FlowCapableNode node = (FlowCapableNode)dps.readConfigurationData(nodesIdentifier);
+ List<Short> tablesId = new ArrayList<Short>();
+ if(node != null && node.getTable()!=null){
+ spLogger.info("Number of tables {} supported by node {}",node.getTable().size(),nodeKey);
+ for(Table table: node.getTable()){
+ tablesId.add(table.getId());
+ }
+ }
+ return tablesId;
+ }
@SuppressWarnings("deprecation")
@Override
*/
package org.opendaylight.controller.md.statistics.manager;
+import java.util.HashMap;
+import java.util.List;
import java.util.concurrent.ConcurrentMap;
import org.opendaylight.controller.sal.binding.api.data.DataModificationTransaction;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.FlowCapableNode;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.FlowCapableNodeConnector;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.FlowId;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.meters.Meter;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.meters.MeterBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.meters.MeterKey;
+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.statistics.rev130819.AggregateFlowStatisticsData;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.statistics.rev130819.AggregateFlowStatisticsDataBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.statistics.rev130819.AggregateFlowStatisticsUpdate;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.statistics.rev130819.FlowStatisticsData;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.statistics.rev130819.FlowStatisticsDataBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.statistics.rev130819.FlowStatisticsUpdated;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.statistics.rev130819.FlowTableStatisticsUpdated;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.statistics.rev130819.FlowsStatisticsUpdate;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.statistics.rev130819.NodeConnectorStatisticsUpdated;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.statistics.rev130819.OpendaylightFlowStatisticsListener;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.statistics.rev130819.aggregate.flow.statistics.AggregateFlowStatisticsBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.statistics.rev130819.flow.and.statistics.map.list.FlowAndStatisticsMapList;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.statistics.rev130819.flow.and.statistics.map.list.FlowAndStatisticsMapListBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.statistics.rev130819.flow.statistics.FlowStatisticsBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.table.statistics.rev131215.FlowTableStatisticsData;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.table.statistics.rev131215.FlowTableStatisticsDataBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.table.statistics.rev131215.FlowTableStatisticsUpdate;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.table.statistics.rev131215.OpendaylightFlowTableStatisticsListener;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.table.statistics.rev131215.flow.table.and.statistics.map.FlowTableAndStatisticsMap;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.table.statistics.rev131215.flow.table.statistics.FlowTableStatisticsBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.types.port.rev130925.queues.Queue;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.types.port.rev130925.queues.QueueBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.types.port.rev130925.queues.QueueKey;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.types.queue.rev130925.QueueId;
import org.opendaylight.yang.gen.v1.urn.opendaylight.group.statistics.rev131111.GroupDescStatsUpdated;
import org.opendaylight.yang.gen.v1.urn.opendaylight.group.statistics.rev131111.GroupFeaturesUpdated;
import org.opendaylight.yang.gen.v1.urn.opendaylight.group.statistics.rev131111.GroupStatisticsUpdated;
import org.opendaylight.yang.gen.v1.urn.opendaylight.group.statistics.rev131111.group.desc.GroupDescBuilder;
import org.opendaylight.yang.gen.v1.urn.opendaylight.group.statistics.rev131111.group.features.GroupFeaturesBuilder;
import org.opendaylight.yang.gen.v1.urn.opendaylight.group.statistics.rev131111.group.statistics.GroupStatisticsBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.group.types.rev131018.group.desc.stats.reply.GroupDescStats;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.group.types.rev131018.group.statistics.reply.GroupStats;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.group.types.rev131018.groups.Group;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.group.types.rev131018.groups.GroupBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.group.types.rev131018.groups.GroupKey;
import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.NodeId;
import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.NodeRef;
import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.Nodes;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.node.NodeConnector;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.node.NodeConnectorBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.node.NodeConnectorKey;
import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.nodes.Node;
import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.nodes.NodeBuilder;
import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.nodes.NodeKey;
import org.opendaylight.yang.gen.v1.urn.opendaylight.meter.statistics.rev131111.NodeMeterStatistics;
import org.opendaylight.yang.gen.v1.urn.opendaylight.meter.statistics.rev131111.NodeMeterStatisticsBuilder;
import org.opendaylight.yang.gen.v1.urn.opendaylight.meter.statistics.rev131111.OpendaylightMeterStatisticsListener;
-import org.opendaylight.yang.gen.v1.urn.opendaylight.meter.statistics.rev131111.nodes.node.MeterConfigStatsBuilder;
import org.opendaylight.yang.gen.v1.urn.opendaylight.meter.statistics.rev131111.nodes.node.MeterFeaturesBuilder;
-import org.opendaylight.yang.gen.v1.urn.opendaylight.meter.statistics.rev131111.nodes.node.MeterStatisticsBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.meter.statistics.rev131111.nodes.node.meter.MeterConfigStatsBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.meter.statistics.rev131111.nodes.node.meter.MeterStatisticsBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.meter.types.rev130918.meter.config.stats.reply.MeterConfigStats;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.meter.types.rev130918.meter.statistics.reply.MeterStats;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.model.statistics.types.rev130925.GenericQueueStatistics;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.model.statistics.types.rev130925.GenericStatistics;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.port.statistics.rev131214.FlowCapableNodeConnectorStatisticsData;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.port.statistics.rev131214.FlowCapableNodeConnectorStatisticsDataBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.port.statistics.rev131214.OpendaylightPortStatisticsListener;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.port.statistics.rev131214.PortStatisticsUpdate;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.port.statistics.rev131214.flow.capable.node.connector.statistics.FlowCapableNodeConnectorStatisticsBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.port.statistics.rev131214.node.connector.statistics.and.port.number.map.NodeConnectorStatisticsAndPortNumberMap;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.queue.statistics.rev131216.FlowCapableNodeConnectorQueueStatisticsData;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.queue.statistics.rev131216.FlowCapableNodeConnectorQueueStatisticsDataBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.queue.statistics.rev131216.OpendaylightQueueStatisticsListener;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.queue.statistics.rev131216.QueueStatisticsUpdate;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.queue.statistics.rev131216.flow.capable.node.connector.queue.statistics.FlowCapableNodeConnectorQueueStatisticsBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.queue.statistics.rev131216.queue.id.and.statistics.map.QueueIdAndStatisticsMap;
import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
import org.opendaylight.yangtools.yang.binding.InstanceIdentifier.InstanceIdentifierBuilder;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+/**
+ * Class implement statistics manager related listener interface and augment all the
+ * received statistics data to data stores.
+ * TODO: Need to add error message listener and clean-up the associated tx id
+ * if it exists in the tx-id cache.
+ * @author vishnoianil
+ *
+ */
public class StatisticsUpdateCommiter implements OpendaylightGroupStatisticsListener,
- OpendaylightMeterStatisticsListener {
+ OpendaylightMeterStatisticsListener,
+ OpendaylightFlowStatisticsListener,
+ OpendaylightPortStatisticsListener,
+ OpendaylightFlowTableStatisticsListener,
+ OpendaylightQueueStatisticsListener{
+ public final static Logger sucLogger = LoggerFactory.getLogger(StatisticsUpdateCommiter.class);
+
private final StatisticsProvider statisticsManager;
+
+ private final int unaccountedFlowsCounter = 1;
public StatisticsUpdateCommiter(final StatisticsProvider manager){
@Override
public void onMeterConfigStatsUpdated(MeterConfigStatsUpdated notification) {
-
+ //Check if response is for the request statistics-manager sent.
+ if(this.statisticsManager.getMultipartMessageManager().removeTxId(notification.getTransactionId()) == null)
+ return;
+
//Add statistics to local cache
ConcurrentMap<NodeId, NodeStatistics> cache = this.statisticsManager.getStatisticsCache();
if(!cache.containsKey(notification.getId())){
cache.get(notification.getId()).setMeterConfigStats(notification.getMeterConfigStats());
//Publish data to configuration data store
- DataModificationTransaction it = this.statisticsManager.startChange();
NodeKey key = new NodeKey(notification.getId());
- NodeRef ref = getNodeRef(key);
-
- final NodeBuilder nodeData = new NodeBuilder();
- nodeData.setKey(key);
-
- NodeMeterConfigStatsBuilder meterConfig= new NodeMeterConfigStatsBuilder();
- MeterConfigStatsBuilder stats = new MeterConfigStatsBuilder();
- stats.setMeterConfigStats(notification.getMeterConfigStats());
- meterConfig.setMeterConfigStats(stats.build());
- //Update augmented data
- nodeData.addAugmentation(NodeMeterConfigStats.class, meterConfig.build());
+ List<MeterConfigStats> eterConfigStatsList = notification.getMeterConfigStats();
- InstanceIdentifier<? extends Object> refValue = ref.getValue();
- it.putOperationalData(refValue, nodeData.build());
- it.commit();
+ for(MeterConfigStats meterConfigStats : eterConfigStatsList){
+ DataModificationTransaction it = this.statisticsManager.startChange();
+ MeterBuilder meterBuilder = new MeterBuilder();
+ MeterKey meterKey = new MeterKey(meterConfigStats.getMeterId());
+ meterBuilder.setKey(meterKey);
+
+ InstanceIdentifier<Meter> meterRef = InstanceIdentifier.builder(Nodes.class).child(Node.class,key)
+ .augmentation(FlowCapableNode.class)
+ .child(Meter.class,meterKey).toInstance();
+
+ NodeMeterConfigStatsBuilder meterConfig= new NodeMeterConfigStatsBuilder();
+ MeterConfigStatsBuilder stats = new MeterConfigStatsBuilder();
+ stats.fieldsFrom(meterConfigStats);
+ meterConfig.setMeterConfigStats(stats.build());
+
+ //Update augmented data
+ meterBuilder.addAugmentation(NodeMeterConfigStats.class, meterConfig.build());
+ it.putOperationalData(meterRef, meterBuilder.build());
+ it.commit();
+ }
}
@Override
public void onMeterStatisticsUpdated(MeterStatisticsUpdated notification) {
+
+ //Check if response is for the request statistics-manager sent.
+ if(this.statisticsManager.getMultipartMessageManager().removeTxId(notification.getTransactionId()) == null)
+ return;
+
//Add statistics to local cache
ConcurrentMap<NodeId, NodeStatistics> cache = this.statisticsManager.getStatisticsCache();
if(!cache.containsKey(notification.getId())){
}
cache.get(notification.getId()).setMeterStatistics(notification.getMeterStats());
- //Publish data to configuration data store
- DataModificationTransaction it = this.statisticsManager.startChange();
NodeKey key = new NodeKey(notification.getId());
- NodeRef ref = getNodeRef(key);
-
- final NodeBuilder nodeData = new NodeBuilder();
- nodeData.setKey(key);
- NodeMeterStatisticsBuilder meterStats= new NodeMeterStatisticsBuilder();
- MeterStatisticsBuilder stats = new MeterStatisticsBuilder();
- stats.setMeterStats(notification.getMeterStats());
- meterStats.setMeterStatistics(stats.build());
+ List<MeterStats> meterStatsList = notification.getMeterStats();
- //Update augmented data
- nodeData.addAugmentation(NodeMeterStatistics.class, meterStats.build());
-
- InstanceIdentifier<? extends Object> refValue = ref.getValue();
- it.putOperationalData(refValue, nodeData.build());
- it.commit();
+ for(MeterStats meterStats : meterStatsList){
+ //Publish data to configuration data store
+ DataModificationTransaction it = this.statisticsManager.startChange();
+ MeterBuilder meterBuilder = new MeterBuilder();
+ MeterKey meterKey = new MeterKey(meterStats.getMeterId());
+ meterBuilder.setKey(meterKey);
+
+ InstanceIdentifier<Meter> meterRef = InstanceIdentifier.builder(Nodes.class).child(Node.class,key)
+ .augmentation(FlowCapableNode.class)
+ .child(Meter.class,meterKey).toInstance();
+
+ NodeMeterStatisticsBuilder meterStatsBuilder= new NodeMeterStatisticsBuilder();
+ MeterStatisticsBuilder stats = new MeterStatisticsBuilder();
+ stats.fieldsFrom(meterStats);
+ meterStatsBuilder.setMeterStatistics(stats.build());
+
+ //Update augmented data
+ meterBuilder.addAugmentation(NodeMeterStatistics.class, meterStatsBuilder.build());
+ it.putOperationalData(meterRef, meterBuilder.build());
+ it.commit();
+ }
}
@Override
public void onGroupDescStatsUpdated(GroupDescStatsUpdated notification) {
+
+ //Check if response is for the request statistics-manager sent.
+ if(this.statisticsManager.getMultipartMessageManager().removeTxId(notification.getTransactionId()) == null)
+ return;
+
//Add statistics to local cache
ConcurrentMap<NodeId, NodeStatistics> cache = this.statisticsManager.getStatisticsCache();
if(!cache.containsKey(notification.getId())){
cache.get(notification.getId()).setGroupDescStats(notification.getGroupDescStats());
//Publish data to configuration data store
- DataModificationTransaction it = this.statisticsManager.startChange();
NodeKey key = new NodeKey(notification.getId());
- NodeRef ref = getNodeRef(key);
-
- final NodeBuilder nodeData = new NodeBuilder();
- nodeData.setKey(key);
-
- NodeGroupDescStatsBuilder groupDesc= new NodeGroupDescStatsBuilder();
- GroupDescBuilder stats = new GroupDescBuilder();
- stats.setGroupDescStats(notification.getGroupDescStats());
- groupDesc.setGroupDesc(stats.build());
-
- //Update augmented data
- nodeData.addAugmentation(NodeGroupDescStats.class, groupDesc.build());
+ List<GroupDescStats> groupDescStatsList = notification.getGroupDescStats();
- InstanceIdentifier<? extends Object> refValue = ref.getValue();
- it.putOperationalData(refValue, nodeData.build());
- it.commit();
+ for(GroupDescStats groupDescStats : groupDescStatsList){
+ DataModificationTransaction it = this.statisticsManager.startChange();
+
+ GroupBuilder groupBuilder = new GroupBuilder();
+ GroupKey groupKey = new GroupKey(groupDescStats.getGroupId());
+ groupBuilder.setKey(groupKey);
+
+ InstanceIdentifier<Group> groupRef = InstanceIdentifier.builder(Nodes.class).child(Node.class,key)
+ .augmentation(FlowCapableNode.class)
+ .child(Group.class,groupKey).toInstance();
+ NodeGroupDescStatsBuilder groupDesc= new NodeGroupDescStatsBuilder();
+ GroupDescBuilder stats = new GroupDescBuilder();
+ stats.fieldsFrom(groupDescStats);
+ groupDesc.setGroupDesc(stats.build());
+
+ //Update augmented data
+ groupBuilder.addAugmentation(NodeGroupDescStats.class, groupDesc.build());
+
+ it.putOperationalData(groupRef, groupBuilder.build());
+ it.commit();
+ }
}
@Override
public void onGroupStatisticsUpdated(GroupStatisticsUpdated notification) {
+ //Check if response is for the request statistics-manager sent.
+ if(this.statisticsManager.getMultipartMessageManager().removeTxId(notification.getTransactionId()) == null)
+ return;
+
//Add statistics to local cache
ConcurrentMap<NodeId, NodeStatistics> cache = this.statisticsManager.getStatisticsCache();
if(!cache.containsKey(notification.getId())){
cache.get(notification.getId()).setGroupStatistics(notification.getGroupStats());
//Publish data to configuration data store
-
- DataModificationTransaction it = this.statisticsManager.startChange();
NodeKey key = new NodeKey(notification.getId());
- NodeRef ref = getNodeRef(key);
-
- final NodeBuilder nodeData = new NodeBuilder();
- nodeData.setKey(key);
-
- NodeGroupStatisticsBuilder groupStats = new NodeGroupStatisticsBuilder();
- GroupStatisticsBuilder stats = new GroupStatisticsBuilder();
- stats.setGroupStats(notification.getGroupStats());
- groupStats.setGroupStatistics(stats.build());
-
- //Update augmented data
- nodeData.addAugmentation(NodeGroupStatistics.class, groupStats.build());
+ List<GroupStats> groupStatsList = notification.getGroupStats();
- InstanceIdentifier<? extends Object> refValue = ref.getValue();
- it.putOperationalData(refValue, nodeData.build());
- it.commit();
+ for(GroupStats groupStats : groupStatsList){
+ DataModificationTransaction it = this.statisticsManager.startChange();
+
+ GroupBuilder groupBuilder = new GroupBuilder();
+ GroupKey groupKey = new GroupKey(groupStats.getGroupId());
+ groupBuilder.setKey(groupKey);
+
+ InstanceIdentifier<Group> groupRef = InstanceIdentifier.builder(Nodes.class).child(Node.class,key)
+ .augmentation(FlowCapableNode.class)
+ .child(Group.class,groupKey).toInstance();
-// for (GroupStats groupstat : notification.getGroupStats()) {
-//
-// GroupStatsKey groupKey = groupstat.getKey();
-// InstanceIdentifier<? extends Object> id = InstanceIdentifier.builder(Nodes.class).child(Node.class, key).augmentation(NodeGroupStatistics.class).child(GroupStatistics.class).child(GroupStats.class,groupKey).toInstance();
-// it.putOperationalData(id, groupstat);
-// it.commit();
-// }
+ NodeGroupStatisticsBuilder groupStatisticsBuilder= new NodeGroupStatisticsBuilder();
+ GroupStatisticsBuilder stats = new GroupStatisticsBuilder();
+ stats.fieldsFrom(groupStats);
+ groupStatisticsBuilder.setGroupStatistics(stats.build());
+
+ //Update augmented data
+ groupBuilder.addAugmentation(NodeGroupStatistics.class, groupStatisticsBuilder.build());
+ it.putOperationalData(groupRef, groupBuilder.build());
+ it.commit();
+ }
}
@Override
it.commit();
}
+ @Override
+ public void onFlowsStatisticsUpdate(FlowsStatisticsUpdate notification) {
+
+ //Check if response is for the request statistics-manager sent.
+ if(this.statisticsManager.getMultipartMessageManager().removeTxId(notification.getTransactionId()) == null)
+ return;
+
+ NodeKey key = new NodeKey(notification.getId());
+ sucLogger.debug("Received flow stats update : {}",notification.toString());
+
+ for(FlowAndStatisticsMapList map: notification.getFlowAndStatisticsMapList()){
+ short tableId = map.getTableId();
+
+ DataModificationTransaction it = this.statisticsManager.startChange();
+
+ boolean foundOriginalFlow = false;
+
+ FlowBuilder flowBuilder = new FlowBuilder();
+
+ FlowStatisticsDataBuilder flowStatisticsData = new FlowStatisticsDataBuilder();
+
+ FlowBuilder flow = new FlowBuilder();
+ flow.setContainerName(map.getContainerName());
+ flow.setBufferId(map.getBufferId());
+ flow.setCookie(map.getCookie());
+ flow.setCookieMask(map.getCookieMask());
+ flow.setFlags(map.getFlags());
+ flow.setFlowName(map.getFlowName());
+ flow.setHardTimeout(map.getHardTimeout());
+ if(map.getFlowId() != null)
+ flow.setId(new FlowId(map.getFlowId().getValue()));
+ flow.setIdleTimeout(map.getIdleTimeout());
+ flow.setInstallHw(map.isInstallHw());
+ flow.setInstructions(map.getInstructions());
+ if(map.getFlowId()!= null)
+ flow.setKey(new FlowKey(new FlowId(map.getKey().getFlowId().getValue())));
+ flow.setMatch(map.getMatch());
+ flow.setOutGroup(map.getOutGroup());
+ flow.setOutPort(map.getOutPort());
+ flow.setPriority(map.getPriority());
+ flow.setStrict(map.isStrict());
+ flow.setTableId(tableId);
+
+ Flow flowRule = flow.build();
+
+ FlowAndStatisticsMapListBuilder stats = new FlowAndStatisticsMapListBuilder();
+ stats.setByteCount(map.getByteCount());
+ stats.setPacketCount(map.getPacketCount());
+ stats.setDuration(map.getDuration());
+
+ GenericStatistics flowStats = stats.build();
+
+ //Add statistics to local cache
+ ConcurrentMap<NodeId, NodeStatistics> cache = this.statisticsManager.getStatisticsCache();
+ if(!cache.containsKey(notification.getId())){
+ cache.put(notification.getId(), new NodeStatistics());
+ }
+ if(!cache.get(notification.getId()).getFlowAndStatsMap().containsKey(tableId)){
+ cache.get(notification.getId()).getFlowAndStatsMap().put(tableId, new HashMap<Flow,GenericStatistics>());
+ }
+ cache.get(notification.getId()).getFlowAndStatsMap().get(tableId).put(flowRule,flowStats);
+
+ //Augment the data to the flow node
+
+ FlowStatisticsBuilder flowStatistics = new FlowStatisticsBuilder();
+ flowStatistics.setByteCount(flowStats.getByteCount());
+ flowStatistics.setPacketCount(flowStats.getPacketCount());
+ flowStatistics.setDuration(flowStats.getDuration());
+ flowStatistics.setContainerName(map.getContainerName());
+ flowStatistics.setBufferId(map.getBufferId());
+ flowStatistics.setCookie(map.getCookie());
+ flowStatistics.setCookieMask(map.getCookieMask());
+ flowStatistics.setFlags(map.getFlags());
+ flowStatistics.setFlowName(map.getFlowName());
+ flowStatistics.setHardTimeout(map.getHardTimeout());
+ flowStatistics.setIdleTimeout(map.getIdleTimeout());
+ flowStatistics.setInstallHw(map.isInstallHw());
+ flowStatistics.setInstructions(map.getInstructions());
+ flowStatistics.setMatch(map.getMatch());
+ flowStatistics.setOutGroup(map.getOutGroup());
+ flowStatistics.setOutPort(map.getOutPort());
+ flowStatistics.setPriority(map.getPriority());
+ flowStatistics.setStrict(map.isStrict());
+ flowStatistics.setTableId(tableId);
+
+ flowStatisticsData.setFlowStatistics(flowStatistics.build());
+
+ sucLogger.debug("Flow : {}",flowRule.toString());
+ sucLogger.debug("Statistics to augment : {}",flowStatistics.build().toString());
+
+ InstanceIdentifier<Table> tableRef = InstanceIdentifier.builder(Nodes.class).child(Node.class, key)
+ .augmentation(FlowCapableNode.class).child(Table.class, new TableKey(tableId)).toInstance();
+
+ Table table= (Table)it.readConfigurationData(tableRef);
+
+ //TODO: Not a good way to do it, need to figure out better way.
+ //TODO: major issue in any alternate approach is that flow key is incrementally assigned
+ //to the flows stored in data store.
+ if(table != null){
+
+ for(Flow existingFlow : table.getFlow()){
+ sucLogger.debug("Existing flow in data store : {}",existingFlow.toString());
+ if(flowEquals(flowRule,existingFlow)){
+ InstanceIdentifier<Flow> flowRef = InstanceIdentifier.builder(Nodes.class).child(Node.class, key)
+ .augmentation(FlowCapableNode.class)
+ .child(Table.class, new TableKey(tableId))
+ .child(Flow.class,existingFlow.getKey()).toInstance();
+ flowBuilder.setKey(existingFlow.getKey());
+ flowBuilder.addAugmentation(FlowStatisticsData.class, flowStatisticsData.build());
+ sucLogger.debug("Found matching flow in the datastore, augmenting statistics");
+ foundOriginalFlow = true;
+ it.putOperationalData(flowRef, flowBuilder.build());
+ it.commit();
+ break;
+ }
+ }
+ }
+
+ if(!foundOriginalFlow){
+ sucLogger.info("Associated original flow is not found in data store. Augmenting flow in operational data st");
+ //TODO: Temporary fix: format [ 0+tableid+0+unaccounted flow counter]
+ long flowKey = Long.getLong(new String("0"+Short.toString(tableId)+"0"+Integer.toString(this.unaccountedFlowsCounter)));
+ FlowKey newFlowKey = new FlowKey(new FlowId(flowKey));
+ InstanceIdentifier<Flow> flowRef = InstanceIdentifier.builder(Nodes.class).child(Node.class, key)
+ .augmentation(FlowCapableNode.class)
+ .child(Table.class, new TableKey(tableId))
+ .child(Flow.class,newFlowKey).toInstance();
+ flowBuilder.setKey(newFlowKey);
+ flowBuilder.addAugmentation(FlowStatisticsData.class, flowStatisticsData.build());
+ sucLogger.info("Flow was no present in data store, augmenting statistics as an unaccounted flow");
+ it.putOperationalData(flowRef, flowBuilder.build());
+ it.commit();
+ }
+ }
+ }
+
+ @Override
+ public void onAggregateFlowStatisticsUpdate(AggregateFlowStatisticsUpdate notification) {
+ //Check if response is for the request statistics-manager sent.
+ if(this.statisticsManager.getMultipartMessageManager().removeTxId(notification.getTransactionId()) == null)
+ return;
+
+ NodeKey key = new NodeKey(notification.getId());
+ sucLogger.debug("Received aggregate flow statistics update : {}",notification.toString());
+
+ Short tableId = this.statisticsManager.getMultipartMessageManager().getTableIdForTxId(notification.getTransactionId());
+ if(tableId != null){
+
+ DataModificationTransaction it = this.statisticsManager.startChange();
+
+ InstanceIdentifier<Table> tableRef = InstanceIdentifier.builder(Nodes.class).child(Node.class, key)
+ .augmentation(FlowCapableNode.class).child(Table.class, new TableKey(tableId)).toInstance();
+
+ AggregateFlowStatisticsDataBuilder aggregateFlowStatisticsDataBuilder = new AggregateFlowStatisticsDataBuilder();
+ AggregateFlowStatisticsBuilder aggregateFlowStatisticsBuilder = new AggregateFlowStatisticsBuilder();
+ aggregateFlowStatisticsBuilder.setByteCount(notification.getByteCount());
+ aggregateFlowStatisticsBuilder.setFlowCount(notification.getFlowCount());
+ aggregateFlowStatisticsBuilder.setPacketCount(notification.getPacketCount());
+ aggregateFlowStatisticsDataBuilder.setAggregateFlowStatistics(aggregateFlowStatisticsBuilder.build());
+
+ ConcurrentMap<NodeId, NodeStatistics> cache = this.statisticsManager.getStatisticsCache();
+ if(!cache.containsKey(notification.getId())){
+ cache.put(notification.getId(), new NodeStatistics());
+ }
+ cache.get(notification.getId()).getTableAndAggregateFlowStatsMap().put(tableId,aggregateFlowStatisticsBuilder.build());
+
+ sucLogger.debug("Augment aggregate statistics: {} for table {} on Node {}",aggregateFlowStatisticsBuilder.build().toString(),tableId,key);
+
+ TableBuilder tableBuilder = new TableBuilder();
+ tableBuilder.setKey(new TableKey(tableId));
+ tableBuilder.addAugmentation(AggregateFlowStatisticsData.class, aggregateFlowStatisticsDataBuilder.build());
+ it.putOperationalData(tableRef, tableBuilder.build());
+ it.commit();
+
+ }
+ }
+
+ @Override
+ public void onPortStatisticsUpdate(PortStatisticsUpdate notification) {
+ //Check if response is for the request statistics-manager sent.
+ if(this.statisticsManager.getMultipartMessageManager().removeTxId(notification.getTransactionId()) == null)
+ return;
+
+ NodeKey key = new NodeKey(notification.getId());
+ sucLogger.debug("Received port stats update : {}",notification.toString());
+
+ //Add statistics to local cache
+ ConcurrentMap<NodeId, NodeStatistics> cache = this.statisticsManager.getStatisticsCache();
+ if(!cache.containsKey(notification.getId())){
+ cache.put(notification.getId(), new NodeStatistics());
+ }
+
+
+ List<NodeConnectorStatisticsAndPortNumberMap> portsStats = notification.getNodeConnectorStatisticsAndPortNumberMap();
+ for(NodeConnectorStatisticsAndPortNumberMap portStats : portsStats){
+
+ DataModificationTransaction it = this.statisticsManager.startChange();
+
+ FlowCapableNodeConnectorStatisticsBuilder statisticsBuilder
+ = new FlowCapableNodeConnectorStatisticsBuilder();
+ statisticsBuilder.setBytes(portStats.getBytes());
+ statisticsBuilder.setCollisionCount(portStats.getCollisionCount());
+ statisticsBuilder.setDuration(portStats.getDuration());
+ statisticsBuilder.setPackets(portStats.getPackets());
+ statisticsBuilder.setReceiveCrcError(portStats.getReceiveCrcError());
+ statisticsBuilder.setReceiveDrops(portStats.getReceiveDrops());
+ statisticsBuilder.setReceiveErrors(portStats.getReceiveErrors());
+ statisticsBuilder.setReceiveFrameError(portStats.getReceiveFrameError());
+ statisticsBuilder.setReceiveOverRunError(portStats.getReceiveOverRunError());
+ statisticsBuilder.setTransmitDrops(portStats.getTransmitDrops());
+ statisticsBuilder.setTransmitErrors(portStats.getTransmitErrors());
+
+ //Update data in the cache
+ cache.get(notification.getId()).getNodeConnectorStats().put(portStats.getNodeConnectorId(), statisticsBuilder.build());
+
+ //Augment data to the node-connector
+ FlowCapableNodeConnectorStatisticsDataBuilder statisticsDataBuilder =
+ new FlowCapableNodeConnectorStatisticsDataBuilder();
+
+ statisticsDataBuilder.setFlowCapableNodeConnectorStatistics(statisticsBuilder.build());
+
+ InstanceIdentifier<NodeConnector> nodeConnectorRef = InstanceIdentifier.builder(Nodes.class).child(Node.class, key).child(NodeConnector.class, new NodeConnectorKey(portStats.getNodeConnectorId())).toInstance();
+
+ NodeConnector nodeConnector = (NodeConnector)it.readOperationalData(nodeConnectorRef);
+
+ if(nodeConnector != null){
+ sucLogger.debug("Augmenting port statistics {} to port {}",statisticsDataBuilder.build().toString(),nodeConnectorRef.toString());
+ NodeConnectorBuilder nodeConnectorBuilder = new NodeConnectorBuilder();
+ nodeConnectorBuilder.addAugmentation(FlowCapableNodeConnectorStatisticsData.class, statisticsDataBuilder.build());
+ it.putOperationalData(nodeConnectorRef, nodeConnectorBuilder.build());
+ it.commit();
+ }
+ }
+ }
+
+ @Override
+ public void onFlowTableStatisticsUpdate(FlowTableStatisticsUpdate notification) {
+ //Check if response is for the request statistics-manager sent.
+ if(this.statisticsManager.getMultipartMessageManager().removeTxId(notification.getTransactionId()) == null)
+ return;
+
+ NodeKey key = new NodeKey(notification.getId());
+ sucLogger.debug("Received flow table statistics update : {}",notification.toString());
+
+ List<FlowTableAndStatisticsMap> flowTablesStatsList = notification.getFlowTableAndStatisticsMap();
+ for (FlowTableAndStatisticsMap ftStats : flowTablesStatsList){
+
+ DataModificationTransaction it = this.statisticsManager.startChange();
+
+ InstanceIdentifier<Table> tableRef = InstanceIdentifier.builder(Nodes.class).child(Node.class, key)
+ .augmentation(FlowCapableNode.class).child(Table.class, new TableKey(ftStats.getTableId().getValue())).toInstance();
+
+ FlowTableStatisticsDataBuilder statisticsDataBuilder = new FlowTableStatisticsDataBuilder();
+
+ FlowTableStatisticsBuilder statisticsBuilder = new FlowTableStatisticsBuilder();
+ statisticsBuilder.setActiveFlows(ftStats.getActiveFlows());
+ statisticsBuilder.setPacketsLookedUp(ftStats.getPacketsLookedUp());
+ statisticsBuilder.setPacketsMatched(ftStats.getPacketsMatched());
+
+ statisticsDataBuilder.setFlowTableStatistics(statisticsBuilder.build());
+
+ ConcurrentMap<NodeId, NodeStatistics> cache = this.statisticsManager.getStatisticsCache();
+ if(!cache.containsKey(notification.getId())){
+ cache.put(notification.getId(), new NodeStatistics());
+ }
+ cache.get(notification.getId()).getFlowTableAndStatisticsMap().put(ftStats.getTableId().getValue(),statisticsBuilder.build());
+
+ sucLogger.debug("Augment flow table statistics: {} for table {} on Node {}",statisticsBuilder.build().toString(),ftStats.getTableId(),key);
+
+ TableBuilder tableBuilder = new TableBuilder();
+ tableBuilder.setKey(new TableKey(ftStats.getTableId().getValue()));
+ tableBuilder.addAugmentation(FlowTableStatisticsData.class, statisticsDataBuilder.build());
+ it.putOperationalData(tableRef, tableBuilder.build());
+ it.commit();
+ }
+ }
+
+ @Override
+ public void onQueueStatisticsUpdate(QueueStatisticsUpdate notification) {
+
+ //Check if response is for the request statistics-manager sent.
+ if(this.statisticsManager.getMultipartMessageManager().removeTxId(notification.getTransactionId()) == null)
+ return;
+
+ NodeKey key = new NodeKey(notification.getId());
+ sucLogger.debug("Received queue stats update : {}",notification.toString());
+
+ //Add statistics to local cache
+ ConcurrentMap<NodeId, NodeStatistics> cache = this.statisticsManager.getStatisticsCache();
+ if(!cache.containsKey(notification.getId())){
+ cache.put(notification.getId(), new NodeStatistics());
+ }
+
+ List<QueueIdAndStatisticsMap> queuesStats = notification.getQueueIdAndStatisticsMap();
+ for(QueueIdAndStatisticsMap swQueueStats : queuesStats){
+
+ if(!cache.get(notification.getId()).getNodeConnectorAndQueuesStatsMap().containsKey(swQueueStats.getNodeConnectorId())){
+ cache.get(notification.getId()).getNodeConnectorAndQueuesStatsMap().put(swQueueStats.getNodeConnectorId(), new HashMap<QueueId,GenericQueueStatistics>());
+ }
+
+ FlowCapableNodeConnectorQueueStatisticsDataBuilder queueStatisticsDataBuilder = new FlowCapableNodeConnectorQueueStatisticsDataBuilder();
+
+ FlowCapableNodeConnectorQueueStatisticsBuilder queueStatisticsBuilder = new FlowCapableNodeConnectorQueueStatisticsBuilder();
+
+ queueStatisticsBuilder.fieldsFrom(swQueueStats);
+
+ queueStatisticsDataBuilder.setFlowCapableNodeConnectorQueueStatistics(queueStatisticsBuilder.build());
+
+ cache.get(notification.getId()).getNodeConnectorAndQueuesStatsMap()
+ .get(swQueueStats.getNodeConnectorId())
+ .put(swQueueStats.getQueueId(), queueStatisticsBuilder.build());
+
+
+ DataModificationTransaction it = this.statisticsManager.startChange();
+
+ InstanceIdentifier<Queue> queueRef
+ = InstanceIdentifier.builder(Nodes.class)
+ .child(Node.class, key)
+ .child(NodeConnector.class, new NodeConnectorKey(swQueueStats.getNodeConnectorId()))
+ .augmentation(FlowCapableNodeConnector.class)
+ .child(Queue.class, new QueueKey(swQueueStats.getQueueId())).toInstance();
+
+ QueueBuilder queueBuilder = new QueueBuilder();
+ queueBuilder.addAugmentation(FlowCapableNodeConnectorQueueStatisticsData.class, queueStatisticsDataBuilder.build());
+ queueBuilder.setKey(new QueueKey(swQueueStats.getQueueId()));
+
+ sucLogger.info("Augmenting queue statistics {} of queue {} to port {}"
+ ,queueStatisticsDataBuilder.build().toString(),
+ swQueueStats.getQueueId(),
+ swQueueStats.getNodeConnectorId());
+
+ it.putOperationalData(queueRef, queueBuilder.build());
+ it.commit();
+
+ }
+
+ }
+
+ @Override
+ public void onFlowStatisticsUpdated(FlowStatisticsUpdated notification) {
+ // TODO Auto-generated method stub
+ //TODO: Depricated, will clean it up once sal-compatibility is fixed.
+ //Sal-Compatibility code usage this notification event.
+
+ }
+
+ @Override
+ public void onFlowTableStatisticsUpdated(FlowTableStatisticsUpdated notification) {
+ // TODO Auto-generated method stub
+ //TODO: Need to implement it yet
+
+ }
+
+ @Override
+ public void onNodeConnectorStatisticsUpdated(NodeConnectorStatisticsUpdated notification) {
+ // TODO Auto-generated method stub
+ //TODO: Need to implement it yet
+
+ }
+
private NodeRef getNodeRef(NodeKey nodeKey){
InstanceIdentifierBuilder<?> builder = InstanceIdentifier.builder(Nodes.class).child(Node.class, nodeKey);
return new NodeRef(builder.toInstance());
}
+
+ public boolean flowEquals(Flow statsFlow, Flow storedFlow) {
+ if (statsFlow.getClass() != storedFlow.getClass()) {
+ return false;
+ }
+ if (statsFlow.getBufferId()== null) {
+ if (storedFlow.getBufferId() != null) {
+ return false;
+ }
+ } else if(!statsFlow.getBufferId().equals(storedFlow.getBufferId())) {
+ return false;
+ }
+ if (statsFlow.getContainerName()== null) {
+ if (storedFlow.getContainerName()!= null) {
+ return false;
+ }
+ } else if(!statsFlow.getContainerName().equals(storedFlow.getContainerName())) {
+ return false;
+ }
+ if (statsFlow.getCookie()== null) {
+ if (storedFlow.getCookie()!= null) {
+ return false;
+ }
+ } else if(!statsFlow.getCookie().equals(storedFlow.getCookie())) {
+ return false;
+ }
+ if (statsFlow.getMatch()== null) {
+ if (storedFlow.getMatch() != null) {
+ return false;
+ }
+ } else if(!statsFlow.getMatch().equals(storedFlow.getMatch())) {
+ return false;
+ }
+ if (statsFlow.getCookie()== null) {
+ if (storedFlow.getCookie()!= null) {
+ return false;
+ }
+ } else if(!statsFlow.getCookie().equals(storedFlow.getCookie())) {
+ return false;
+ }
+ if (statsFlow.getHardTimeout() == null) {
+ if (storedFlow.getHardTimeout() != null) {
+ return false;
+ }
+ } else if(!statsFlow.getHardTimeout().equals(storedFlow.getHardTimeout() )) {
+ return false;
+ }
+ if (statsFlow.getIdleTimeout()== null) {
+ if (storedFlow.getIdleTimeout() != null) {
+ return false;
+ }
+ } else if(!statsFlow.getIdleTimeout().equals(storedFlow.getIdleTimeout())) {
+ return false;
+ }
+ if (statsFlow.getPriority() == null) {
+ if (storedFlow.getPriority() != null) {
+ return false;
+ }
+ } else if(!statsFlow.getPriority().equals(storedFlow.getPriority())) {
+ return false;
+ }
+ if (statsFlow.getTableId() == null) {
+ if (storedFlow.getTableId() != null) {
+ return false;
+ }
+ } else if(!statsFlow.getTableId().equals(storedFlow.getTableId())) {
+ return false;
+ }
+ return true;
+ }
}
this.lastAttribute = attributeIfc;
+ OpenType<?> openType = attributeIfc.getOpenType();
+
if (attributeIfc instanceof JavaAttribute) {
try {
if(((JavaAttribute)attributeIfc).getTypeDefinition() instanceof BinaryTypeDefinition) {
- return caseJavaBinaryAttribute(attributeIfc.getOpenType());
+ return caseJavaBinaryAttribute(openType);
+ } else if(((JavaAttribute)attributeIfc).isUnion()) {
+ return caseJavaUnionAttribute(openType);
} else
- return caseJavaAttribute(attributeIfc.getOpenType());
+ return caseJavaAttribute(openType);
} catch (UnknownOpenTypeException e) {
throw getIllegalArgumentException(attributeIfc);
}
} else if (attributeIfc instanceof DependencyAttribute) {
return caseDependencyAttribute(((DependencyAttribute) attributeIfc).getOpenType());
} else if (attributeIfc instanceof ListAttribute) {
- return caseListAttribute((ArrayType<?>) attributeIfc.getOpenType());
+ return caseListAttribute((ArrayType<?>) openType);
} else if (attributeIfc instanceof ListDependenciesAttribute) {
- return caseListDependeciesAttribute((ArrayType<?>) attributeIfc.getOpenType());
+ return caseListDependeciesAttribute((ArrayType<?>) openType);
} else if (attributeIfc instanceof TOAttribute) {
return caseTOAttribute(((TOAttribute) attributeIfc).getOpenType());
}
throw getIllegalArgumentException(attributeIfc);
}
+ protected T caseJavaUnionAttribute(OpenType<?> openType) {
+ return caseJavaAttribute(openType);
+ }
+
protected T caseJavaBinaryAttribute(OpenType<?> openType) {
return caseJavaAttribute(openType);
}
--- /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.confignetconfconnector.mapping.attributes;
+
+public class AttributesConstants {
+
+ /**
+ * Property placed into object names for dependencies to preserve reference name
+ */
+ public static final String REF_NAME_ON_PROPERTY_KEY = "X-refName";
+}
import com.google.common.base.Preconditions;
import com.google.common.collect.Maps;
import org.opendaylight.controller.config.yangjmxgenerator.attribute.AttributeIfc;
+import org.opendaylight.controller.config.yangjmxgenerator.attribute.JavaAttribute;
import org.opendaylight.controller.config.yangjmxgenerator.attribute.ListAttribute;
import org.opendaylight.controller.config.yangjmxgenerator.attribute.ListDependenciesAttribute;
import org.opendaylight.controller.config.yangjmxgenerator.attribute.TOAttribute;
return new SimpleBinaryAttributeReadingStrategy(lastAttribute.getNullableDefault());
}
+ @Override
+ protected AttributeReadingStrategy caseJavaUnionAttribute(OpenType<?> openType) {
+ String mappingKey = JavaAttribute.DESCRIPTION_OF_VALUE_ATTRIBUTE_FOR_UNION;
+ return new SimpleUnionAttributeReadingStrategy(lastAttribute.getNullableDefault(), mappingKey);
+ }
+
@Override
public AttributeReadingStrategy caseJavaSimpleAttribute(SimpleType<?> openType) {
return new SimpleAttributeReadingStrategy(lastAttribute.getNullableDefault());
--- /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.confignetconfconnector.mapping.attributes.fromxml;
+
+import com.google.common.collect.Lists;
+import com.google.common.collect.Maps;
+
+import java.util.List;
+import java.util.Map;
+
+public class SimpleUnionAttributeReadingStrategy extends SimpleAttributeReadingStrategy {
+
+ private final String key;
+
+ public SimpleUnionAttributeReadingStrategy(String nullableDefault, String key) {
+ super(nullableDefault);
+ this.key = key;
+ }
+
+ protected Object postprocessParsedValue(String textContent) {
+ char[] charArray = textContent.toCharArray();
+ List<String> chars = Lists.newArrayListWithCapacity(charArray.length);
+
+ for (char c : charArray) {
+ chars.add(Character.toString(c));
+ }
+
+ Map<String, Object> map = Maps.newHashMap();
+ map.put(key, chars);
+ return map;
+ }
+
+ @Override
+ protected Object postprocessNullableDefault(String nullableDefault) {
+ return nullableDefault == null ? null : postprocessParsedValue(nullableDefault);
+ }
+}
Map<String, Object> retVal = Maps.newHashMap();
for (String jmxName : jmxToJavaNameMapping.keySet()) {
- String innerAttrJmxName = jmxName;
- Object innerValue = compositeData.get(innerAttrJmxName);
-
- AttributeMappingStrategy<?, ? extends OpenType<?>> attributeMappingStrategy = innerStrategies
- .get(innerAttrJmxName);
- Optional<?> mapAttribute = attributeMappingStrategy.mapAttribute(innerValue);
- if (mapAttribute.isPresent())
- retVal.put(jmxToJavaNameMapping.get(innerAttrJmxName), mapAttribute.get());
+ Optional<?> mapped = mapInnerAttribute(compositeData, jmxName, expectedType.getDescription(jmxName));
+ if(mapped.isPresent())
+ retVal.put(jmxToJavaNameMapping.get(jmxName), mapped.get());
}
return Optional.of(retVal);
}
+ protected Optional<?> mapInnerAttribute(CompositeDataSupport compositeData, String jmxName, String description) {
+ Object innerValue = compositeData.get(jmxName);
+
+ AttributeMappingStrategy<?, ? extends OpenType<?>> attributeMappingStrategy = innerStrategies
+ .get(jmxName);
+ Optional<?> mapAttribute = attributeMappingStrategy.mapAttribute(innerValue);
+ return mapAttribute;
+ }
+
}
return new CompositeAttributeMappingStrategy(openType, innerStrategies, attributeMapping);
}
+ @Override
+ protected AttributeMappingStrategy<?, ? extends OpenType<?>> caseJavaUnionAttribute(OpenType<?> openType) {
+ Map<String, AttributeMappingStrategy<?, ? extends OpenType<?>>> innerStrategies = Maps.newHashMap();
+
+ Map<String, String> attributeMapping = Maps.newHashMap();
+
+ CompositeType compositeType = (CompositeType) openType;
+ for (String innerAttributeKey : compositeType.keySet()) {
+
+ innerStrategies.put(innerAttributeKey, caseJavaAttribute(compositeType.getType(innerAttributeKey)));
+ attributeMapping.put(innerAttributeKey, innerAttributeKey);
+ }
+
+ return new UnionCompositeAttributeMappingStrategy(compositeType, innerStrategies, attributeMapping);
+ }
+
private String serviceNameOfDepAttr;
private String namespaceOfDepAttr;
import com.google.common.base.Optional;
import com.google.common.base.Preconditions;
+import org.opendaylight.controller.netconf.confignetconfconnector.mapping.attributes.AttributesConstants;
import org.opendaylight.controller.netconf.confignetconfconnector.mapping.config.Services;
import org.opendaylight.controller.netconf.confignetconfconnector.util.Util;
Util.checkType(value, ObjectName.class);
ObjectName on = (ObjectName) value;
- String refName = tracker.addServiceEntry(namespace, serviceName, on);
+
+ String expectedRefName = on.getKeyProperty(AttributesConstants.REF_NAME_ON_PROPERTY_KEY);
+
+ String refName = expectedRefName == null ? tracker.getRefName(namespace, serviceName, on, Optional.<String> absent())
+ : tracker.getRefName(namespace, serviceName, on, Optional.of(expectedRefName));
return Optional.of(new MappedDependency(namespace, serviceName, refName));
}
--- /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.confignetconfconnector.mapping.attributes.mapping;
+
+import com.google.common.base.Optional;
+import org.opendaylight.controller.config.yangjmxgenerator.attribute.JavaAttribute;
+
+import javax.management.openmbean.CompositeDataSupport;
+import javax.management.openmbean.CompositeType;
+import javax.management.openmbean.OpenType;
+import java.util.Map;
+
+public class UnionCompositeAttributeMappingStrategy extends
+ CompositeAttributeMappingStrategy {
+
+
+ public UnionCompositeAttributeMappingStrategy(CompositeType compositeType, Map<String, AttributeMappingStrategy<?, ? extends OpenType<?>>> innerStrategies, Map<String, String> jmxToJavaNameMapping) {
+ super(compositeType, innerStrategies, jmxToJavaNameMapping);
+ }
+
+ @Override
+ protected Optional<?> mapInnerAttribute(CompositeDataSupport compositeData, String jmxName, String description) {
+ if(description.equals(JavaAttribute.DESCRIPTION_OF_VALUE_ATTRIBUTE_FOR_UNION) == false)
+ return Optional.absent();
+
+ return super.mapInnerAttribute(compositeData, jmxName, description);
+ }
+}
import javax.management.openmbean.OpenType;
import java.util.Map;
-final class CompositeAttributeResolvingStrategy extends
+class CompositeAttributeResolvingStrategy extends
AbstractAttributeResolvingStrategy<CompositeDataSupport, CompositeType> {
private final Map<String, AttributeResolvingStrategy<?, ? extends OpenType<?>>> innerTypes;
private final Map<String, String> yangToJavaAttrMapping;
Util.checkType(value, Map.class);
Map<?, ?> valueMap = (Map<?, ?>) value;
+ valueMap = preprocessValueMap(valueMap);
Map<String, Object> items = Maps.newHashMap();
Map<String, OpenType<?>> openTypes = Maps.newHashMap();
return Optional.of(parsedValue);
}
+
+ protected Map<?, ?> preprocessValueMap(Map<?, ?> valueMap) {
+ return valueMap;
+ }
}
import com.google.common.base.Optional;
import org.opendaylight.controller.config.api.jmx.ObjectNameUtil;
+import org.opendaylight.controller.netconf.confignetconfconnector.mapping.attributes.AttributesConstants;
import org.opendaylight.controller.netconf.confignetconfconnector.mapping.attributes.mapping.ObjectNameAttributeMappingStrategy;
import org.opendaylight.controller.netconf.confignetconfconnector.mapping.config.Services;
import org.opendaylight.controller.netconf.confignetconfconnector.mapping.config.Services.ServiceInstance;
ServiceInstance byRefName = serviceTracker.getByServiceAndRefName(namespace, serviceName, refName);
ObjectName on = ObjectNameUtil.createReadOnlyModuleON(byRefName.getModuleName(), byRefName.getInstanceName());
+ on = ObjectNameUtil.createON(on.toString() + "," + AttributesConstants.REF_NAME_ON_PROPERTY_KEY + "=" + refName);
+
logger.debug("Attribute {} : {} parsed to type {}", attrName, value, getOpenType());
return Optional.of(on);
}
@Override
protected AttributeResolvingStrategy<?, ? extends OpenType<?>> caseJavaCompositeAttribute(CompositeType openType) {
Map<String, AttributeResolvingStrategy<?, ? extends OpenType<?>>> innerMap = Maps.newHashMap();
-
Map<String, String> yangToJmxMapping = Maps.newHashMap();
+
+ fillMappingForComposite(openType, innerMap, yangToJmxMapping);
+ return new CompositeAttributeResolvingStrategy(innerMap, openType, yangToJmxMapping);
+ }
+
+ private void fillMappingForComposite(CompositeType openType, Map<String, AttributeResolvingStrategy<?, ? extends OpenType<?>>> innerMap, Map<String, String> yangToJmxMapping) {
for (String innerAttributeKey : openType.keySet()) {
innerMap.put(innerAttributeKey, caseJavaAttribute(openType.getType(innerAttributeKey)));
yangToJmxMapping.put(innerAttributeKey, innerAttributeKey);
}
- return new CompositeAttributeResolvingStrategy(innerMap, openType, yangToJmxMapping);
+ }
+
+ @Override
+ protected AttributeResolvingStrategy<?, ? extends OpenType<?>> caseJavaUnionAttribute(OpenType<?> openType) {
+
+ Preconditions.checkState(openType instanceof CompositeType, "Unexpected open type, expected %s but was %s");
+ CompositeType compositeType = (CompositeType) openType;
+
+ Map<String, AttributeResolvingStrategy<?, ? extends OpenType<?>>> innerMap = Maps.newHashMap();
+ Map<String, String> yangToJmxMapping = Maps.newHashMap();
+ fillMappingForComposite(compositeType, innerMap, yangToJmxMapping);
+
+ return new UnionCompositeAttributeResolvingStrategy(innerMap, compositeType, yangToJmxMapping);
}
@Override
--- /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.confignetconfconnector.mapping.attributes.resolving;
+
+import com.google.common.base.Preconditions;
+import com.google.common.collect.Maps;
+import org.opendaylight.controller.config.yangjmxgenerator.attribute.JavaAttribute;
+
+import javax.management.openmbean.CompositeType;
+import javax.management.openmbean.OpenType;
+import java.util.Map;
+
+final class UnionCompositeAttributeResolvingStrategy extends CompositeAttributeResolvingStrategy {
+
+ UnionCompositeAttributeResolvingStrategy(Map<String, AttributeResolvingStrategy<?, ? extends OpenType<?>>> innerTypes,
+ CompositeType openType, Map<String, String> yangToJavaAttrMapping) {
+ super(innerTypes, openType, yangToJavaAttrMapping);
+ }
+
+ protected Map<String, Object> preprocessValueMap(Map<?, ?> valueMap) {
+ CompositeType openType = getOpenType();
+
+ Preconditions.checkArgument(
+ valueMap.size() == 1 && valueMap.containsKey(JavaAttribute.DESCRIPTION_OF_VALUE_ATTRIBUTE_FOR_UNION),
+ "Unexpected structure of incoming map, expecting one element under %s, but was %s",
+ JavaAttribute.DESCRIPTION_OF_VALUE_ATTRIBUTE_FOR_UNION, valueMap);
+
+ Map<String, Object> newMap = Maps.newHashMap();
+
+ for (String key : openType.keySet()) {
+ if (openType.getDescription(key).equals(JavaAttribute.DESCRIPTION_OF_VALUE_ATTRIBUTE_FOR_UNION))
+ newMap.put(key, valueMap.get(JavaAttribute.DESCRIPTION_OF_VALUE_ATTRIBUTE_FOR_UNION));
+ else
+ newMap.put(key, null);
+ }
+ return newMap;
+ }
+}
return new SimpleCompositeAttributeWritingStrategy(document, key);
}
+ @Override
+ protected AttributeWritingStrategy caseJavaUnionAttribute(OpenType<?> openType) {
+ return new SimpleUnionAttributeWritingStrategy(document, key);
+ }
+
@Override
protected AttributeWritingStrategy caseDependencyAttribute(SimpleType<?> openType) {
return new ObjectNameAttributeWritingStrategy(document, key);
--- /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.confignetconfconnector.mapping.attributes.toxml;
+
+import com.google.common.base.Preconditions;
+import org.opendaylight.controller.netconf.confignetconfconnector.util.Util;
+import org.w3c.dom.Document;
+
+import java.util.List;
+import java.util.Map;
+
+public class SimpleUnionAttributeWritingStrategy extends SimpleAttributeWritingStrategy {
+
+ /**
+ * @param document
+ * @param key
+ */
+ public SimpleUnionAttributeWritingStrategy(Document document, String key) {
+ super(document, key);
+ }
+
+ protected Object preprocess(Object value) {
+ Util.checkType(value, Map.class);
+ Preconditions.checkArgument(((Map)value).size() == 1, "Unexpected number of values in %s, expected 1", value);
+ Object listOfStrings = ((Map) value).values().iterator().next();
+ Util.checkType(listOfStrings, List.class);
+
+ StringBuilder b = new StringBuilder();
+ for (Object character: (List)listOfStrings) {
+ Util.checkType(character, String.class);
+ b.append(character);
+ }
+
+ return b.toString();
+ }
+
+}
import com.google.common.collect.Lists;
import com.google.common.collect.Maps;
import com.google.common.collect.Multimap;
+import org.opendaylight.controller.config.api.ServiceReferenceReadableRegistry;
import org.opendaylight.controller.config.api.jmx.ObjectNameUtil;
import org.opendaylight.controller.netconf.confignetconfconnector.operations.editconfig.EditStrategyType;
import org.opendaylight.controller.netconf.util.xml.XmlElement;
}
public static Map<String, Map<String, Collection<ObjectName>>> getMappedInstances(Set<ObjectName> instancesToMap,
- Services serviceTracker, Map<String, Map<String, ModuleConfig>> configs) {
+ Map<String, Map<String, ModuleConfig>> configs) {
Multimap<String, ObjectName> moduleToInstances = mapInstancesToModules(instancesToMap);
Map<String, Map<String, Collection<ObjectName>>> retVal = Maps.newLinkedHashMap();
innerRetVal.put(moduleName, instances);
- // All found instances add to service tracker in advance
- // This way all instances will be serialized as all available
- // services when get-config is triggered
- // (even if they are not used as services by other instances)
- // = more user friendly
- addServices(serviceTracker, instances, mbeEntry.getValue().getProvidedServices());
-
}
retVal.put(namespace, innerRetVal);
return retVal;
}
- private static void addServices(Services serviceTracker, Collection<ObjectName> instances,
- Multimap<String, String> providedServices) {
- for (ObjectName instanceOn : instances) {
- for (Entry<String, String> serviceName : providedServices.entries()) {
- serviceTracker.addServiceEntry(serviceName.getKey(), serviceName.getValue(), instanceOn);
- }
- }
- }
-
private static Multimap<String, ObjectName> mapInstancesToModules(Set<ObjectName> instancesToMap) {
Multimap<String, ObjectName> retVal = HashMultimap.create();
// }
public Element toXml(Set<ObjectName> instancesToMap, Optional<String> maybeNamespace, Document document,
- Element dataElement) {
- Services serviceTracker = new Services();
+ Element dataElement, Services serviceTracker) {
Map<String, Map<String, Collection<ObjectName>>> moduleToInstances = getMappedInstances(instancesToMap,
- serviceTracker, moduleConfigs);
+ moduleConfigs);
Element root = dataElement;
if (maybeNamespace.isPresent()) {
// TODO refactor, replace string representing namespace with namespace class
// TODO refactor, replace Map->Multimap with e.g. ConfigElementResolved
// class
- public Map<String, Multimap<String, ModuleElementResolved>> fromXml(XmlElement xml, Set<ObjectName> instancesForFillingServiceRefMapping,
- EditStrategyType defaultEditStrategyType) {
+ public ConfigElementResolved fromXml(XmlElement xml,
+ EditStrategyType defaultEditStrategyType, ServiceReferenceReadableRegistry taClient) {
Map<String, Multimap<String, ModuleElementResolved>> retVal = Maps.newHashMap();
List<XmlElement> recognisedChildren = Lists.newArrayList();
- Services serviceTracker = fromXmlServices(xml, recognisedChildren, instancesForFillingServiceRefMapping);
+ Services serviceTracker = fromXmlServices(xml, recognisedChildren, taClient);
List<XmlElement> moduleElements = fromXmlModules(xml, recognisedChildren);
xml.checkUnrecognisedElements(recognisedChildren);
resolveModule(retVal, serviceTracker, moduleElement, defaultEditStrategyType);
}
- return retVal;
+ return new ConfigElementResolved(retVal, serviceTracker);
+ }
+
+ public static class ConfigElementResolved {
+
+ private final Map<String, Multimap<String, ModuleElementResolved>> resolvedModules;
+ private final Services services;
+
+ public ConfigElementResolved(Map<String, Multimap<String, ModuleElementResolved>> retVal, Services serviceTracker) {
+ this.resolvedModules = retVal;
+ this.services = serviceTracker;
+ }
+
+ public Map<String, Multimap<String, ModuleElementResolved>> getResolvedModules() {
+ return resolvedModules;
+ }
+
+ public Services getServices() {
+ return services;
+ }
}
private List<XmlElement> fromXmlModules(XmlElement xml, List<XmlElement> recognisedChildren) {
innerMap.put(factoryName, moduleElementResolved);
}
- private Services fromXmlServices(XmlElement xml, List<XmlElement> recognisedChildren, Set<ObjectName> instancesForFillingServiceRefMapping) {
+ private Services fromXmlServices(XmlElement xml, List<XmlElement> recognisedChildren,
+ ServiceReferenceReadableRegistry taClient) {
Optional<XmlElement> servicesElement = xml.getOnlyChildElementOptionally(XmlNetconfConstants.SERVICES_KEY,
XmlNetconfConstants.URN_OPENDAYLIGHT_PARAMS_XML_NS_YANG_CONTROLLER_CONFIG);
} else {
mappedServices = new HashMap<>();
}
- Services services = Services.resolveServices(mappedServices);
- // merge with what candidate db contains by default - ref_
-
- for(ObjectName existingON: instancesForFillingServiceRefMapping) {
- logger.trace("Filling services from {}", existingON);
- // get all its services
- String factoryName = ObjectNameUtil.getFactoryName(existingON);
- ModuleConfig moduleConfig = moduleNamesToConfigs.get(factoryName);
-
- checkState(moduleConfig != null, "Cannot find ModuleConfig with name " + factoryName + " in " + moduleNamesToConfigs);
- // Set<String> services = ;
- for (Entry<String, String> serviceName : moduleConfig.getProvidedServices().entries()) {
-
- services.addServiceEntry(serviceName.getKey(), serviceName.getValue(), existingON);
- }
- }
+ Services services = Services.resolveServices(mappedServices, taClient);
return services;
}
import com.google.common.base.Preconditions;
import com.google.common.collect.Lists;
import com.google.common.collect.Maps;
+import com.google.common.collect.Multimap;
import org.opendaylight.controller.config.util.ConfigRegistryClient;
import org.opendaylight.controller.config.yangjmxgenerator.RuntimeBeanEntry;
import org.opendaylight.controller.config.yangjmxgenerator.attribute.AttributeIfc;
}
public InstanceConfigElementResolved fromXml(XmlElement moduleElement, Services services, String moduleNamespace,
- EditStrategyType defaultStrategy) {
+ EditStrategyType defaultStrategy, Multimap<String, String> providedServices) {
Map<String, AttributeConfigElement> retVal = Maps.newHashMap();
Map<String, AttributeReadingStrategy> strats = new ObjectXmlReader().prepareReading(yangToAttrConfig);
XmlNetconfConstants.URN_IETF_PARAMS_XML_NS_NETCONF_BASE_1_0);
InstanceConfigElementResolved instanceConfigElementResolved = perInstanceEditStrategy.equals("") ? new InstanceConfigElementResolved(
- retVal, defaultStrategy) : new InstanceConfigElementResolved(perInstanceEditStrategy, retVal, defaultStrategy);
+ retVal, defaultStrategy, providedServices) : new InstanceConfigElementResolved(perInstanceEditStrategy, retVal, defaultStrategy, providedServices);
resolveConfiguration(instanceConfigElementResolved, services);
return instanceConfigElementResolved;
package org.opendaylight.controller.netconf.confignetconfconnector.mapping.config;
import com.google.common.base.Preconditions;
+import com.google.common.collect.Multimap;
import org.opendaylight.controller.netconf.confignetconfconnector.mapping.attributes.fromxml.AttributeConfigElement;
import org.opendaylight.controller.netconf.confignetconfconnector.operations.editconfig.EditConfigStrategy;
import org.opendaylight.controller.netconf.confignetconfconnector.operations.editconfig.EditConfigXmlParser;
private final EditStrategyType editStrategy;
private final Map<String, AttributeConfigElement> configuration;
+ private final Multimap<String, String> providedServices;
- public InstanceConfigElementResolved(String currentStrategy, Map<String, AttributeConfigElement> configuration, EditStrategyType defaultStrategy) {
+ public InstanceConfigElementResolved(String currentStrategy, Map<String, AttributeConfigElement> configuration, EditStrategyType defaultStrategy, Multimap<String, String> providedServices) {
EditStrategyType valueOf = checkStrategy(currentStrategy, defaultStrategy);
this.editStrategy = valueOf;
this.configuration = configuration;
+ this.providedServices = providedServices;
}
- public InstanceConfigElementResolved(Map<String, AttributeConfigElement> configuration, EditStrategyType defaultStrategy) {
+ public InstanceConfigElementResolved(Map<String, AttributeConfigElement> configuration, EditStrategyType defaultStrategy, Multimap<String, String> providedServices) {
editStrategy = defaultStrategy;
this.configuration = configuration;
+ this.providedServices = providedServices;
}
public EditConfigStrategy getEditStrategy() {
- return editStrategy.getFittingStrategy();
+ return editStrategy.getFittingStrategy(providedServices);
}
public Map<String, AttributeConfigElement> getConfiguration() {
public ModuleElementResolved fromXml(XmlElement moduleElement, Services depTracker, String instanceName,
String moduleNamespace, EditStrategyType defaultStrategy) {
- InstanceConfigElementResolved ice = instanceConfig.fromXml(moduleElement, depTracker, moduleNamespace, defaultStrategy);
+ InstanceConfigElementResolved ice = instanceConfig.fromXml(moduleElement, depTracker, moduleNamespace, defaultStrategy, providedServices);
return new ModuleElementResolved(instanceName, ice);
}
package org.opendaylight.controller.netconf.confignetconfconnector.mapping.config;
import com.google.common.annotations.VisibleForTesting;
-import com.google.common.base.Function;
+import com.google.common.base.Optional;
import com.google.common.base.Preconditions;
+import com.google.common.collect.HashMultimap;
import com.google.common.collect.Maps;
+import com.google.common.collect.Multimap;
import com.google.common.collect.Sets;
+import org.opendaylight.controller.config.api.ServiceReferenceReadableRegistry;
+import org.opendaylight.controller.config.api.jmx.ObjectNameUtil;
import org.opendaylight.controller.netconf.confignetconfconnector.mapping.attributes.fromxml.ObjectNameAttributeReadingStrategy;
import org.opendaylight.controller.netconf.util.xml.XmlElement;
import org.opendaylight.controller.netconf.util.xml.XmlNetconfConstants;
import org.w3c.dom.Document;
import org.w3c.dom.Element;
-import javax.annotation.Nullable;
import javax.management.ObjectName;
import java.util.Collection;
+import java.util.Collections;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import java.util.regex.Pattern;
public final class Services {
+
private static final Logger logger = LoggerFactory.getLogger(Services.class);
private static final String PROVIDER_KEY = "provider";
private long suffix = 1;
- private final Map<ServiceInstance, String> instanceToRef = Maps.newHashMap();
private final Map<String /*Namespace*/, Map<String/* ServiceName */, Map<String/* refName */, ServiceInstance>>> namespaceToServiceNameToRefNameToInstance = Maps
.newHashMap();
+ private ServiceReferenceReadableRegistry configServiceRefRegistry;
- public String addServiceEntry(String namespace, String serviceName, ObjectName on) {
-
- String moduleName = on.getKeyProperty("moduleFactoryName");
- String instanceName = on.getKeyProperty("instanceName");
-
- String refName = addServiceEntry(namespace, serviceName, moduleName, instanceName);
- logger.trace("Added service entry to tracker. Service name {}, ref name {}, module name {}, instance name {}",
- serviceName, refName, moduleName, instanceName);
- return refName;
+ public Services(ServiceReferenceReadableRegistry configServiceRefRegistry) {
+ this.configServiceRefRegistry = configServiceRefRegistry;
}
@VisibleForTesting
- public String addServiceEntry(String namespace, String serviceName, String moduleName, String instanceName) {
- ServiceInstance serviceInstance = new ServiceInstance(moduleName, instanceName);
- serviceInstance.setServiceName(serviceName);
+ public String getNewDefaultRefName(String namespace, String serviceName, String moduleName, String instanceName) {
+ String refName;
+ refName = "ref_" + instanceName;
- String refName = instanceToRef.get(serviceInstance);
+ Map<String, Map<String, String>> serviceNameToRefNameToInstance = getMappedServices().get(namespace);
- Map<String, Map<String, ServiceInstance>> serviceNameToRefNameToInstance = namespaceToServiceNameToRefNameToInstance.get(namespace);
- if (serviceNameToRefNameToInstance == null) {
- serviceNameToRefNameToInstance = Maps.newHashMap();
- namespaceToServiceNameToRefNameToInstance.put(namespace, serviceNameToRefNameToInstance);
- }
+ Map<String, String> refNameToInstance;
+ if(serviceNameToRefNameToInstance == null || serviceNameToRefNameToInstance.containsKey(serviceName) == false) {
+ refNameToInstance = Collections.emptyMap();
+ } else
+ refNameToInstance = serviceNameToRefNameToInstance.get(serviceName);
- Map<String, ServiceInstance> refNameToInstance = serviceNameToRefNameToInstance.get(serviceName);
- if (refNameToInstance == null) {
- refNameToInstance = Maps.newHashMap();
- serviceNameToRefNameToInstance.put(serviceName, refNameToInstance);
+ final Set<String> refNamesAsSet = toSet(refNameToInstance.keySet());
+ if (refNamesAsSet.contains(refName)) {
+ refName = findAvailableRefName(refName, refNamesAsSet);
}
- if (refName != null) {
- if (serviceNameToRefNameToInstance.get(serviceName).containsKey(moduleName) == false) {
- refNameToInstance.put(refName, serviceInstance);
- }
- return refName;
- } else {
- refName = "ref_" + instanceName;
-
- final Set<String> refNamesAsSet = toSet(instanceToRef.values());
- if (refNamesAsSet.contains(refName)) {
- refName = findAvailableRefName(refName, refNamesAsSet);
- }
-
- instanceToRef.put(serviceInstance, refName);
- refNameToInstance.put(refName, serviceInstance);
-
- return refName;
- }
+ return refName;
}
private Set<String> toSet(Collection<String> values) {
}
public ServiceInstance getByServiceAndRefName(String namespace, String serviceName, String refName) {
- Map<String, Map<String, ServiceInstance>> serviceNameToRefNameToInstance = namespaceToServiceNameToRefNameToInstance.get(namespace);
- Preconditions.checkArgument(serviceNameToRefNameToInstance != null, "No serviceInstances mapped to " + namespace + " , "
- + serviceNameToRefNameToInstance.keySet());
+ Map<String, Map<String, String>> serviceNameToRefNameToInstance = getMappedServices().get(namespace);
+
+ Preconditions.checkArgument(serviceNameToRefNameToInstance != null, "No serviceInstances mapped to " + namespace);
- Map<String, ServiceInstance> refNameToInstance = serviceNameToRefNameToInstance.get(serviceName);
+ Map<String, String> refNameToInstance = serviceNameToRefNameToInstance.get(serviceName);
Preconditions.checkArgument(refNameToInstance != null, "No serviceInstances mapped to " + serviceName + " , "
+ serviceNameToRefNameToInstance.keySet());
- ServiceInstance serviceInstance = refNameToInstance.get(refName);
+ String instanceId = refNameToInstance.get(refName);
+ Preconditions.checkArgument(instanceId != null, "No serviceInstances mapped to " + serviceName + ":"
+ + refName + ", " + serviceNameToRefNameToInstance.keySet());
+
+ ServiceInstance serviceInstance = ServiceInstance.fromString(instanceId);
Preconditions.checkArgument(serviceInstance != null, "No serviceInstance mapped to " + refName
+ " under service name " + serviceName + " , " + refNameToInstance.keySet());
return serviceInstance;
for (String serviceName : serviceNameToRefNameToInstance.keySet()) {
- Map<String, String> innerInnerRetVal = Maps.transformValues(
- serviceNameToRefNameToInstance.get(serviceName), new Function<ServiceInstance, String>() {
- @Nullable
- @Override
- public String apply(@Nullable ServiceInstance serviceInstance) {
- return serviceInstance.toString();
- }
- });
+ Map<String, String> innerInnerRetVal = Maps.newHashMap();
+ for (Entry<String, ServiceInstance> refNameToSi : serviceNameToRefNameToInstance.get(serviceName).entrySet()) {
+ innerInnerRetVal.put(refNameToSi.getKey(), refNameToSi.getValue().toString());
+ }
innerRetVal.put(serviceName, innerInnerRetVal);
}
retVal.put(namespace, innerRetVal);
}
+ Map<String, Map<String, ObjectName>> serviceMapping = configServiceRefRegistry.getServiceMapping();
+ for (String serviceQName : serviceMapping.keySet())
+ for (String refName : serviceMapping.get(serviceQName).keySet()) {
+
+ ObjectName on = serviceMapping.get(serviceQName).get(refName);
+ ServiceInstance si = ServiceInstance.fromObjectName(on);
+
+ // FIXME use QName's new String constructor, after its implemented
+ Pattern p = Pattern.compile("\\(([^\\(\\?]+)\\?[^\\?\\)]*\\)([^\\)]+)");
+ Matcher matcher = p.matcher(serviceQName);
+ Preconditions.checkArgument(matcher.matches());
+ String namespace = matcher.group(1);
+ String localName = matcher.group(2);
+
+ Map<String, Map<String, String>> serviceToRefs = retVal.get(namespace);
+ if(serviceToRefs==null) {
+ serviceToRefs = Maps.newHashMap();
+ retVal.put(namespace, serviceToRefs);
+ }
+
+ Map<String, String> refsToSis = serviceToRefs.get(localName);
+ if(refsToSis==null) {
+ refsToSis = Maps.newHashMap();
+ serviceToRefs.put(localName, refsToSis);
+ }
+
+ Preconditions.checkState(refsToSis.containsKey(refName) == false,
+ "Duplicate reference name %s for service %s:%s, now for instance %s", refName, namespace,
+ localName, on);
+ refsToSis.put(refName, si.toString());
+ }
+
return retVal;
}
+ /**
+ *
+ */
+ public Map<String, Map<String, Map<String, ServiceInstance>>> getNamespaceToServiceNameToRefNameToInstance() {
+ return namespaceToServiceNameToRefNameToInstance;
+ }
+
// TODO hide resolveServices, call it explicitly in fromXml
- public static Services resolveServices(Map<String, Map<String, Map<String, String>>> mappedServices) {
- Services tracker = new Services();
+ public static Services resolveServices(Map<String, Map<String, Map<String, String>>> mappedServices, ServiceReferenceReadableRegistry taClient) {
+ Services tracker = new Services(taClient);
for (Entry<String, Map<String, Map<String, String>>> namespaceEntry : mappedServices.entrySet()) {
String namespace = namespaceEntry.getKey();
}
String refName = refEntry.getKey();
- Preconditions.checkState(false == refNameToInstance.containsKey(refName),
- "Duplicate reference name to service " + refName + " under service " + serviceName);
+
ServiceInstance serviceInstance = ServiceInstance.fromString(refEntry.getValue());
refNameToInstance.put(refName, serviceInstance);
- tracker.instanceToRef.put(serviceInstance, refEntry.getKey());
}
}
}
return tracker;
}
+ // TODO support edit strategies on services
+
public static Map<String, Map<String, Map<String, String>>> fromXml(XmlElement xml) {
Map<String, Map<String, Map<String, String>>> retVal = Maps.newHashMap();
return root;
}
+ public String getRefName(String namespace, String serviceName, ObjectName on, Optional<String> expectedRefName) {
+ Optional<String> refNameOptional = getRefNameOptional(namespace, serviceName, on, expectedRefName);
+ Preconditions.checkState(refNameOptional.isPresent(), "No reference names mapped to %s, %s, %s", namespace,
+ serviceName, on);
+ return refNameOptional.get();
+ }
+
+ public Optional<String> getRefNameOptional(String namespace, String serviceName, ObjectName on,
+ Optional<String> expectedRefName) {
+ Map<String, Map<String, String>> services = getMappedServices().get(namespace);
+
+ if(services == null) return Optional.absent();
+ Map<String, String> refs = services.get(serviceName);
+
+ if(refs == null) return Optional.absent();
+ Multimap<ServiceInstance, String> reverted = revertMap(refs);
+
+ ServiceInstance serviceInstance = ServiceInstance.fromObjectName(on);
+ Collection<String> references = reverted.get(serviceInstance);
+
+ if (expectedRefName.isPresent() && references.contains(expectedRefName.get())) {
+ logger.debug("Returning expected ref name {} for {}", expectedRefName.get(), on);
+ return expectedRefName;
+ } else if (references.size() > 0) {
+ String next = references.iterator().next();
+ logger.debug("Returning random ref name {} for {}", next, on);
+ return Optional.of(next);
+ } else
+ return Optional.absent();
+ }
+
+ private Multimap<ServiceInstance, String> revertMap(Map<String, String> refs) {
+ Multimap<ServiceInstance, String> multimap = HashMultimap.create();
+
+ for (Entry<String, String> e : refs.entrySet()) {
+ multimap.put(ServiceInstance.fromString(e.getValue()), e.getKey());
+ }
+
+ return multimap;
+ }
+
+ public boolean hasRefName(String key, String value, ObjectName on) {
+ return getRefNameOptional(key, value, on, Optional.<String>absent()).isPresent();
+ }
+
public static final class ServiceInstance {
public ServiceInstance(String moduleName, String instanceName) {
this.moduleName = moduleName;
return true;
}
+ public ObjectName getObjectName(String transactionName) {
+ return ObjectNameUtil.createTransactionModuleON(transactionName, moduleName, instanceName);
+ }
+
+ public static ServiceInstance fromObjectName(ObjectName on) {
+ return new ServiceInstance(ObjectNameUtil.getFactoryName(on), ObjectNameUtil.getInstanceName(on));
+ }
}
}
import com.google.common.collect.HashMultimap;
import com.google.common.collect.Maps;
import com.google.common.collect.Multimap;
+import org.opendaylight.controller.config.api.ServiceReferenceReadableRegistry;
import org.opendaylight.controller.config.api.jmx.ObjectNameUtil;
import org.opendaylight.controller.netconf.confignetconfconnector.mapping.config.Config;
import org.opendaylight.controller.netconf.confignetconfconnector.mapping.config.ModuleConfig;
return retVal;
}
- public Element toXml(Set<ObjectName> instancesToMap, Set<ObjectName> configBeans, Document document) {
- Services serviceTracker = new Services();
+ public Element toXml(Set<ObjectName> instancesToMap, Set<ObjectName> configBeans, Document document, ServiceReferenceReadableRegistry serviceRegistry) {
+ Services serviceTracker = new Services(serviceRegistry);
Element root = document.createElement(XmlNetconfConstants.DATA_KEY);
Map<String, Multimap<String, ObjectName>> moduleToRuntimeInstance = mapInstancesToModules(instancesToMap);
Map<String, Map<String, Collection<ObjectName>>> moduleToConfigInstance = Config.getMappedInstances(
- configBeans, serviceTracker, moduleConfigs);
+ configBeans, moduleConfigs);
for (String localNamespace : moduleConfigs.keySet()) {
package org.opendaylight.controller.netconf.confignetconfconnector.operations.editconfig;
-import java.util.Map;
-
-import javax.management.InstanceNotFoundException;
-import javax.management.ObjectName;
-
import org.opendaylight.controller.config.util.ConfigTransactionClient;
import org.opendaylight.controller.netconf.confignetconfconnector.mapping.attributes.fromxml.AttributeConfigElement;
+import org.opendaylight.controller.netconf.confignetconfconnector.mapping.config.Services;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
+import javax.management.InstanceNotFoundException;
+import javax.management.ObjectName;
+import java.util.Map;
+
public abstract class AbstractEditConfigStrategy implements EditConfigStrategy {
private static final Logger logger = LoggerFactory.getLogger(AbstractEditConfigStrategy.class);
@Override
public void executeConfiguration(String module, String instance, Map<String, AttributeConfigElement> configuration,
- ConfigTransactionClient ta) {
+ ConfigTransactionClient ta, Services services) {
try {
ObjectName on = ta.lookupConfigBean(module, instance);
logger.debug("ServiceInstance for {} {} located successfully under {}", module, instance, on);
- executeStrategy(configuration, ta, on);
+ executeStrategy(configuration, ta, on, services);
} catch (InstanceNotFoundException e) {
- handleMissingInstance(configuration, ta, module, instance);
+ handleMissingInstance(configuration, ta, module, instance, services);
}
}
abstract void handleMissingInstance(Map<String, AttributeConfigElement> configuration, ConfigTransactionClient ta,
- String module, String instance);
+ String module, String instance, Services services);
abstract void executeStrategy(Map<String, AttributeConfigElement> configuration, ConfigTransactionClient ta,
- ObjectName objectName);
+ ObjectName objectName, Services services);
}
package org.opendaylight.controller.netconf.confignetconfconnector.operations.editconfig;
-import java.util.Map;
-
-import javax.management.InstanceNotFoundException;
-import javax.management.ObjectName;
-
+import com.google.common.collect.HashMultimap;
+import com.google.common.collect.Multimap;
import org.opendaylight.controller.config.util.ConfigTransactionClient;
import org.opendaylight.controller.netconf.confignetconfconnector.mapping.attributes.fromxml.AttributeConfigElement;
+import org.opendaylight.controller.netconf.confignetconfconnector.mapping.config.Services;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
+import javax.management.InstanceNotFoundException;
+import javax.management.ObjectName;
+import java.util.Map;
+
public class DeleteEditConfigStrategy extends AbstractEditConfigStrategy {
private static final Logger logger = LoggerFactory.getLogger(DeleteEditConfigStrategy.class);
+ private final Multimap<String, String> providedServices;
+
+ public DeleteEditConfigStrategy() {
+ this.providedServices = HashMultimap.create();
+ }
+
+ public DeleteEditConfigStrategy(Multimap<String, String> providedServices) {
+ this.providedServices = providedServices;
+ }
+
@Override
void handleMissingInstance(Map<String, AttributeConfigElement> configuration, ConfigTransactionClient ta,
- String module, String instance) {
+ String module, String instance, Services services) {
throw new IllegalStateException("Unable to delete " + module + ":" + instance + " , ServiceInstance not found");
}
@Override
- void executeStrategy(Map<String, AttributeConfigElement> configuration, ConfigTransactionClient ta, ObjectName on) {
+ void executeStrategy(Map<String, AttributeConfigElement> configuration, ConfigTransactionClient ta, ObjectName on, Services services) {
try {
ta.destroyModule(on);
logger.debug("ServiceInstance {} deleted successfully", on);
import org.opendaylight.controller.netconf.confignetconfconnector.mapping.config.InstanceConfigElementResolved;
import org.opendaylight.controller.netconf.confignetconfconnector.mapping.config.ModuleConfig;
import org.opendaylight.controller.netconf.confignetconfconnector.mapping.config.ModuleElementResolved;
+import org.opendaylight.controller.netconf.confignetconfconnector.mapping.config.Services;
import org.opendaylight.controller.netconf.confignetconfconnector.operations.AbstractConfigNetconfOperation;
import org.opendaylight.controller.netconf.confignetconfconnector.operations.editconfig.EditConfigXmlParser.EditConfigExecution;
import org.opendaylight.controller.netconf.confignetconfconnector.transactions.TransactionProvider;
import org.w3c.dom.Document;
import org.w3c.dom.Element;
+import javax.management.InstanceNotFoundException;
import javax.management.ObjectName;
import java.util.HashMap;
import java.util.Map;
@VisibleForTesting
Element getResponseInternal(final Document document,
final EditConfigXmlParser.EditConfigExecution editConfigExecution) throws NetconfDocumentedException {
+
if (editConfigExecution.shouldTest()) {
executeTests(configRegistryClient, editConfigExecution);
}
private void executeTests(ConfigRegistryClient configRegistryClient,
EditConfigExecution editConfigExecution) throws NetconfDocumentedException {
try {
- test(configRegistryClient, editConfigExecution.getResolvedXmlElements(), editConfigExecution.getDefaultStrategy());
+ test(configRegistryClient, editConfigExecution, editConfigExecution.getDefaultStrategy());
} catch (IllegalStateException | JmxAttributeValidationException | ValidationException e) {
logger.warn("Test phase for {} failed", EditConfigXmlParser.EDIT_CONFIG, e);
final Map<String, String> errorInfo = new HashMap<>();
}
private void test(ConfigRegistryClient configRegistryClient,
- Map<String, Multimap<String, ModuleElementResolved>> resolvedModules, EditStrategyType editStrategyType) {
+ EditConfigExecution execution, EditStrategyType editStrategyType) {
ObjectName taON = transactionProvider.getTestTransaction();
try {
if (editStrategyType == EditStrategyType.replace) {
transactionProvider.wipeTestTransaction(taON);
}
- setOnTransaction(configRegistryClient, resolvedModules, taON);
+
+ setOnTransaction(configRegistryClient, execution.getResolvedXmlElements(), execution.getServices(), taON);
+ // TODO add service reference persistance testing here
transactionProvider.validateTestTransaction(taON);
} finally {
transactionProvider.abortTestTransaction(taON);
if (editConfigExecution.getDefaultStrategy() == EditStrategyType.replace) {
transactionProvider.wipeTransaction();
}
- setOnTransaction(configRegistryClient, editConfigExecution.getResolvedXmlElements(), taON);
+
+ setOnTransaction(configRegistryClient, editConfigExecution.getResolvedXmlElements(),
+ editConfigExecution.getServices(), taON);
+ setServicesOnTransaction(configRegistryClient, editConfigExecution.getServices(), taON);
+ }
+
+ private void setServicesOnTransaction(ConfigRegistryClient configRegistryClient, Services services,
+ ObjectName taON) {
+ ConfigTransactionClient ta = configRegistryClient.getConfigTransactionClient(taON);
+
+ Map<String, Map<String, Map<String, Services.ServiceInstance>>> namespaceToServiceNameToRefNameToInstance = services
+ .getNamespaceToServiceNameToRefNameToInstance();
+
+ for (String serviceNamespace : namespaceToServiceNameToRefNameToInstance.keySet()) {
+ for (String serviceName : namespaceToServiceNameToRefNameToInstance.get(serviceNamespace).keySet()) {
+
+ String qnameOfService = getQname(ta, serviceNamespace, serviceName);
+ Map<String, Services.ServiceInstance> refNameToInstance = namespaceToServiceNameToRefNameToInstance
+ .get(serviceNamespace).get(serviceName);
+
+ for (String refName : refNameToInstance.keySet()) {
+ ObjectName on = refNameToInstance.get(refName).getObjectName(ta.getTransactionName());
+ // TODO check for duplicates
+ try {
+ ta.saveServiceReference(qnameOfService, refName, on);
+ } catch (InstanceNotFoundException e) {
+ throw new IllegalStateException("Unable to save ref name " + refName + " for instance " + on, e);
+ }
+ }
+ }
+ }
+ }
+
+ private String getQname(ConfigTransactionClient ta, String namespace, String serviceName) {
+ return ta.getServiceInterfaceName(namespace, serviceName);
}
private void setOnTransaction(ConfigRegistryClient configRegistryClient,
- Map<String, Multimap<String, ModuleElementResolved>> resolvedXmlElements, ObjectName taON) {
+ Map<String, Multimap<String, ModuleElementResolved>> resolvedXmlElements, Services services, ObjectName taON) {
ConfigTransactionClient ta = configRegistryClient.getConfigTransactionClient(taON);
for (Multimap<String, ModuleElementResolved> modulesToResolved : resolvedXmlElements.values()) {
InstanceConfigElementResolved ice = moduleElementResolved.getInstanceConfigElementResolved();
EditConfigStrategy strategy = ice.getEditStrategy();
- strategy.executeConfiguration(moduleName, instanceName, ice.getConfiguration(), ta);
+ strategy.executeConfiguration(moduleName, instanceName, ice.getConfiguration(), ta, services);
}
}
}
import org.opendaylight.controller.config.util.ConfigTransactionClient;
import org.opendaylight.controller.netconf.confignetconfconnector.mapping.attributes.fromxml.AttributeConfigElement;
+import org.opendaylight.controller.netconf.confignetconfconnector.mapping.config.Services;
import java.util.Map;
public interface EditConfigStrategy {
void executeConfiguration(String module, String instance, Map<String, AttributeConfigElement> configuration,
- ConfigTransactionClient ta);
+ ConfigTransactionClient ta, Services services);
}
import com.google.common.base.Optional;
import com.google.common.base.Preconditions;
import com.google.common.collect.Multimap;
+import org.opendaylight.controller.config.api.ServiceReferenceReadableRegistry;
import org.opendaylight.controller.config.util.ConfigRegistryClient;
+import org.opendaylight.controller.config.util.ConfigTransactionClient;
import org.opendaylight.controller.netconf.api.NetconfDocumentedException;
import org.opendaylight.controller.netconf.confignetconfconnector.mapping.config.Config;
import org.opendaylight.controller.netconf.confignetconfconnector.mapping.config.ModuleElementResolved;
+import org.opendaylight.controller.netconf.confignetconfconnector.mapping.config.Services;
import org.opendaylight.controller.netconf.confignetconfconnector.operations.Datastore;
import org.opendaylight.controller.netconf.confignetconfconnector.transactions.TransactionProvider;
import org.opendaylight.controller.netconf.util.xml.XmlElement;
import javax.management.ObjectName;
import java.util.Arrays;
-import java.util.Collections;
import java.util.Map;
-import java.util.Set;
public class EditConfigXmlParser {
TransactionProvider transactionProvider, ConfigRegistryClient configRegistryClient)
throws NetconfDocumentedException {
+ //TODO remove transactionProvider and CfgRegistry from parameters, accept only service ref store
+
EditStrategyType editStrategyType = EditStrategyType.getDefaultStrategy();
xml.checkName(EditConfigXmlParser.EDIT_CONFIG);
logger.trace("Setting merge strategy to {}", mergeStrategyString);
editStrategyType = EditStrategyType.valueOf(mergeStrategyString);
}
- Set<ObjectName> instancesForFillingServiceRefMapping = Collections.emptySet();
- if (editStrategyType == EditStrategyType.merge) {
- instancesForFillingServiceRefMapping = Datastore.getInstanceQueryStrategy(targetDatastore, transactionProvider)
- .queryInstances(configRegistryClient);
- logger.trace("Pre-filling services from following instances: {}", instancesForFillingServiceRefMapping);
- }
XmlElement configElement = xml.getOnlyChildElementWithSameNamespace(XmlNetconfConstants.CONFIG_KEY);
- return new EditConfigXmlParser.EditConfigExecution(xml, cfgMapping, configElement, testOption,
- instancesForFillingServiceRefMapping, editStrategyType);
- }
+ ObjectName taON = transactionProvider.getOrCreateTransaction();
+ ConfigTransactionClient ta = configRegistryClient.getConfigTransactionClient(taON);
- private void removeMountpointsFromConfig(XmlElement configElement, XmlElement mountpointsElement) {
- configElement.getDomElement().removeChild(mountpointsElement.getDomElement());
+ return new EditConfigXmlParser.EditConfigExecution(cfgMapping, configElement, testOption,
+ ta, editStrategyType);
}
@VisibleForTesting
@VisibleForTesting
static class EditConfigExecution {
- private final XmlElement editConfigXml;
+
private final Map<String, Multimap<String, ModuleElementResolved>> resolvedXmlElements;
private final TestOption testOption;
private final EditStrategyType defaultEditStrategyType;
+ private final Services services;
- EditConfigExecution(XmlElement xml, Config configResolver, XmlElement configElement, TestOption testOption, Set<ObjectName> instancesForFillingServiceRefMapping,
- EditStrategyType defaultStrategy) {
- this.editConfigXml = xml;
- this.resolvedXmlElements = configResolver.fromXml(configElement, instancesForFillingServiceRefMapping, defaultStrategy);
+ EditConfigExecution(Config configResolver, XmlElement configElement, TestOption testOption, ServiceReferenceReadableRegistry ta, EditStrategyType defaultStrategy) {
+ Config.ConfigElementResolved configElementResolved = configResolver.fromXml(configElement, defaultStrategy, ta);
+ this.resolvedXmlElements = configElementResolved.getResolvedModules();
+ this.services = configElementResolved.getServices();
this.testOption = testOption;
this.defaultEditStrategyType = defaultStrategy;
}
EditStrategyType getDefaultStrategy() {
return defaultEditStrategyType;
}
+
+ Services getServices() {
+ return services;
+ }
}
}
package org.opendaylight.controller.netconf.confignetconfconnector.operations.editconfig;
+import com.google.common.collect.Multimap;
+
import java.util.EnumSet;
import java.util.Set;
}
}
- public EditConfigStrategy getFittingStrategy() {
+ public EditConfigStrategy getFittingStrategy(Multimap<String, String> providedServices) {
switch (this) {
case merge:
- return new MergeEditConfigStrategy();
+ return new MergeEditConfigStrategy(providedServices);
case replace:
- return new ReplaceEditConfigStrategy();
+ return new ReplaceEditConfigStrategy(providedServices);
case delete:
- return new DeleteEditConfigStrategy();
+ return new DeleteEditConfigStrategy(providedServices);
case remove:
return new RemoveEditConfigStrategy();
case none:
package org.opendaylight.controller.netconf.confignetconfconnector.operations.editconfig;
-import java.util.Map;
-import java.util.Map.Entry;
-
-import javax.management.Attribute;
-import javax.management.InstanceAlreadyExistsException;
-import javax.management.ObjectName;
-
+import com.google.common.collect.HashMultimap;
+import com.google.common.collect.Multimap;
import org.opendaylight.controller.config.util.ConfigTransactionClient;
import org.opendaylight.controller.netconf.confignetconfconnector.mapping.attributes.fromxml.AttributeConfigElement;
+import org.opendaylight.controller.netconf.confignetconfconnector.mapping.config.Services;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
+import javax.management.Attribute;
+import javax.management.InstanceAlreadyExistsException;
+import javax.management.InstanceNotFoundException;
+import javax.management.ObjectName;
+import java.util.Map;
+import java.util.Map.Entry;
+
public class MergeEditConfigStrategy extends AbstractEditConfigStrategy {
private static final Logger logger = LoggerFactory.getLogger(MergeEditConfigStrategy.class);
+ private final Multimap<String, String> providedServices;
+
+ public MergeEditConfigStrategy() {
+ this.providedServices = HashMultimap.create();
+ }
+
+ public MergeEditConfigStrategy(Multimap<String, String> providedServices) {
+ this.providedServices = providedServices;
+ }
@Override
void handleMissingInstance(Map<String, AttributeConfigElement> configuration, ConfigTransactionClient ta,
- String module, String instance) {
- ObjectName on;
+ String module, String instance, Services services) {
+ ObjectName on = null;
try {
on = ta.createModule(module, instance);
logger.info("New instance for {} {} created under name {}", module, instance, on);
- executeStrategy(configuration, ta, on);
+ addRefNames(services, providedServices, module, instance, ta, on);
+ executeStrategy(configuration, ta, on, services);
} catch (InstanceAlreadyExistsException e1) {
throw new IllegalStateException("Unable to create instance for " + module + " : " + instance);
+ } catch (InstanceNotFoundException e) {
+ throw new IllegalStateException("Unable to save default ref name for instance " + on, e);
+ }
+ }
+
+ private void addRefNames(Services services, Multimap<String, String> providedServices, String module,
+ String instance, ConfigTransactionClient ta, ObjectName on) throws InstanceNotFoundException {
+ for (Entry<String, String> namespaceToService : providedServices.entries()) {
+
+ if(services.hasRefName(namespaceToService.getKey(),
+ namespaceToService.getValue(), on))
+ continue;
+
+ String refName = services.getNewDefaultRefName(namespaceToService.getKey(), namespaceToService.getValue(),
+ module, instance);
+ ta.saveServiceReference(
+ ta.getServiceInterfaceName(namespaceToService.getKey(), namespaceToService.getValue()), refName, on);
}
}
@Override
- void executeStrategy(Map<String, AttributeConfigElement> configuration, ConfigTransactionClient ta, ObjectName on) {
+ void executeStrategy(Map<String, AttributeConfigElement> configuration, ConfigTransactionClient ta, ObjectName on, Services services) {
for (Entry<String, AttributeConfigElement> configAttributeEntry : configuration.entrySet()) {
try {
AttributeConfigElement ace = configAttributeEntry.getValue();
import org.opendaylight.controller.config.util.ConfigTransactionClient;
import org.opendaylight.controller.netconf.confignetconfconnector.mapping.attributes.fromxml.AttributeConfigElement;
+import org.opendaylight.controller.netconf.confignetconfconnector.mapping.config.Services;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@Override
public void executeConfiguration(String module, String instance, Map<String, AttributeConfigElement> configuration,
- ConfigTransactionClient ta) {
+ ConfigTransactionClient ta, Services services) {
logger.debug("Skipping configuration element for {}:{}", module, instance);
}
import org.opendaylight.controller.config.util.ConfigTransactionClient;
import org.opendaylight.controller.netconf.confignetconfconnector.mapping.attributes.fromxml.AttributeConfigElement;
+import org.opendaylight.controller.netconf.confignetconfconnector.mapping.config.Services;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@Override
void handleMissingInstance(Map<String, AttributeConfigElement> configuration, ConfigTransactionClient ta,
- String module, String instance) {
+ String module, String instance, Services services) {
logger.warn("Unable to delete {}:{}, ServiceInstance not found", module, instance);
}
}
package org.opendaylight.controller.netconf.confignetconfconnector.operations.editconfig;
-import java.util.Map;
-import java.util.Map.Entry;
-
-import javax.management.Attribute;
-import javax.management.InstanceAlreadyExistsException;
-import javax.management.ObjectName;
-
+import com.google.common.collect.HashMultimap;
+import com.google.common.collect.Multimap;
import org.opendaylight.controller.config.util.ConfigTransactionClient;
import org.opendaylight.controller.netconf.confignetconfconnector.mapping.attributes.fromxml.AttributeConfigElement;
+import org.opendaylight.controller.netconf.confignetconfconnector.mapping.config.Services;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
+import javax.management.Attribute;
+import javax.management.InstanceAlreadyExistsException;
+import javax.management.InstanceNotFoundException;
+import javax.management.ObjectName;
+import java.util.Map;
+import java.util.Map.Entry;
+
public class ReplaceEditConfigStrategy extends AbstractEditConfigStrategy {
private static final Logger logger = LoggerFactory.getLogger(ReplaceEditConfigStrategy.class);
+ private final Multimap<String, String> providedServices;
+
+ public ReplaceEditConfigStrategy() {
+ this.providedServices = HashMultimap.create();
+ }
+
+ public ReplaceEditConfigStrategy(Multimap<String, String> providedServices) {
+ this.providedServices = providedServices;
+ }
+
@Override
void handleMissingInstance(Map<String, AttributeConfigElement> configuration, ConfigTransactionClient ta,
- String module, String instance) {
+ String module, String instance, Services services) {
+ ObjectName on = null;
try {
- ObjectName on = ta.createModule(module, instance);
+ on = ta.createModule(module, instance);
logger.debug("New instance for {} {} created under name {}", module, instance, on);
- executeStrategy(configuration, ta, on);
+ addRefNames(services, providedServices, module, instance, ta, on);
+ executeStrategy(configuration, ta, on, services);
} catch (InstanceAlreadyExistsException e) {
logger.warn("Error creating instance {}:{}, replace failed", module, instance, e);
throw new IllegalStateException("Unable to create new instance for " + module + " : " + instance, e);
+ } catch (InstanceNotFoundException e) {
+ throw new IllegalStateException("Unable to save default ref name for instance " + on, e);
}
}
+ private void addRefNames(Services services, Multimap<String, String> providedServices, String module,
+ String instance, ConfigTransactionClient ta, ObjectName on) throws InstanceNotFoundException {
+ for (Entry<String, String> namespaceToService : providedServices.entries()) {
+
+ if(services.hasRefName(namespaceToService.getKey(),
+ namespaceToService.getValue(), on))
+ continue;
+
+ String refName = services.getNewDefaultRefName(namespaceToService.getKey(), namespaceToService.getValue(),
+ module, instance);
+ ta.saveServiceReference(
+ ta.getServiceInterfaceName(namespaceToService.getKey(), namespaceToService.getValue()), refName, on);
+ }
+ }
@Override
- void executeStrategy(Map<String, AttributeConfigElement> configuration, ConfigTransactionClient ta, ObjectName on) {
+ void executeStrategy(Map<String, AttributeConfigElement> configuration, ConfigTransactionClient ta, ObjectName on, Services services) {
for (Entry<String, AttributeConfigElement> configAttributeEntry : configuration.entrySet()) {
try {
AttributeConfigElement ace = configAttributeEntry.getValue();
import com.google.common.collect.Maps;
import org.opendaylight.controller.config.util.ConfigRegistryClient;
+import org.opendaylight.controller.config.util.ConfigTransactionClient;
import org.opendaylight.controller.config.yang.store.api.YangStoreSnapshot;
import org.opendaylight.controller.config.yangjmxgenerator.ModuleMXBeanEntry;
import org.opendaylight.controller.config.yangjmxgenerator.RuntimeBeanEntry;
import org.opendaylight.controller.netconf.confignetconfconnector.operations.AbstractConfigNetconfOperation;
import org.opendaylight.controller.netconf.confignetconfconnector.operations.Datastore;
import org.opendaylight.controller.netconf.confignetconfconnector.operations.getconfig.GetConfig;
+import org.opendaylight.controller.netconf.confignetconfconnector.transactions.TransactionProvider;
import org.opendaylight.controller.netconf.util.xml.XmlElement;
import org.opendaylight.controller.netconf.util.xml.XmlNetconfConstants;
import org.slf4j.Logger;
private final YangStoreSnapshot yangStoreSnapshot;
private static final Logger logger = LoggerFactory.getLogger(Get.class);
+ private final TransactionProvider transactionProvider;
public Get(YangStoreSnapshot yangStoreSnapshot, ConfigRegistryClient configRegistryClient,
- String netconfSessionIdForReporting) {
+ String netconfSessionIdForReporting, TransactionProvider transactionProvider) {
super(configRegistryClient, netconfSessionIdForReporting);
this.yangStoreSnapshot = yangStoreSnapshot;
+ this.transactionProvider = transactionProvider;
}
private Map<String, Map<String, ModuleRuntime>> createModuleRuntimes(ConfigRegistryClient configRegistryClient,
final Runtime runtime = new Runtime(moduleRuntimes, moduleConfigs);
- final Element element = runtime.toXml(runtimeBeans, configBeans, document);
+ ObjectName txOn = transactionProvider.getOrCreateTransaction();
+ ConfigTransactionClient ta = configRegistryClient.getConfigTransactionClient(txOn);
+ final Element element = runtime.toXml(runtimeBeans, configBeans, document, ta);
logger.info("{} operation successful", XmlNetconfConstants.GET);
import com.google.common.base.Optional;
import com.google.common.collect.Maps;
import org.opendaylight.controller.config.util.ConfigRegistryClient;
+import org.opendaylight.controller.config.util.ConfigTransactionClient;
import org.opendaylight.controller.config.yang.store.api.YangStoreSnapshot;
import org.opendaylight.controller.config.yangjmxgenerator.ModuleMXBeanEntry;
import org.opendaylight.controller.netconf.api.NetconfDocumentedException;
import org.opendaylight.controller.netconf.confignetconfconnector.mapping.config.Config;
import org.opendaylight.controller.netconf.confignetconfconnector.mapping.config.InstanceConfig;
import org.opendaylight.controller.netconf.confignetconfconnector.mapping.config.ModuleConfig;
+import org.opendaylight.controller.netconf.confignetconfconnector.mapping.config.Services;
import org.opendaylight.controller.netconf.confignetconfconnector.operations.AbstractConfigNetconfOperation;
import org.opendaylight.controller.netconf.confignetconfconnector.operations.Datastore;
import org.opendaylight.controller.netconf.confignetconfconnector.transactions.TransactionProvider;
final Config configMapping = new Config(transform(configRegistryClient,
yangStoreSnapshot.getModuleMXBeanEntryMap()));
- dataElement = configMapping.toXml(instances, this.maybeNamespace, document, dataElement);
+
+
+ ObjectName on = transactionProvider.getOrCreateTransaction();
+ ConfigTransactionClient ta = configRegistryClient.getConfigTransactionClient(on);
+
+ Services serviceTracker = new Services(ta);
+ dataElement = configMapping.toXml(instances, this.maybeNamespace, document, dataElement, serviceTracker);
logger.info("{} operation successful", GET_CONFIG);
ops.add(new EditConfig(yangStoreSnapshot, transactionProvider, configRegistryClient,
netconfSessionIdForReporting));
ops.add(new Commit(transactionProvider, configRegistryClient, netconfSessionIdForReporting));
- ops.add(new Get(yangStoreSnapshot, configRegistryClient, netconfSessionIdForReporting));
+ ops.add(new Get(yangStoreSnapshot, configRegistryClient, netconfSessionIdForReporting, transactionProvider));
ops.add(new DiscardChanges(transactionProvider, configRegistryClient, netconfSessionIdForReporting));
ops.add(new Validate(transactionProvider, configRegistryClient, netconfSessionIdForReporting));
ops.add(new RuntimeRpc(yangStoreSnapshot, configRegistryClient, netconfSessionIdForReporting));
package org.opendaylight.controller.netconf.confignetconfconnector.osgi;
+import com.google.common.annotations.VisibleForTesting;
import com.google.common.base.Optional;
+import com.google.common.base.Preconditions;
import com.google.common.collect.Sets;
+import org.opendaylight.controller.config.api.LookupRegistry;
import org.opendaylight.controller.config.util.ConfigRegistryJMXClient;
import org.opendaylight.controller.config.yang.store.api.YangStoreException;
import org.opendaylight.controller.config.yang.store.api.YangStoreService;
import org.opendaylight.controller.config.yang.store.api.YangStoreSnapshot;
+import org.opendaylight.controller.config.yangjmxgenerator.ModuleMXBeanEntry;
import org.opendaylight.controller.netconf.confignetconfconnector.transactions.TransactionProvider;
import org.opendaylight.controller.netconf.confignetconfconnector.util.Util;
import org.opendaylight.controller.netconf.mapping.api.Capability;
String netconfSessionIdForReporting) throws YangStoreException {
yangStoreSnapshot = yangStoreService.getYangStoreSnapshot();
+ checkConsistencyBetweenYangStoreAndConfig(jmxClient, yangStoreSnapshot);
+
transactionProvider = new TransactionProvider(jmxClient, netconfSessionIdForReporting);
operationProvider = new NetconfOperationProvider(yangStoreSnapshot, jmxClient, transactionProvider,
netconfSessionIdForReporting);
capabilities = setupCapabilities(yangStoreSnapshot);
}
+
+ @VisibleForTesting
+ static void checkConsistencyBetweenYangStoreAndConfig(LookupRegistry jmxClient, YangStoreSnapshot yangStoreSnapshot) {
+ Set<String> missingModulesFromConfig = Sets.newHashSet();
+
+ Set<String> modulesSeenByConfig = jmxClient.getAvailableModuleFactoryQNames();
+ Map<String, Map<String, ModuleMXBeanEntry>> moduleMXBeanEntryMap = yangStoreSnapshot.getModuleMXBeanEntryMap();
+
+ for (Map<String, ModuleMXBeanEntry> moduleNameToMBE : moduleMXBeanEntryMap.values()) {
+ for (ModuleMXBeanEntry moduleMXBeanEntry : moduleNameToMBE.values()) {
+ String moduleSeenByYangStore = moduleMXBeanEntry.getYangModuleQName().toString();
+ if(modulesSeenByConfig.contains(moduleSeenByYangStore) == false)
+ missingModulesFromConfig.add(moduleSeenByYangStore);
+ }
+ }
+
+ Preconditions
+ .checkState(
+ missingModulesFromConfig.isEmpty(),
+ "There are inconsistencies between configuration subsystem and yangstore in terms of discovered yang modules, yang modules missing from config subsystem but present in yangstore: %s, %sAll modules present in config: %s",
+ missingModulesFromConfig, System.lineSeparator(), modulesSeenByConfig);
+
+ }
+
@Override
public void close() {
yangStoreSnapshot.close();
}
/**
- * Wiping means removing all module instances keeping the transaction open.
+ * Wiping means removing all module instances keeping the transaction open + service references.
*/
synchronized void wipeInternal(ObjectName taON, boolean isTest, String moduleName) {
ConfigTransactionClient transactionClient = configRegistryClient.getConfigTransactionClient(taON);
Set<ObjectName> lookupConfigBeans = moduleName == null ? transactionClient.lookupConfigBeans()
: transactionClient.lookupConfigBeans(moduleName);
+ int i = lookupConfigBeans.size();
for (ObjectName instance : lookupConfigBeans) {
try {
transactionClient.destroyModule(instance);
throw new IllegalStateException("Unable to clean configuration in transactiom " + taON, e);
}
}
- logger.debug("Transaction {} wiped clean", taON);
+ logger.debug("Transaction {} wiped clean of {} config beans", taON, i);
+
+ transactionClient.removeAllServiceReferences();
+ logger.debug("Transaction {} wiped clean of all service references", taON);
}
public void wipeTransaction() {
public static void checkType(final Object value, final Class<?> clazz) {
Preconditions.checkArgument(clazz.isAssignableFrom(value.getClass()), "Unexpected type " + value.getClass()
- + " should be " + clazz);
+ + " should be " + clazz + " of " + value);
}
// TODO: add message and proper error types
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.Test;
import org.junit.matchers.JUnitMatchers;
import org.mockito.Mock;
import org.mockito.MockitoAnnotations;
+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.opendaylight.controller.config.manager.impl.factoriesresolver.HardcodedModuleFactoriesResolver;
import org.opendaylight.controller.config.util.ConfigTransactionJMXClient;
import org.slf4j.LoggerFactory;
import org.w3c.dom.Document;
import org.w3c.dom.Element;
+import org.w3c.dom.NodeList;
import org.xml.sax.SAXException;
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;
public class NetconfMappingTest extends AbstractConfigTest {
private static final Logger logger = LoggerFactory.getLogger(NetconfMappingTest.class);
- private static final String INSTANCE_NAME = "test1";
+ private static final String INSTANCE_NAME = "instance-from-code";
private static final String NETCONF_SESSION_ID = "foo";
private NetconfTestImplModuleFactory factory;
private DepTestImplModuleFactory factory2;
transactionProvider = new TransactionProvider(this.configRegistryClient, NETCONF_SESSION_ID);
}
- private ObjectName createModule(final String instanceName) throws InstanceAlreadyExistsException {
+ private ObjectName createModule(final String instanceName) throws InstanceAlreadyExistsException, InstanceNotFoundException, URISyntaxException {
final ConfigTransactionJMXClient transaction = this.configRegistryClient.createTransaction();
final ObjectName on = transaction.createModule(this.factory.getImplementationName(), instanceName);
final NetconfTestImplModuleMXBean mxBean = transaction.newMXBeanProxy(on, NetconfTestImplModuleMXBean.class);
- setModule(mxBean, transaction);
+ setModule(mxBean, transaction, instanceName + "_dep");
+ int i = 1;
+ for (Class<? extends AbstractServiceInterface> sInterface : factory.getImplementedServiceIntefaces()) {
+ ServiceInterfaceAnnotation annotation = sInterface.getAnnotation(ServiceInterfaceAnnotation.class);
+ transaction.saveServiceReference(
+ transaction.getServiceInterfaceName(annotation.namespace(), annotation.localName()), "ref_from_code_to_" + instanceName + "_" + i++,
+ on);
+
+ }
transaction.commit();
return on;
}
+ @Test
+ public void testServicePersistance() throws Exception {
+ createModule(INSTANCE_NAME);
+
+ edit("netconfMessages/editConfig.xml");
+ Element config = getConfigCandidate();
+ assertCorrectServiceNames(config, 6, "ref_test2", "user_to_instance_from_code", "ref_dep_user",
+ "ref_dep_user_two", "ref_from_code_to_instance-from-code_dep_1",
+ "ref_from_code_to_instance-from-code_1");
+
+ edit("netconfMessages/editConfig_addServiceName.xml");
+ config = getConfigCandidate();
+ assertCorrectServiceNames(config, 7, "ref_test2", "user_to_instance_from_code", "ref_dep_user",
+ "ref_dep_user_two", "ref_from_code_to_instance-from-code_dep_1",
+ "ref_from_code_to_instance-from-code_1", "ref_dep_user_another");
+
+ commit();
+ config = getConfigRunning();
+ assertCorrectRefNamesForDependencies(config);
+ assertCorrectServiceNames(config, 7, "ref_test2", "user_to_instance_from_code", "ref_dep_user",
+ "ref_dep_user_two", "ref_from_code_to_instance-from-code_dep_1",
+ "ref_from_code_to_instance-from-code_1", "ref_dep_user_another");
+
+ edit("netconfMessages/editConfig_replace_default.xml");
+ config = getConfigCandidate();
+ assertCorrectServiceNames(config, 2, "ref_dep", "ref_dep2");
+
+ edit("netconfMessages/editConfig_remove.xml");
+ config = getConfigCandidate();
+ assertCorrectServiceNames(config, 0);
+
+ commit();
+ config = getConfigCandidate();
+ assertCorrectServiceNames(config, 0);
+
+ }
+
+ private void assertCorrectRefNamesForDependencies(Element config) {
+ NodeList modulesList = config.getElementsByTagName("modules");
+ assertEquals(1, modulesList.getLength());
+
+ Element modules = (Element) modulesList.item(0);
+
+ String trimmedModules = XmlUtil.toString(modules).replaceAll("\\s", "");
+ int defaultRefNameCount = StringUtils.countMatches(trimmedModules, "ref_dep2");
+ int userRefNameCount = StringUtils.countMatches(trimmedModules, "ref_dep_user_two");
+
+ assertEquals(0, defaultRefNameCount);
+ assertEquals(2, userRefNameCount);
+ }
+
+ private void assertCorrectServiceNames(Element configCandidate, int servicesSize, String... refNames) {
+ NodeList elements = configCandidate.getElementsByTagName("provider");
+ assertEquals(servicesSize, elements.getLength());
+
+ NodeList servicesList = configCandidate.getElementsByTagName("services");
+ assertEquals(1, servicesList.getLength());
+
+ Element services = (Element) servicesList.item(0);
+ String trimmedServices = XmlUtil.toString(services).replaceAll("\\s", "");
+
+ for (String s : refNames) {
+ assertThat(trimmedServices, JUnitMatchers.containsString(s));
+ }
+ }
+
+ @Test
+ public void testConfigNetconfUnionTypes() throws Exception {
+
+ createModule(INSTANCE_NAME);
+
+ edit("netconfMessages/editConfig.xml");
+ commit();
+ Element response = getConfigRunning();
+ String trimmedResponse = XmlUtil.toString(response).replaceAll("\\s", "");
+ assertContainsString(trimmedResponse, "<ipxmlns=\"urn:opendaylight:params:xml:ns:yang:controller:test:impl\">0:0:0:0:0:0:0:1</ip>");
+ assertContainsString(trimmedResponse, "<union-test-attrxmlns=\"urn:opendaylight:params:xml:ns:yang:controller:test:impl\">456</union-test-attr>");
+
+
+ edit("netconfMessages/editConfig_setUnions.xml");
+ commit();
+ response = getConfigRunning();
+
+ trimmedResponse = XmlUtil.toString(response).replaceAll("\\s", "");
+ assertContainsString(trimmedResponse, "<ipxmlns=\"urn:opendaylight:params:xml:ns:yang:controller:test:impl\">127.1.2.3</ip>");
+ assertContainsString(trimmedResponse, "<union-test-attrxmlns=\"urn:opendaylight:params:xml:ns:yang:controller:test:impl\">randomStringForUnion</union-test-attr>");
+
+ }
+
@Test
public void testConfigNetconf() throws Exception {
createModule(INSTANCE_NAME);
edit("netconfMessages/editConfig.xml");
- checkBinaryLeafEdited(getConfigCandidate());
+ Element configCandidate = getConfigCandidate();
+ checkBinaryLeafEdited(configCandidate);
// default-operation:none, should not affect binary leaf
return executeOp(getConfigOp, "netconfMessages/getConfig.xml");
}
+ @Ignore("second edit message corrupted")
@Test(expected = NetconfDocumentedException.class)
public void testConfigNetconfReplaceDefaultEx() throws Exception {
for (XmlElement moduleElement : modulesElement.getChildElements("module")) {
String name = moduleElement.getOnlyChildElement("name").getTextContent();
- if(name.equals("test1")) {
+ if(name.equals(INSTANCE_NAME)) {
XmlElement enumAttr = moduleElement.getOnlyChildElement(enumName);
assertEquals(enumContent, enumAttr.getTextContent());
XmlElement modulesElement = XmlElement.fromDomElement(response).getOnlyChildElement("data")
.getOnlyChildElement("modules");
- XmlElement configAttributeType = null;
+ List<String> expectedValues = Lists.newArrayList("default-string", "configAttributeType");
+ Set<String> configAttributeType = Sets.newHashSet();
+
for (XmlElement moduleElement : modulesElement.getChildElements("module")) {
for (XmlElement type : moduleElement.getChildElements("type")) {
if (type.getAttribute(XmlUtil.XMLNS_ATTRIBUTE_KEY).equals("") == false) {
- configAttributeType = type;
+ configAttributeType.add(type.getTextContent());
}
}
}
- assertEquals("configAttributeType", configAttributeType.getTextContent());
+ for (String expectedValue : expectedValues) {
+ assertTrue(configAttributeType.contains(expectedValue));
+ }
}
private Map<String, Map<String, ModuleMXBeanEntry>> getMbes() throws Exception {
}
private Element get() throws NetconfDocumentedException, ParserConfigurationException, SAXException, IOException {
- Get getOp = new Get(yangStoreSnapshot, configRegistryClient, NETCONF_SESSION_ID);
+ Get getOp = new Get(yangStoreSnapshot, configRegistryClient, NETCONF_SESSION_ID, transactionProvider);
return executeOp(getOp, "netconfMessages/get.xml");
}
return Lists.newArrayList(yangDependencies);
}
- private void setModule(final NetconfTestImplModuleMXBean mxBean, final ConfigTransactionJMXClient transaction)
- throws InstanceAlreadyExistsException {
+ private void setModule(final NetconfTestImplModuleMXBean mxBean, final ConfigTransactionJMXClient transaction, String depName)
+ throws InstanceAlreadyExistsException, InstanceNotFoundException {
mxBean.setSimpleInt((long) 44);
mxBean.setBinaryLeaf(new byte[] { 8, 7, 9 });
final DtoD dtob = getDtoD();
mxBean.setComplexList(Lists.<ComplexList> newArrayList());
mxBean.setSimpleList(Lists.<Integer> newArrayList());
- final ObjectName testingDepOn = transaction.createModule(this.factory2.getImplementationName(), "dep");
+ final ObjectName testingDepOn = transaction.createModule(this.factory2.getImplementationName(), depName);
+ int i = 1;
+ for (Class<? extends AbstractServiceInterface> sInterface : factory2.getImplementedServiceIntefaces()) {
+ ServiceInterfaceAnnotation annotation = sInterface.getAnnotation(ServiceInterfaceAnnotation.class);
+ transaction.saveServiceReference(
+ transaction.getServiceInterfaceName(annotation.namespace(), annotation.localName()), "ref_from_code_to_" + depName + "_" + i++,
+ testingDepOn);
+
+ }
mxBean.setTestingDep(testingDepOn);
}
import org.opendaylight.controller.netconf.confignetconfconnector.mapping.config.Services.ServiceInstance;
import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertTrue;
public class ServiceTrackerTest {
assertEquals(serviceInstance, serviceInstance2);
}
- @Test
- public void testOneInstanceMultipleServices() {
- Services services = new Services();
- services.addServiceEntry("nm", "s1", "module", "instance");
- assertEquals(1, services.getMappedServices().size());
-
- services.addServiceEntry("nm2", "s2", "module", "instance");
- assertEquals(2, services.getMappedServices().size());
- }
-
- @Test
- public void testMultipleInstancesOneName() throws Exception {
- Services services = new Services();
- services.addServiceEntry("nm", "s1", "module", "instance");
- assertEquals(1, services.getMappedServices().size());
-
- services.addServiceEntry("nm", "s1", "module2", "instance");
- assertEquals(1, services.getMappedServices().size());
- assertEquals(2, services.getMappedServices().get("nm").get("s1").size());
- assertTrue(services.getMappedServices().get("nm").get("s1").containsKey("ref_instance"));
- assertTrue(services.getMappedServices().get("nm").get("s1").containsKey("ref_instance_1"));
- }
-
- @Test
- public void testMultipleInstancesOneName2() throws Exception {
- Services services = new Services();
- services.addServiceEntry("nm", "s1", "module", "instance_1");
-
- services.addServiceEntry("nm2", "s2", "module2", "instance");
- services.addServiceEntry("nm2", "s2", "module3", "instance");
- services.addServiceEntry("nm", "s1", "module3", "instance");
-
- assertEquals(2, services.getMappedServices().get("nm").get("s1").size());
- assertEquals(2, services.getMappedServices().get("nm2").get("s2").size());
- assertTrue(services.getMappedServices().get("nm").get("s1").containsKey("ref_instance_2"));
- assertTrue(services.getMappedServices().get("nm").get("s1").containsKey("ref_instance_1"));
- assertTrue(services.getMappedServices().get("nm2").get("s2").containsKey("ref_instance"));
- assertTrue(services.getMappedServices().get("nm2").get("s2").containsKey("ref_instance_2"));
- }
-
}
import org.junit.Test;
import org.mockito.Mock;
import org.mockito.MockitoAnnotations;
+import org.opendaylight.controller.config.api.ServiceReferenceReadableRegistry;
import org.opendaylight.controller.config.util.ConfigRegistryClient;
import org.opendaylight.controller.config.util.ConfigTransactionClient;
import org.opendaylight.controller.config.yang.store.api.YangStoreSnapshot;
import org.opendaylight.controller.netconf.api.NetconfDocumentedException;
import org.opendaylight.controller.netconf.confignetconfconnector.mapping.attributes.fromxml.AttributeConfigElement;
-import org.opendaylight.controller.netconf.confignetconfconnector.mapping.config.Config;
import org.opendaylight.controller.netconf.confignetconfconnector.mapping.config.InstanceConfigElementResolved;
import org.opendaylight.controller.netconf.confignetconfconnector.mapping.config.ModuleElementResolved;
+import org.opendaylight.controller.netconf.confignetconfconnector.mapping.config.Services;
import org.opendaylight.controller.netconf.confignetconfconnector.operations.ValidateTest;
import org.opendaylight.controller.netconf.confignetconfconnector.operations.editconfig.EditConfigXmlParser.EditConfigExecution;
import org.opendaylight.controller.netconf.confignetconfconnector.transactions.TransactionProvider;
-import org.opendaylight.controller.netconf.util.xml.XmlElement;
import org.opendaylight.controller.netconf.util.xml.XmlUtil;
import javax.management.ObjectName;
import java.util.Collections;
import java.util.Map;
-import java.util.Set;
import static org.mockito.Matchers.any;
import static org.mockito.Matchers.anyMap;
EditConfig edit = new EditConfig(yangStoreSnapshot, provider, configRegistry,
ValidateTest.NETCONF_SESSION_ID_FOR_REPORTING);
EditConfigStrategy editStrat = mock(EditConfigStrategy.class);
- doNothing().when(editStrat).executeConfiguration(anyString(), anyString(), anyMap(),
- any(ConfigTransactionClient.class));
- Map<String, Multimap<String, ModuleElementResolved>> resolvedXmlElements = getMapping(editStrat);
- Config cfg = mock(Config.class);
- XmlElement xmlElement = mock(XmlElement.class);
- Set<ObjectName> instancesForFillingServiceRefMapping = Collections.emptySet();
- EditStrategyType defaultStrategy = EditStrategyType.getDefaultStrategy();
- doReturn(resolvedXmlElements).when(cfg).fromXml(xmlElement, instancesForFillingServiceRefMapping, defaultStrategy);
+ doNothing().when(editStrat).executeConfiguration(anyString(), anyString(), anyMap(),
+ any(ConfigTransactionClient.class), any(Services.class));
- EditConfigExecution editConfigExecution = new EditConfigExecution(null, cfg, xmlElement,
- EditConfigXmlParser.TestOption.testThenSet, instancesForFillingServiceRefMapping, defaultStrategy);
+ EditConfigExecution editConfigExecution = mockExecution(editStrat);
edit.getResponseInternal(XmlUtil.newDocument(), editConfigExecution);
// For every instance execute strat
verify(editStrat, times(2/* Test */+ 2/* Set */)).executeConfiguration(anyString(), anyString(), anyMap(),
- any(ConfigTransactionClient.class));
+ any(ConfigTransactionClient.class), any(Services.class));
+ }
+
+ private EditConfigExecution mockExecution(EditConfigStrategy editStrat) {
+ EditConfigExecution mock = mock(EditConfigExecution.class);
+ doReturn(getMapping(editStrat)).when(mock).getResolvedXmlElements();
+ doReturn(EditStrategyType.merge).when(mock).getDefaultStrategy();
+ doReturn(true).when(mock).shouldSet();
+ doReturn(true).when(mock).shouldTest();
+ doReturn(mockServices()).when(mock).getServices();
+ return mock;
+ }
+
+ private static ServiceReferenceReadableRegistry mockServiceRegistry() {
+ ServiceReferenceReadableRegistry mock = mock(ServiceReferenceReadableRegistry.class);
+ doReturn(
+ Collections.emptyMap())
+ .when(mock).getServiceMapping();
+ doReturn("mockedServiceReg").when(mock).toString();
+
+ return mock;
+ }
+
+ static Services mockServices() {
+ return new Services(mockServiceRegistry());
}
private Map<String, Multimap<String, ModuleElementResolved>> getMapping(EditConfigStrategy editStrat) {
doReturn(Sets.newHashSet(mockON(), mockON())).when(ta).lookupConfigBeans();
- strat.executeConfiguration("m1", "i1", map, ta);
+ strat.executeConfiguration("m1", "i1", map, ta, EditConfigTest.mockServices());
verify(ta).lookupConfigBean(anyString(), anyString());
verify(ta).setAttribute(any(ObjectName.class), anyString(), any(Attribute.class));
--- /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.confignetconfconnector.osgi;
+
+import com.google.common.collect.Maps;
+import com.google.common.collect.Sets;
+import org.junit.Assert;
+import org.junit.Test;
+import org.junit.matchers.JUnitMatchers;
+import org.opendaylight.controller.config.api.LookupRegistry;
+import org.opendaylight.controller.config.yang.store.api.YangStoreSnapshot;
+import org.opendaylight.controller.config.yangjmxgenerator.ModuleMXBeanEntry;
+import org.opendaylight.yangtools.yang.common.QName;
+
+import java.net.URI;
+import java.text.ParseException;
+import java.text.SimpleDateFormat;
+import java.util.Date;
+import java.util.Map;
+import java.util.Set;
+
+import static org.junit.Assert.fail;
+import static org.mockito.Mockito.doReturn;
+import static org.mockito.Mockito.mock;
+
+public class NetconfOperationServiceImplTest {
+
+ private static final Date date1970_01_01;
+
+ static {
+ try {
+ date1970_01_01 = new SimpleDateFormat("yyyy-MM-dd").parse("1970-01-01");
+ } catch (ParseException e) {
+ throw new IllegalStateException(e);
+ }
+ }
+
+ @Test
+ public void testCheckConsistencyBetweenYangStoreAndConfig_ok() throws Exception {
+ NetconfOperationServiceImpl.checkConsistencyBetweenYangStoreAndConfig(
+ mockJmxClient("qname1", "qname2"),
+ mockYangStoreSnapshot("qname2", "qname1"));
+ }
+
+ @Test
+ public void testCheckConsistencyBetweenYangStoreAndConfig_ok2() throws Exception {
+ NetconfOperationServiceImpl.checkConsistencyBetweenYangStoreAndConfig(
+ mockJmxClient("qname1", "qname2", "qname4", "qname5"),
+ mockYangStoreSnapshot("qname2", "qname1"));
+ }
+
+ @Test
+ public void testCheckConsistencyBetweenYangStoreAndConfig_ok3() throws Exception {
+ NetconfOperationServiceImpl.checkConsistencyBetweenYangStoreAndConfig(
+ mockJmxClient(),
+ mockYangStoreSnapshot());
+ }
+
+ @Test
+ public void testCheckConsistencyBetweenYangStoreAndConfig_yangStoreMore() throws Exception {
+ try {
+ NetconfOperationServiceImpl.checkConsistencyBetweenYangStoreAndConfig(mockJmxClient("qname1"),
+ mockYangStoreSnapshot("qname2", "qname1"));
+ fail("An exception of type " + IllegalArgumentException.class + " was expected");
+ } catch (IllegalStateException e) {
+ String message = e.getMessage();
+ Assert.assertThat(
+ message,
+ JUnitMatchers
+ .containsString("missing from config subsystem but present in yangstore: [(namespace?revision=1970-01-01)qname2]"));
+ Assert.assertThat(
+ message,
+ JUnitMatchers
+ .containsString("All modules present in config: [(namespace?revision=1970-01-01)qname1]"));
+ }
+ }
+
+ private YangStoreSnapshot mockYangStoreSnapshot(String... qnames) {
+ YangStoreSnapshot mock = mock(YangStoreSnapshot.class);
+
+ Map<String, Map<String, ModuleMXBeanEntry>> map = Maps.newHashMap();
+
+ Map<String, ModuleMXBeanEntry> innerMap = Maps.newHashMap();
+
+ int i = 1;
+ for (String qname : qnames) {
+ innerMap.put(Integer.toString(i++), mockMBeanEntry(qname));
+ }
+
+ map.put("1", innerMap);
+
+ doReturn(map).when(mock).getModuleMXBeanEntryMap();
+
+ return mock;
+ }
+
+ private ModuleMXBeanEntry mockMBeanEntry(String qname) {
+ ModuleMXBeanEntry mock = mock(ModuleMXBeanEntry.class);
+ QName q = getQName(qname);
+ doReturn(q).when(mock).getYangModuleQName();
+ return mock;
+ }
+
+ private QName getQName(String qname) {
+ return new QName(URI.create("namespace"), date1970_01_01, qname);
+ }
+
+ private LookupRegistry mockJmxClient(String... visibleQNames) {
+ LookupRegistry mock = mock(LookupRegistry.class);
+ Set<String> qnames = Sets.newHashSet();
+ for (String visibleQName : visibleQNames) {
+ QName q = getQName(visibleQName);
+ qnames.add(q.toString());
+ }
+ doReturn(qnames).when(mock).getAvailableModuleFactoryQNames();
+ return mock;
+ }
+}
</dependency>
<dependency>
<groupId>org.opendaylight.controller</groupId>
- <artifactId>config-persister-file-adapter</artifactId>
+ <artifactId>config-persister-file-xml-adapter</artifactId>
+ <scope>test</scope>
+ <version>${config.version}</version>
</dependency>
<!-- test dependencies -->
</dependency>
<dependency>
<groupId>org.opendaylight.controller</groupId>
- <artifactId>config-persister-directory-adapter</artifactId>
- <version>${parent.version}</version>
+ <artifactId>config-persister-directory-xml-adapter</artifactId>
+ <version>${config.version}</version>
<scope>test</scope>
</dependency>
</dependencies>
org.opendaylight.controller.netconf.client,
org.opendaylight.controller.netconf.util.osgi,
org.opendaylight.controller.netconf.util.xml,
+ org.opendaylight.controller.netconf.util.messages,
io.netty.channel,
io.netty.channel.nio,
io.netty.util.concurrent,
package org.opendaylight.controller.netconf.persist.impl;
-import com.google.common.base.Optional;
-import com.google.common.base.Preconditions;
import io.netty.channel.EventLoopGroup;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.net.InetSocketAddress;
+import java.util.Collections;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Set;
+
+import javax.annotation.concurrent.Immutable;
+
import org.opendaylight.controller.config.api.ConflictingVersionException;
import org.opendaylight.controller.config.persist.api.ConfigSnapshotHolder;
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.messages.NetconfMessageAdditionalHeader;
import org.opendaylight.controller.netconf.util.xml.XmlElement;
import org.opendaylight.controller.netconf.util.xml.XmlNetconfConstants;
import org.opendaylight.controller.netconf.util.xml.XmlUtil;
import org.w3c.dom.Element;
import org.xml.sax.SAXException;
-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.List;
-import java.util.Set;
+import com.google.common.base.Optional;
+import com.google.common.base.Preconditions;
@Immutable
public class ConfigPusher {
long deadline = pollingStart + timeout;
+ String additionalHeader = NetconfMessageAdditionalHeader.toString("unknown", address.getAddress().getHostAddress(),
+ Integer.toString(address.getPort()), "tcp", Optional.of("persister"));
+
Set<String> latestCapabilities = new HashSet<>();
while (System.currentTimeMillis() < deadline) {
attempt++;
- NetconfClientDispatcher netconfClientDispatcher = new NetconfClientDispatcher(nettyThreadgroup, nettyThreadgroup);
+ NetconfClientDispatcher netconfClientDispatcher = new NetconfClientDispatcher(nettyThreadgroup,
+ nettyThreadgroup, additionalHeader);
NetconfClient netconfClient;
try {
netconfClient = new NetconfClient(this.toString(), address, delay, netconfClientDispatcher);
NetconfMessage message = createEditConfigMessage(xmlToBePersisted, "/netconfOp/editConfig.xml");
// sending message to netconf
- NetconfMessage responseMessage = netconfClient.sendMessage(message, NETCONF_SEND_ATTEMPTS, NETCONF_SEND_ATTEMPT_MS_DELAY);
+ NetconfMessage responseMessage = getResponse(message, netconfClient);
XmlElement element = XmlElement.fromDomDocument(responseMessage.getDocument());
Preconditions.checkState(element.getName().equals(XmlNetconfConstants.RPC_REPLY_KEY));
Util.checkIsOk(element, responseMessage);
response.append(XmlUtil.toString(responseMessage.getDocument()));
response.append("}");
- responseMessage = netconfClient.sendMessage(getNetconfMessageFromResource("/netconfOp/commit.xml"), NETCONF_SEND_ATTEMPTS, NETCONF_SEND_ATTEMPT_MS_DELAY);
+ responseMessage = getResponse(getNetconfMessageFromResource("/netconfOp/commit.xml"), netconfClient);
element = XmlElement.fromDomDocument(responseMessage.getDocument());
Preconditions.checkState(element.getName().equals(XmlNetconfConstants.RPC_REPLY_KEY));
logger.trace("Detailed message {}", response);
}
+ private static NetconfMessage getResponse(NetconfMessage request, NetconfClient netconfClient) {
+ try {
+ return netconfClient.sendMessage(request, NETCONF_SEND_ATTEMPTS, NETCONF_SEND_ATTEMPT_MS_DELAY);
+ } catch(RuntimeException e) {
+ logger.error("Error while sending message {} to {}", request, netconfClient);
+ throw e;
+ }
+ }
+
private static NetconfMessage createEditConfigMessage(Element dataElement, String editConfigResourcename) {
try (InputStream stream = ConfigPersisterNotificationHandler.class.getResourceAsStream(editConfigResourcename)) {
Preconditions.checkNotNull(stream, "Unable to load resource " + editConfigResourcename);
* Example configuration:<pre>
netconf.config.persister.active=2,3
# read startup configuration
- netconf.config.persister.1.storageAdapterClass=org.opendaylight.controller.config.persist.storage.directory.DirectoryStorageAdapter
+ netconf.config.persister.1.storageAdapterClass=org.opendaylight.controller.config.persist.storage.directory.xml.XmlDirectoryStorageAdapter
netconf.config.persister.1.properties.fileStorage=configuration/initial/
netconf.config.persister.2.storageAdapterClass=org.opendaylight.controller.config.persist.storage.file.FileStorageAdapter
-/**
- * @author Tomas Olvecky
+/*
+ * Copyright (c) 2013 Cisco Systems, Inc. and others. All rights reserved.
*
- * 11 2013
- *
- * Copyright (c) 2013 by Cisco Systems, Inc.
- * All rights reserved.
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
*/
package org.opendaylight.controller.netconf.persist.impl;
import org.junit.Test;
import org.opendaylight.controller.config.persist.api.ConfigSnapshotHolder;
import org.opendaylight.controller.config.persist.api.Persister;
-import org.opendaylight.controller.config.persist.storage.file.FileStorageAdapter;
+import org.opendaylight.controller.config.persist.storage.file.xml.XmlFileStorageAdapter;
import org.opendaylight.controller.netconf.persist.impl.osgi.ConfigPersisterActivator;
import org.opendaylight.controller.netconf.persist.impl.osgi.PropertiesProviderBaseImpl;
List<PersisterWithConfiguration> persisters = persisterAggregator.getPersisterWithConfigurations();
assertEquals(1, persisters.size());
PersisterWithConfiguration persister = persisters.get(0);
- assertEquals(FileStorageAdapter.class.getName() ,persister.getStorage().getClass().getName());
+ assertEquals(XmlFileStorageAdapter.class.getName() ,persister.getStorage().getClass().getName());
assertFalse(persister.isReadOnly());
}
netconf.config.persister.active=2
# read startup configuration
-netconf.config.persister.1.storageAdapterClass=org.opendaylight.controller.config.persist.storage.directory.DirectoryStorageAdapter
+netconf.config.persister.1.storageAdapterClass=org.opendaylight.controller.config.persist.storage.directory.xml.XmlDirectoryStorageAdapter
netconf.config.persister.1.properties.directoryStorage=target/configuration/initial/
netconf.config.persister.1.readonly=true
-netconf.config.persister.2.storageAdapterClass=org.opendaylight.controller.config.persist.storage.file.FileStorageAdapter
+netconf.config.persister.2.storageAdapterClass=org.opendaylight.controller.config.persist.storage.file.xml.XmlFileStorageAdapter
netconf.config.persister.2.properties.fileStorage=target/configuration/current/controller.config.2.txt
netconf.config.persister.2.properties.numberOfBackups=3
netconf.config.persister.active=3
-netconf.config.persister.3.storageAdapterClass=org.opendaylight.controller.config.persist.storage.file.FileStorageAdapter
+netconf.config.persister.3.storageAdapterClass=org.opendaylight.controller.config.persist.storage.file.xml.XmlFileStorageAdapter
netconf.config.persister.3.properties.fileStorage=target/configuration/current/controller.config.2.txt
netconf.config.persister.3.properties.numberOfBackups=0
--- /dev/null
+<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+ <parent>
+ <artifactId>netconf-subsystem</artifactId>
+ <groupId>org.opendaylight.controller</groupId>
+ <version>0.2.3-SNAPSHOT</version>
+ </parent>
+ <modelVersion>4.0.0</modelVersion>
+ <artifactId>ietf-netconf-monitoring-extension</artifactId>
+ <name>${project.artifactId}</name>
+ <packaging>bundle</packaging>
+
+ <dependencies>
+ <dependency>
+ <groupId>org.opendaylight.controller</groupId>
+ <artifactId>ietf-netconf-monitoring</artifactId>
+ </dependency>
+ <dependency>
+ <groupId>com.google.guava</groupId>
+ <artifactId>guava</artifactId>
+ </dependency>
+ <dependency>
+ <groupId>org.slf4j</groupId>
+ <artifactId>slf4j-api</artifactId>
+ </dependency>
+ </dependencies>
+
+
+ <build>
+ <plugins>
+ <plugin>
+ <groupId>org.opendaylight.yangtools</groupId>
+ <artifactId>yang-maven-plugin</artifactId>
+ <version>${yangtools.version}</version>
+ <executions>
+ <execution>
+ <goals>
+ <goal>generate-sources</goal>
+ </goals>
+ <configuration>
+ <yangFilesRootDir>src/main/yang</yangFilesRootDir>
+ <codeGenerators>
+ <generator>
+ <codeGeneratorClass>
+ org.opendaylight.yangtools.maven.sal.api.gen.plugin.CodeGeneratorImpl
+ </codeGeneratorClass>
+ <outputBaseDir>
+ target/generated-sources/monitoring
+ </outputBaseDir>
+ </generator>
+ </codeGenerators>
+ <inspectDependencies>true</inspectDependencies>
+ </configuration>
+ </execution>
+ </executions>
+ <dependencies>
+ <dependency>
+ <groupId>org.opendaylight.yangtools</groupId>
+ <artifactId>maven-sal-api-gen-plugin</artifactId>
+ <version>${yangtools.binding.version}</version>
+ </dependency>
+ </dependencies>
+ </plugin>
+ <plugin>
+ <groupId>org.codehaus.mojo</groupId>
+ <artifactId>build-helper-maven-plugin</artifactId>
+ <version>1.7</version>
+ <executions>
+ <execution>
+ <phase>generate-sources</phase>
+ <goals>
+ <goal>add-source</goal>
+ </goals>
+ <configuration>
+ <sources>
+ <source>target/generated-sources/sal</source>
+ </sources>
+ </configuration>
+ </execution>
+ </executions>
+ </plugin>
+
+ <plugin>
+ <groupId>org.apache.felix</groupId>
+ <artifactId>maven-bundle-plugin</artifactId>
+ <configuration>
+ <instructions>
+ <Import-Package>
+ com.google.common.collect,
+ org.opendaylight.yangtools.yang.binding,
+ org.opendaylight.yangtools.yang.common,
+ org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.netconf.monitoring.rev101004,
+ </Import-Package>
+ <Export-Package>
+ org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.netconf.monitoring.extension.rev131210,
+ </Export-Package>
+ </instructions>
+ </configuration>
+ </plugin>
+ </plugins>
+ </build>
+</project>
\ No newline at end of file
--- /dev/null
+module ietf-netconf-monitoring-extension {
+
+ yang-version 1;
+
+ namespace
+ "urn:ietf:params:xml:ns:yang:ietf-netconf-monitoring-extension";
+
+ prefix ncme;
+
+ import ietf-netconf-monitoring {
+ prefix ncm;
+ }
+
+ revision "2013-12-10" {
+ description "Initial revision.";
+
+ }
+
+ identity netconf-tcp {
+ base ncm:transport;
+ description
+ "NETCONF over TCP.";
+ }
+
+ augment "/ncm:netconf-state/ncm:sessions/ncm:session" {
+ leaf session-identifier {
+ type string;
+ }
+ }
+
+}
\ No newline at end of file
--- /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.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.netconf.monitoring.rev101004.netconf.state.schemas;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev100924.Uri;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.netconf.monitoring.rev101004.netconf.state.schemas.Schema.Location;
+
+
+/**
+**/
+public class LocationBuilder {
+
+ public static Location getDefaultInstance(String defaultValue) {
+ return defaultValue.equals("NETCONF") ? new Location(Location.Enumeration.NETCONF) : new Location(new Uri(
+ defaultValue));
+ }
+
+}
<groupId>${project.groupId}</groupId>
<artifactId>ietf-netconf-monitoring</artifactId>
</dependency>
+ <dependency>
+ <groupId>${project.groupId}</groupId>
+ <artifactId>ietf-netconf-monitoring-extension</artifactId>
+ <version>${project.version}</version>
+ </dependency>
<dependency>
<groupId>org.opendaylight.bgpcep</groupId>
package org.opendaylight.controller.netconf.api;
-import com.google.common.base.Optional;
import org.w3c.dom.Document;
+import com.google.common.base.Optional;
+
/**
* NetconfMessage represents a wrapper around org.w3c.dom.Document. Needed for
* implementing ProtocolMessage interface.
}
public NetconfMessage sendMessage(NetconfMessage message, int attempts, int attemptMsDelay) {
+ long startTime = System.currentTimeMillis();
Preconditions.checkState(clientSession.isUp(), "Session was not up yet");
clientSession.sendMessage(message);
try {
throw new RuntimeException(this + " Cannot read message from " + address, e);
} catch (IllegalStateException e) {
throw new IllegalStateException(this + " Cannot read message from " + address, e);
+ } finally {
+ long diffMillis = System.currentTimeMillis() - startTime;
+ logger.debug("Total time spent waiting for response {}", diffMillis);
}
}
import io.netty.util.HashedWheelTimer;
import io.netty.util.concurrent.Future;
import io.netty.util.concurrent.Promise;
+
import java.io.Closeable;
import java.net.InetSocketAddress;
+
import org.opendaylight.controller.netconf.api.NetconfMessage;
import org.opendaylight.controller.netconf.api.NetconfSession;
import org.opendaylight.controller.netconf.api.NetconfTerminationReason;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
+import com.google.common.base.Optional;
+
public class NetconfClientDispatcher extends AbstractDispatcher<NetconfClientSession, NetconfClientSessionListener> implements Closeable {
private static final Logger logger = LoggerFactory.getLogger(NetconfClient.class);
public NetconfClientDispatcher(EventLoopGroup bossGroup, EventLoopGroup workerGroup) {
super(bossGroup, workerGroup);
timer = new HashedWheelTimer();
- this.negotatorFactory = new NetconfClientSessionNegotiatorFactory(timer);
+ this.negotatorFactory = new NetconfClientSessionNegotiatorFactory(timer, Optional.<String>absent());
+ }
+
+ public NetconfClientDispatcher(EventLoopGroup bossGroup, EventLoopGroup workerGroup, String additionalHeader) {
+ super(bossGroup, workerGroup);
+ timer = new HashedWheelTimer();
+ this.negotatorFactory = new NetconfClientSessionNegotiatorFactory(timer, Optional.of(additionalHeader));
}
public Future<NetconfClientSession> createClient(InetSocketAddress address,
package org.opendaylight.controller.netconf.client;
-import com.google.common.base.Preconditions;
import io.netty.channel.Channel;
import io.netty.util.Timer;
import io.netty.util.concurrent.Promise;
+
+import java.io.IOException;
+import java.io.InputStream;
+
import org.opendaylight.controller.netconf.api.NetconfMessage;
import org.opendaylight.controller.netconf.api.NetconfSessionPreferences;
import org.opendaylight.controller.netconf.util.xml.XmlUtil;
import org.opendaylight.protocol.framework.SessionNegotiatorFactory;
import org.xml.sax.SAXException;
-import java.io.IOException;
-import java.io.InputStream;
+import com.google.common.base.Optional;
+import com.google.common.base.Preconditions;
public class NetconfClientSessionNegotiatorFactory implements SessionNegotiatorFactory {
private final Timer timer;
- public NetconfClientSessionNegotiatorFactory(Timer timer) {
+ private final Optional<String> additionalHeader;
+
+ public NetconfClientSessionNegotiatorFactory(Timer timer, Optional<String> additionalHeader) {
this.timer = timer;
+ this.additionalHeader = additionalHeader;
}
private static NetconfMessage loadHelloMessageTemplate() {
public SessionNegotiator getSessionNegotiator(SessionListenerFactory sessionListenerFactory, Channel channel,
Promise promise) {
// Hello message needs to be recreated every time
- NetconfSessionPreferences proposal = new NetconfSessionPreferences(loadHelloMessageTemplate());
+ NetconfMessage helloMessage = loadHelloMessageTemplate();
+ if(this.additionalHeader.isPresent()) {
+ helloMessage = new NetconfMessage(helloMessage.getDocument(), additionalHeader.get());
+ }
+ NetconfSessionPreferences proposal = new NetconfSessionPreferences(helloMessage);
return new NetconfClientSessionNegotiator(proposal, promise, channel, timer,
sessionListenerFactory.getSessionListener());
}
import io.netty.util.HashedWheelTimer;
import io.netty.util.concurrent.Future;
import io.netty.util.concurrent.Promise;
+
import java.io.IOException;
import java.net.InetSocketAddress;
+
import org.opendaylight.controller.netconf.api.NetconfMessage;
import org.opendaylight.controller.netconf.api.NetconfSession;
import org.opendaylight.controller.netconf.api.NetconfTerminationReason;
import org.opendaylight.protocol.framework.SessionListener;
import org.opendaylight.protocol.framework.SessionListenerFactory;
+import com.google.common.base.Optional;
+
public class NetconfSshClientDispatcher extends NetconfClientDispatcher {
private AuthenticationHandler authHandler;
super(bossGroup, workerGroup);
this.authHandler = authHandler;
this.timer = new HashedWheelTimer();
- this.negotatorFactory = new NetconfClientSessionNegotiatorFactory(timer);
+ this.negotatorFactory = new NetconfClientSessionNegotiatorFactory(timer, Optional.<String>absent());
+ }
+
+ public NetconfSshClientDispatcher(AuthenticationHandler authHandler, EventLoopGroup bossGroup,
+ EventLoopGroup workerGroup, String additionalHeader) {
+ super(bossGroup, workerGroup, additionalHeader);
+ this.authHandler = authHandler;
+ this.timer = new HashedWheelTimer();
+ this.negotatorFactory = new NetconfClientSessionNegotiatorFactory(timer, Optional.of(additionalHeader));
}
public Future<NetconfClientSession> createClient(InetSocketAddress address,
<groupId>${project.groupId}</groupId>
<artifactId>ietf-netconf-monitoring</artifactId>
</dependency>
+ <dependency>
+ <groupId>${project.groupId}</groupId>
+ <artifactId>ietf-netconf-monitoring-extension</artifactId>
+ <version>${project.version}</version>
+ </dependency>
<dependency>
<groupId>${project.groupId}</groupId>
<artifactId>netconf-util</artifactId>
org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.netconf.monitoring.rev101004.netconf.state,
org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.netconf.monitoring.rev101004.netconf.state.sessions,
org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.netconf.monitoring.rev101004.netconf.state.schemas,
+ org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.netconf.monitoring.extension.rev131210,
+ org.opendaylight.yangtools.yang.binding,
</Import-Package>
</instructions>
</configuration>
package org.opendaylight.controller.netconf.impl;
-import com.google.common.base.Preconditions;
import io.netty.channel.Channel;
+
+import java.text.SimpleDateFormat;
+import java.util.Date;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+
import org.opendaylight.controller.netconf.api.NetconfSession;
import org.opendaylight.controller.netconf.api.monitoring.NetconfManagementSession;
import org.opendaylight.protocol.framework.SessionListener;
import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev100924.DomainName;
import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev100924.Host;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.netconf.monitoring.extension.rev131210.NetconfTcp;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.netconf.monitoring.extension.rev131210.Session1;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.netconf.monitoring.extension.rev131210.Session1Builder;
import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.netconf.monitoring.rev101004.NetconfSsh;
import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.netconf.monitoring.rev101004.Transport;
import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.netconf.monitoring.rev101004.netconf.state.sessions.Session;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
-import java.text.SimpleDateFormat;
-import java.util.Date;
-import java.util.regex.Matcher;
-import java.util.regex.Pattern;
+import com.google.common.base.Preconditions;
public class NetconfServerSession extends NetconfSession implements NetconfManagementSession {
builder.setOutNotifications(new ZeroBasedCounter32(0L));
builder.setKey(new SessionKey(getSessionId()));
+
+ Session1Builder builder1 = new Session1Builder();
+ builder1.setSessionIdentifier(header.getSessionType());
+ builder.addAugmentation(Session1.class, builder1.build());
+
return builder.build();
}
private Class<? extends Transport> getTransportForString(String transport) {
switch(transport) {
case "ssh" : return NetconfSsh.class;
- // TODO what about tcp
- case "tcp" : return NetconfSsh.class;
+ case "tcp" : return NetconfTcp.class;
default: throw new IllegalArgumentException("Unknown transport type " + transport);
}
}
package org.opendaylight.controller.netconf.impl;
-import com.google.common.base.Optional;
-import com.google.common.base.Preconditions;
import io.netty.channel.Channel;
import io.netty.util.Timer;
import io.netty.util.concurrent.Promise;
+
+import java.net.InetSocketAddress;
+
import org.opendaylight.controller.netconf.api.NetconfMessage;
import org.opendaylight.controller.netconf.api.NetconfServerSessionPreferences;
+import org.opendaylight.controller.netconf.impl.util.AdditionalHeaderUtil;
import org.opendaylight.controller.netconf.util.AbstractNetconfSessionNegotiator;
import org.opendaylight.protocol.framework.SessionListener;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
-import java.util.regex.Matcher;
-import java.util.regex.Pattern;
+import com.google.common.base.Optional;
public class NetconfServerSessionNegotiator extends
AbstractNetconfSessionNegotiator<NetconfServerSessionPreferences, NetconfServerSession> {
static final Logger logger = LoggerFactory.getLogger(NetconfServerSessionNegotiator.class);
- private static final AdditionalHeader DEFAULT_HEADER = new AdditionalHeader();
-
protected NetconfServerSessionNegotiator(NetconfServerSessionPreferences sessionPreferences,
Promise<NetconfServerSession> promise, Channel channel, Timer timer, SessionListener sessionListener) {
super(sessionPreferences, promise, channel, timer, sessionListener);
AdditionalHeader parsedHeader;
if (additionalHeader.isPresent()) {
- parsedHeader = new AdditionalHeader(additionalHeader.get());
+ parsedHeader = AdditionalHeaderUtil.fromString(additionalHeader.get());
} else {
- parsedHeader = DEFAULT_HEADER;
+ parsedHeader = new AdditionalHeader("unknown", ((InetSocketAddress)channel.localAddress()).getHostString(),
+ "tcp", "client");
}
logger.debug("Additional header from hello parsed as {} from {}", parsedHeader, additionalHeader);
return new NetconfServerSession(sessionListener, channel, sessionPreferences.getSessionId(), parsedHeader);
}
- static class AdditionalHeader {
+ public static class AdditionalHeader {
- private static final Pattern pattern = Pattern
- .compile("\\[(?<username>[^;]+);(?<address>[0-9\\.]+)[:/](?<port>[0-9]+);(?<transport>[a-z]+)[^\\]]+\\]");
private final String username;
private final String address;
private final String transport;
+ private final String sessionIdentifier;
- public AdditionalHeader(String addHeaderAsString) {
- addHeaderAsString = addHeaderAsString.trim();
- Matcher matcher = pattern.matcher(addHeaderAsString);
- Preconditions.checkArgument(matcher.matches(), "Additional header in wrong format %s, expected %s",
- addHeaderAsString, pattern);
- this.username = matcher.group("username");
- this.address = matcher.group("address");
- this.transport = matcher.group("transport");
- }
-
- private AdditionalHeader() {
- this.username = this.address = "unknown";
- this.transport = "ssh";
+ public AdditionalHeader(String userName, String hostAddress, String transport, String sessionIdentifier) {
+ this.address = hostAddress;
+ this.username = userName;
+ this.transport = transport;
+ this.sessionIdentifier = sessionIdentifier;
}
String getUsername() {
return transport;
}
+ String getSessionType() {
+ return sessionIdentifier;
+ }
+
@Override
public String toString() {
final StringBuffer sb = new StringBuffer("AdditionalHeader{");
return sb.toString();
}
}
+
}
--- /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.impl.util;
+
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+
+import org.opendaylight.controller.netconf.impl.NetconfServerSessionNegotiator.AdditionalHeader;
+
+import com.google.common.base.Preconditions;
+
+public class AdditionalHeaderUtil {
+
+ private static final Pattern pattern = Pattern
+ .compile("\\[(?<username>[^;]+);(?<address>[0-9\\.]+)[:/](?<port>[0-9]+);(?<transport>[a-z]+)[^\\]]+\\]");
+ private static final Pattern customHeaderPattern = Pattern
+ .compile("\\[(?<username>[^;]+);(?<address>[0-9\\.]+)[:/](?<port>[0-9]+);(?<transport>[a-z]+);(?<sessionIdentifier>[a-z]+)[^\\]]+\\]");
+
+ public static AdditionalHeader fromString(String additionalHeader) {
+ additionalHeader = additionalHeader.trim();
+ Matcher matcher = pattern.matcher(additionalHeader);
+ Matcher matcher2 = customHeaderPattern.matcher(additionalHeader);
+ Preconditions.checkArgument(matcher.matches(), "Additional header in wrong format %s, expected %s",
+ additionalHeader, pattern);
+ String username = matcher.group("username");
+ String address = matcher.group("address");
+ String transport = matcher.group("transport");
+ String sessionIdentifier = "client";
+ if (matcher2.matches()) {
+ sessionIdentifier = matcher2.group("sessionIdentifier");
+ }
+ return new AdditionalHeader(username, address, transport, sessionIdentifier);
+ }
+
+}
package org.opendaylight.controller.netconf.impl;
import junit.framework.Assert;
+
import org.junit.Test;
+import org.opendaylight.controller.netconf.impl.util.AdditionalHeaderUtil;
public class AdditionalHeaderParserTest {
@Test
public void testParsing() throws Exception {
String s = "[netconf;10.12.0.102:48528;ssh;;;;;;]";
- NetconfServerSessionNegotiator.AdditionalHeader header = new NetconfServerSessionNegotiator.AdditionalHeader(s);
+ NetconfServerSessionNegotiator.AdditionalHeader header = AdditionalHeaderUtil.fromString(s);
Assert.assertEquals("netconf", header.getUsername());
Assert.assertEquals("10.12.0.102", header.getAddress());
Assert.assertEquals("ssh", header.getTransport());
@Test
public void testParsing2() throws Exception {
String s = "[tomas;10.0.0.0/10000;tcp;1000;1000;;/home/tomas;;]";
- NetconfServerSessionNegotiator.AdditionalHeader header = new NetconfServerSessionNegotiator.AdditionalHeader(s);
+ NetconfServerSessionNegotiator.AdditionalHeader header = AdditionalHeaderUtil.fromString(s);
Assert.assertEquals("tomas", header.getUsername());
Assert.assertEquals("10.0.0.0", header.getAddress());
Assert.assertEquals("tcp", header.getTransport());
@Test(expected = IllegalArgumentException.class)
public void testParsingNoUsername() throws Exception {
String s = "[10.12.0.102:48528;ssh;;;;;;]";
- new NetconfServerSessionNegotiator.AdditionalHeader(s);
+ AdditionalHeaderUtil.fromString(s);
}
}
package org.opendaylight.controller.netconf.impl;
-import com.google.common.base.Optional;
-import com.google.common.collect.Sets;
+import static com.google.common.base.Preconditions.checkNotNull;
+import static org.junit.Assert.fail;
+import static org.mockito.Matchers.any;
+import static org.mockito.Mockito.doNothing;
+import static org.mockito.Mockito.doReturn;
+import static org.mockito.Mockito.mock;
import io.netty.channel.ChannelFuture;
import io.netty.channel.EventLoopGroup;
import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.util.HashedWheelTimer;
+
+import java.io.DataOutputStream;
+import java.io.InputStream;
+import java.io.InputStreamReader;
+import java.lang.management.ManagementFactory;
+import java.net.InetSocketAddress;
+import java.net.Socket;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.List;
+import java.util.Set;
+import java.util.concurrent.TimeUnit;
+
+import javax.management.ObjectName;
+
import org.apache.commons.io.IOUtils;
import org.junit.After;
import org.junit.AfterClass;
import org.slf4j.LoggerFactory;
import org.w3c.dom.Document;
-import javax.management.ObjectName;
-import java.io.DataOutputStream;
-import java.io.InputStream;
-import java.io.InputStreamReader;
-import java.lang.management.ManagementFactory;
-import java.net.InetSocketAddress;
-import java.net.Socket;
-import java.util.ArrayList;
-import java.util.Collections;
-import java.util.List;
-import java.util.Set;
-import java.util.concurrent.TimeUnit;
-
-import static com.google.common.base.Preconditions.checkNotNull;
-import static org.junit.Assert.fail;
-import static org.mockito.Matchers.any;
-import static org.mockito.Mockito.doNothing;
-import static org.mockito.Mockito.doReturn;
-import static org.mockito.Mockito.mock;
+import com.google.common.base.Optional;
+import com.google.common.collect.Sets;
public class ConcurrentClientsTest {
private static final int CONCURRENCY = 16;
private static EventLoopGroup nettyGroup = new NioEventLoopGroup();
- public static final NetconfClientDispatcher NETCONF_CLIENT_DISPATCHER = new NetconfClientDispatcher( nettyGroup, nettyGroup);
+ public static final NetconfClientDispatcher NETCONF_CLIENT_DISPATCHER =
+ new NetconfClientDispatcher( nettyGroup, nettyGroup);
@Mock
private YangStoreService yangStoreService;
<artifactId>netconf-ssh</artifactId>
<scope>test</scope>
</dependency>
+ <dependency>
+ <groupId>${project.groupId}</groupId>
+ <artifactId>netconf-ssh</artifactId>
+ <scope>test</scope>
+ <type>test-jar</type>
+ </dependency>
<dependency>
<groupId>${project.groupId}</groupId>
<artifactId>netconf-util</artifactId>
package org.opendaylight.controller.netconf.it;
-import static java.util.Collections.emptyList;
-import static junit.framework.Assert.assertEquals;
-import static junit.framework.Assert.assertNotNull;
-import static junit.framework.Assert.assertTrue;
-import static org.mockito.Matchers.anyLong;
-import static org.mockito.Mockito.doReturn;
-import static org.mockito.Mockito.mock;
+import ch.ethz.ssh2.Connection;
+import ch.ethz.ssh2.Session;
+import com.google.common.collect.Lists;
+import com.google.common.collect.Sets;
import io.netty.channel.ChannelFuture;
import io.netty.channel.EventLoopGroup;
import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.util.HashedWheelTimer;
-
import java.io.IOException;
import java.io.InputStream;
import java.lang.management.ManagementFactory;
import java.util.List;
import java.util.Set;
import java.util.concurrent.TimeUnit;
-
import javax.management.ObjectName;
import javax.xml.parsers.ParserConfigurationException;
-
import junit.framework.Assert;
-
import org.junit.After;
import org.junit.Before;
import org.junit.Ignore;
import org.opendaylight.controller.config.yang.test.impl.NetconfTestImplModuleFactory;
import org.opendaylight.controller.config.yang.test.impl.NetconfTestImplModuleMXBean;
import org.opendaylight.controller.config.yang.test.impl.TestImplModuleFactory;
+import org.opendaylight.controller.netconf.StubUserManager;
import org.opendaylight.controller.netconf.api.NetconfMessage;
import org.opendaylight.controller.netconf.client.NetconfClient;
import org.opendaylight.controller.netconf.client.NetconfClientDispatcher;
import org.opendaylight.controller.netconf.impl.osgi.NetconfOperationServiceSnapshot;
import org.opendaylight.controller.netconf.mapping.api.NetconfOperationService;
import org.opendaylight.controller.netconf.ssh.NetconfSSHServer;
+import org.opendaylight.controller.netconf.ssh.authentication.AuthProvider;
import org.opendaylight.controller.netconf.util.test.XmlFileLoader;
import org.opendaylight.controller.netconf.util.xml.ExiParameters;
import org.opendaylight.controller.netconf.util.xml.XmlElement;
import org.w3c.dom.NamedNodeMap;
import org.w3c.dom.Node;
import org.xml.sax.SAXException;
-
-import ch.ethz.ssh2.Connection;
-import ch.ethz.ssh2.Session;
-
-import com.google.common.collect.Lists;
-import com.google.common.collect.Sets;
+import static java.util.Collections.emptyList;
+import static junit.framework.Assert.assertEquals;
+import static junit.framework.Assert.assertNotNull;
+import static junit.framework.Assert.assertTrue;
+import static org.mockito.Matchers.anyLong;
+import static org.mockito.Mockito.doReturn;
+import static org.mockito.Mockito.mock;
public class NetconfITTest extends AbstractConfigTest {
private void startSSHServer() throws Exception{
logger.info("Creating SSH server");
- Thread sshServerThread = new Thread(NetconfSSHServer.start(10830,tcpAddress));
+ StubUserManager um = new StubUserManager(USERNAME,PASSWORD);
+ AuthProvider ap = new AuthProvider(um);
+ Thread sshServerThread = new Thread(NetconfSSHServer.start(10830,tcpAddress,ap));
sshServerThread.setDaemon(true);
sshServerThread.start();
logger.info("SSH server on");
*/
package org.opendaylight.controller.netconf.it;
-import com.google.common.base.Charsets;
-import com.google.common.base.Optional;
-import com.google.common.collect.Sets;
+import static org.mockito.Matchers.anyLong;
+import static org.mockito.Mockito.doReturn;
+import static org.mockito.Mockito.mock;
import io.netty.channel.ChannelFuture;
import io.netty.channel.EventLoopGroup;
import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.util.HashedWheelTimer;
+
+import java.io.BufferedReader;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.InputStreamReader;
+import java.net.InetSocketAddress;
+import java.net.Socket;
+import java.util.Collection;
+import java.util.List;
+import java.util.Set;
+import java.util.concurrent.TimeUnit;
+
import junit.framework.Assert;
+
import org.junit.Before;
import org.junit.Test;
import org.junit.matchers.JUnitMatchers;
import org.slf4j.LoggerFactory;
import org.w3c.dom.Document;
-import java.io.BufferedReader;
-import java.io.IOException;
-import java.io.InputStream;
-import java.io.InputStreamReader;
-import java.net.InetSocketAddress;
-import java.net.Socket;
-import java.util.Collection;
-import java.util.List;
-import java.util.Set;
-import java.util.concurrent.TimeUnit;
-
-import static org.mockito.Matchers.anyLong;
-import static org.mockito.Mockito.doReturn;
-import static org.mockito.Mockito.mock;
+import com.google.common.base.Charsets;
+import com.google.common.base.Optional;
+import com.google.common.collect.Sets;
public class NetconfMonitoringITTest extends AbstractConfigTest {
org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev100924,
org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.yang.types.rev100924,
org.osgi.util.tracker,
+ org.opendaylight.yangtools.yang.common,
org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.netconf.monitoring.rev101004.netconf.state,
org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.netconf.monitoring.rev101004.netconf.state.sessions,
org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.netconf.monitoring.rev101004,
org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.netconf.monitoring.rev101004.netconf.state.schemas,
+ org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.netconf.monitoring.extension.rev131210,
+ org.opendaylight.yangtools.yang.binding,
</Import-Package>
</instructions>
</configuration>
*/
package org.opendaylight.controller.netconf.monitoring.xml.model;
-import com.google.common.base.Preconditions;
-import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.netconf.monitoring.rev101004.NetconfSsh;
-import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.netconf.monitoring.rev101004.netconf.state.sessions.Session;
-
import javax.xml.bind.annotation.XmlElement;
import javax.xml.bind.annotation.XmlTransient;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.netconf.monitoring.extension.rev131210.Session1;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.netconf.monitoring.rev101004.netconf.state.sessions.Session;
+import org.opendaylight.yangtools.yang.common.QName;
+
final class MonitoringSession {
@XmlTransient
@XmlElement(name = "transport")
public String getTransport() {
- Preconditions.checkState(managementSession.getTransport() == NetconfSsh.class);
- return "netconf-ssh";
+ try {
+ QName qName = (QName) managementSession.getTransport().getField("QNAME").get(null);
+ return qName.getLocalName();
+ } catch (NoSuchFieldException | SecurityException | IllegalArgumentException | IllegalAccessException e) {
+ throw new IllegalArgumentException("Unknown transport type " + managementSession.getTransport(), e);
+ }
+ }
+
+ @XmlElement(name= "session-identifier")
+ public String getSessionType() {
+ return managementSession.getAugmentation(Session1.class).getSessionIdentifier();
}
@XmlElement(name = "username")
*/
package org.opendaylight.controller.netconf.monitoring.xml;
-import com.google.common.collect.Lists;
+import static org.mockito.Mockito.doReturn;
+import static org.mockito.Mockito.mock;
+
+import java.util.Date;
+
import org.junit.Test;
import org.opendaylight.controller.netconf.api.monitoring.NetconfMonitoringService;
import org.opendaylight.controller.netconf.monitoring.xml.model.NetconfState;
import org.opendaylight.controller.netconf.util.xml.XmlUtil;
import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev100924.DomainName;
import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev100924.Host;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.netconf.monitoring.extension.rev131210.Session1;
import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.netconf.monitoring.rev101004.NetconfSsh;
import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.netconf.monitoring.rev101004.netconf.state.Schemas;
import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.netconf.monitoring.rev101004.netconf.state.SchemasBuilder;
import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.yang.types.rev100924.ZeroBasedCounter32;
import org.w3c.dom.Element;
-import java.util.Date;
-
-import static org.mockito.Mockito.doReturn;
-import static org.mockito.Mockito.mock;
+import com.google.common.collect.Lists;
public class JaxBSerializerTest {
private Session getMockSession() {
Session mocked = mock(Session.class);
+ Session1 mockedSession1 = mock(Session1.class);
+ doReturn("client").when(mockedSession1).getSessionIdentifier();
doReturn(1L).when(mocked).getSessionId();
doReturn(new DateAndTime(new Date().toString())).when(mocked).getLoginTime();
doReturn(new Host(new DomainName("address/port"))).when(mocked).getSourceHost();
doReturn(new ZeroBasedCounter32(0L)).when(mocked).getOutRpcErrors();
doReturn(NetconfSsh.class).when(mocked).getTransport();
doReturn("username").when(mocked).getUsername();
+ doReturn(mockedSession1).when(mocked).getAugmentation(Session1.class);
return mocked;
}
}
<groupId>commons-io</groupId>
<artifactId>commons-io</artifactId>
</dependency>
+ <dependency>
+ <groupId>org.opendaylight.controller</groupId>
+ <artifactId>usermanager</artifactId>
+ <version>0.4.1-SNAPSHOT</version>
+ </dependency>
</dependencies>
<build>
<plugins>
+ <plugin>
+ <groupId>org.apache.maven.plugins</groupId>
+ <artifactId>maven-jar-plugin</artifactId>
+ <version>2.4</version>
+ <executions>
+ <execution>
+ <phase>package</phase>
+ <goals>
+ <goal>test-jar</goal>
+ </goals>
+ </execution>
+ </executions>
+ </plugin>
<plugin>
<groupId>org.apache.felix</groupId>
<artifactId>maven-bundle-plugin</artifactId>
org.apache.commons.io,
org.opendaylight.controller.netconf.util,
org.opendaylight.controller.netconf.util.osgi,
+ org.opendaylight.controller.usermanager,
+ org.opendaylight.controller.sal.authorization,
+ org.opendaylight.controller.sal.utils,
org.opendaylight.protocol.framework,
org.osgi.framework,
- org.slf4j
+ org.osgi.util.tracker,
+ org.slf4j,
</Import-Package>
</instructions>
</configuration>
import com.google.common.base.Optional;
import java.net.InetSocketAddress;
import org.opendaylight.controller.netconf.ssh.NetconfSSHServer;
+import org.opendaylight.controller.netconf.ssh.authentication.AuthProvider;
import org.opendaylight.controller.netconf.util.osgi.NetconfConfigUtil;
+import org.opendaylight.controller.usermanager.IUserManager;
import org.osgi.framework.BundleActivator;
import org.osgi.framework.BundleContext;
+import org.osgi.framework.ServiceReference;
+import org.osgi.util.tracker.ServiceTracker;
+import org.osgi.util.tracker.ServiceTrackerCustomizer;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
private NetconfSSHServer server;
private static final Logger logger = LoggerFactory.getLogger(NetconfSSHActivator.class);
private static final String EXCEPTION_MESSAGE = "Netconf ssh bridge is not available.";
+ private IUserManager iUserManager;
+ private BundleContext context = null;
+
+ ServiceTrackerCustomizer<IUserManager, IUserManager> customizer = new ServiceTrackerCustomizer<IUserManager, IUserManager>(){
+ @Override
+ public IUserManager addingService(ServiceReference<IUserManager> reference) {
+ logger.info("Service IUserManager added, let there be SSH bridge.");
+ iUserManager = context.getService(reference);
+ try {
+ onUserManagerFound(iUserManager);
+ } catch (Exception e) {
+ logger.trace("Can't start SSH server due to {}",e);
+ }
+ return iUserManager;
+ }
+ @Override
+ public void modifiedService(ServiceReference<IUserManager> reference, IUserManager service) {
+ logger.info("Replacing modified service IUserManager in netconf SSH.");
+ server.addUserManagerService(service);
+ }
+ @Override
+ public void removedService(ServiceReference<IUserManager> reference, IUserManager service) {
+ logger.info("Removing service IUserManager from netconf SSH. " +
+ "SSH won't authenticate users until IUserManeger service will be started.");
+ removeUserManagerService();
+ }
+ };
+
@Override
public void start(BundleContext context) throws Exception {
+ this.context = context;
+ listenForManagerService();
+ }
+ @Override
+ public void stop(BundleContext context) throws Exception {
+ if (server != null){
+ server.stop();
+ logger.trace("Netconf SSH bridge is down ...");
+ }
+ }
+ private void startSSHServer() throws Exception {
logger.trace("Starting netconf SSH bridge.");
-
- Optional<InetSocketAddress> sshSocketAddressOptional = NetconfConfigUtil.extractSSHNetconfAddress(context,EXCEPTION_MESSAGE);
+ Optional<InetSocketAddress> sshSocketAddressOptional = NetconfConfigUtil.extractSSHNetconfAddress(context, EXCEPTION_MESSAGE);
InetSocketAddress tcpSocketAddress = NetconfConfigUtil.extractTCPNetconfAddress(context,
EXCEPTION_MESSAGE, true);
if (sshSocketAddressOptional.isPresent()){
- server = NetconfSSHServer.start(sshSocketAddressOptional.get().getPort(),tcpSocketAddress);
+ AuthProvider authProvider = new AuthProvider(iUserManager);
+ this.server = NetconfSSHServer.start(sshSocketAddressOptional.get().getPort(),tcpSocketAddress,authProvider);
Thread serverThread = new Thread(server,"netconf SSH server thread");
serverThread.setDaemon(true);
serverThread.start();
throw new Exception("No valid connection configuration for SSH bridge found.");
}
}
-
- @Override
- public void stop(BundleContext context) throws Exception {
- if (server != null){
- logger.trace("Netconf SSH bridge going down ...");
- server.stop();
- logger.trace("Netconf SSH bridge is down ...");
+ private void onUserManagerFound(IUserManager userManager) throws Exception{
+ if (server!=null && server.isUp()){
+ server.addUserManagerService(userManager);
+ } else {
+ startSSHServer();
}
}
+ private void removeUserManagerService(){
+ this.server.removeUserManagerService();
+ }
+ private void listenForManagerService(){
+ ServiceTracker<IUserManager, IUserManager> listenerTracker = new ServiceTracker<>(context, IUserManager.class,customizer);
+ listenerTracker.open();
+ }
}
import java.net.ServerSocket;
import java.util.concurrent.atomic.AtomicLong;
import javax.annotation.concurrent.ThreadSafe;
+import org.opendaylight.controller.netconf.ssh.authentication.AuthProvider;
import org.opendaylight.controller.netconf.ssh.threads.SocketThread;
+import org.opendaylight.controller.usermanager.IUserManager;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@ThreadSafe
public class NetconfSSHServer implements Runnable {
- private static boolean acceptMore = true;
private ServerSocket ss = null;
private static final Logger logger = LoggerFactory.getLogger(NetconfSSHServer.class);
private static final AtomicLong sesssionId = new AtomicLong();
private final InetSocketAddress clientAddress;
+ private final AuthProvider authProvider;
+ private boolean up = false;
- private NetconfSSHServer(int serverPort,InetSocketAddress clientAddress) throws Exception{
+ private NetconfSSHServer(int serverPort,InetSocketAddress clientAddress, AuthProvider authProvider) throws Exception{
logger.trace("Creating SSH server socket on port {}",serverPort);
this.ss = new ServerSocket(serverPort);
}
logger.trace("Server socket created.");
this.clientAddress = clientAddress;
-
+ this.authProvider = authProvider;
+ this.up = true;
}
-
- public static NetconfSSHServer start(int serverPort, InetSocketAddress clientAddress) throws Exception {
- return new NetconfSSHServer(serverPort, clientAddress);
+ public static NetconfSSHServer start(int serverPort, InetSocketAddress clientAddress,AuthProvider authProvider) throws Exception {
+ return new NetconfSSHServer(serverPort, clientAddress,authProvider);
}
public void stop() throws Exception {
- acceptMore = false;
+ up = false;
logger.trace("Closing SSH server socket.");
ss.close();
logger.trace("SSH server socket closed.");
}
+ public void removeUserManagerService(){
+ this.authProvider.removeUserManagerService();
+ }
+
+ public void addUserManagerService(IUserManager userManagerService){
+ this.authProvider.addUserManagerService(userManagerService);
+ }
+ public boolean isUp(){
+ return this.up;
+ }
@Override
public void run() {
- while (acceptMore) {
+ while (up) {
logger.trace("Starting new socket thread.");
try {
- SocketThread.start(ss.accept(), clientAddress, sesssionId.incrementAndGet());
+ SocketThread.start(ss.accept(), clientAddress, sesssionId.incrementAndGet(),authProvider);
} catch (IOException e) {
e.printStackTrace(); //To change body of catch statement use File | Settings | File Templates.
}
--- /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.ssh.authentication;
+
+import ch.ethz.ssh2.signature.RSAPrivateKey;
+import java.io.IOException;
+import java.io.InputStream;
+import java.util.ArrayList;
+import java.util.List;
+import org.apache.commons.io.IOUtils;
+import org.opendaylight.controller.sal.authorization.AuthResultEnum;
+import org.opendaylight.controller.sal.authorization.UserLevel;
+import org.opendaylight.controller.usermanager.IUserManager;
+import org.opendaylight.controller.usermanager.UserConfig;
+
+public class AuthProvider implements AuthProviderInterface {
+
+ private static RSAPrivateKey hostkey = null;
+ private static IUserManager um;
+ private static final String DEAFULT_USER = "netconf";
+ private static final String DEAFULT_PASSWORD = "netconf";
+
+
+ public AuthProvider(IUserManager ium) throws Exception {
+
+ this.um = ium;
+
+ if (this.um == null){
+ throw new Exception("No usermanager service available.");
+ }
+
+ List<String> roles = new ArrayList<String>(1);
+ roles.add(UserLevel.SYSTEMADMIN.toString());
+ this.um.addLocalUser(new UserConfig(DEAFULT_USER, DEAFULT_PASSWORD, roles));
+ }
+ @Override
+ public boolean authenticated(String username, String password) throws Exception {
+ if (this.um == null){
+ throw new Exception("No usermanager service available.");
+ }
+ AuthResultEnum authResult = this.um.authenticate(username,password);
+ if (authResult.equals(AuthResultEnum.AUTH_ACCEPT) || authResult.equals(AuthResultEnum.AUTH_ACCEPT_LOC)){
+ return true;
+ }
+ return false;
+ }
+
+ @Override
+ public char[] getPEMAsCharArray() {
+
+ InputStream is = getClass().getResourceAsStream("/RSA.pk");
+ try {
+ return IOUtils.toCharArray(is);
+ } catch (IOException e) {
+ e.printStackTrace();
+ }
+ return null;
+ }
+
+ @Override
+ public void removeUserManagerService() {
+ this.um = null;
+ }
+
+ @Override
+ public void addUserManagerService(IUserManager userManagerService) {
+ this.um = userManagerService;
+ }
+
+
+}
--- /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.ssh.authentication;
+
+import org.opendaylight.controller.usermanager.IUserManager;
+
+public interface AuthProviderInterface {
+
+ public boolean authenticated(String username, String password) throws Exception;
+ public char[] getPEMAsCharArray();
+ public void removeUserManagerService();
+ public void addUserManagerService(IUserManager userManagerService);
+}
+++ /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.ssh.authentication;
-
-import ch.ethz.ssh2.signature.RSAPrivateKey;
-
-import java.math.BigInteger;
-
-public class RSAKey implements KeyStoreHandler {
-
- private static RSAPrivateKey hostkey = null;
- private static String user = "netconf";
- private static String password = "netconf";
- static {
-
- BigInteger p = new BigInteger("2967886344240998436887630478678331145236162666668503940430852241825039192450179076148979094256007292741704260675085192441025058193581327559331546948442042987131728039318861235625879376246169858586459472691398815098207618446039"); //.BigInteger.probablePrime(N / 2, rnd);
- BigInteger q = new BigInteger("4311534819291430017572425052029278681302539382618633848168923130451247487970187151403375389974616614405320169278870943605377518341666894603659873284783174749122655429409273983428000534304828056597676444751611433784228298909767"); //BigInteger.probablePrime(N / 2, rnd);
- BigInteger phi = (p.subtract(BigInteger.ONE)).multiply(q.subtract(BigInteger.ONE));
-
- BigInteger n = p.multiply(q);
- BigInteger e = new BigInteger("65537");
- BigInteger d = e.modInverse(phi);
-
- hostkey = new RSAPrivateKey(d, e, n);
- }
-
- @Override
- public RSAPrivateKey getPrivateKey() {
- return hostkey;
- }
-}
import java.net.InetSocketAddress;
import java.net.Socket;
import javax.annotation.concurrent.ThreadSafe;
-import org.opendaylight.controller.netconf.ssh.authentication.RSAKey;
+import org.opendaylight.controller.netconf.ssh.authentication.AuthProvider;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
private long sessionId;
private String currentUser;
private final String remoteAddressWithPort;
+ private final AuthProvider authProvider;
- public static void start(Socket socket, InetSocketAddress clientAddress, long sessionId) throws IOException{
- Thread netconf_ssh_socket_thread = new Thread(new SocketThread(socket,clientAddress,sessionId));
+ public static void start(Socket socket,
+ InetSocketAddress clientAddress,
+ long sessionId,
+ AuthProvider authProvider) throws IOException{
+ Thread netconf_ssh_socket_thread = new Thread(new SocketThread(socket,clientAddress,sessionId,authProvider));
netconf_ssh_socket_thread.setDaemon(true);
netconf_ssh_socket_thread.start();
}
- private SocketThread(Socket socket, InetSocketAddress clientAddress, long sessionId) throws IOException {
+ private SocketThread(Socket socket,
+ InetSocketAddress clientAddress,
+ long sessionId,
+ AuthProvider authProvider) throws IOException {
this.socket = socket;
this.clientAddress = clientAddress;
this.sessionId = sessionId;
this.remoteAddressWithPort = socket.getRemoteSocketAddress().toString().replaceFirst("/","");
+ this.authProvider = authProvider;
}
@Override
public void run() {
conn = new ServerConnection(socket);
- RSAKey keyStore = new RSAKey();
- conn.setRsaHostKey(keyStore.getPrivateKey());
+ try {
+ conn.setPEMHostKey(authProvider.getPEMAsCharArray(),"netconf");
+ } catch (IOException e) {
+ e.printStackTrace();
+ }
conn.setAuthenticationCallback(this);
conn.setServerConnectionCallback(this);
try {
netconf_ssh_output.start();
} catch (Throwable t){
- logger.error(t.getMessage(),t);
+ logger.error("SSH bridge couldn't create echo socket",t.getMessage(),t);
try {
if (netconf_ssh_input!=null){
public AuthenticationResult authenticateWithPassword(ServerConnection sc, String username, String password)
{
- if (USER.equals(username) && PASSWORD.equals(password)){
- currentUser = username;
- logger.trace("user {}@{} authenticated",currentUser,remoteAddressWithPort);
- return AuthenticationResult.SUCCESS;
- }
-
+ try {
+ if (authProvider.authenticated(username,password)){
+ currentUser = username;
+ logger.trace("user {}@{} authenticated",currentUser,remoteAddressWithPort);
+ return AuthenticationResult.SUCCESS;
+ }
+ } catch (Exception e){
+ logger.info("Authentication failed due to :" + e.getLocalizedMessage());
+ }
return AuthenticationResult.FAILURE;
}
--- /dev/null
+-----BEGIN RSA PRIVATE KEY-----
+MIIEogIBAAKCAQEAuC9hbEacpewvylI0mwFwjy3Wou2hpr/ncN9BBiFDSaG5yW2k
+3Oy+SCAcFCL+ZKWb6cc6Ch4gUeCwyEHRojZguuhliKtak9YQf6qbvpPLe00842Lx
+iqNAGurMpzizCDsGFq8ChaAkBZQI3TvcHuPoSUWSMJ+K8xHpRyUdVr6g2yEjezKJ
+sTXBtWaeCCh6YUafFujuDJk7fvYcPW7Je5KRBBStIKvxcMW0zB+7eq04deTHwGbJ
+gGjKWilQ72hsDDP3Hbp5CJMAYg1r4GlCmFx3KyHRGztgWgNgaD7nNpKCkTLjtmA6
+b4x7TA+jrzZ6Af2z5TMrI4dv5w1SrxHaZ+ziLQIDAQABAoIBAHTndeGgq/rQf8De
+Do+4CTaHtK0zQSAyu/azbXUzlZ7drKuCEVs8VMY4wzmwwGEnkF+A2YDkgEUX5X0l
+8aYQ97KKoS9u+43MGCrAIhyDeGrpqlT1TzRcy+qJz53v6gq2U/X/3QztiQ+VV078
+mIluxNgE9XYxPaNsYfGLSCTv1+9c8y/hjGVX2kwFK+u4ut0ZZETggNa8UxfaHVDS
+fIJQX9Gm3J3GSUV30fDGMBIUW6ESLc2L8b7u8Mp9TRP39ZeQSuEUjBe8MYKv0Rel
+oEpjZvcnniMTpFbLpndBYn7/AoIiEBvtCN8faVTuRRcvvLcsRm09IctzKQYnMh6M
+6PLKV+ECgYEA8HFRYaKHUzxpzE/fyon82GQbzqFFY0/bbWrfWICMfNbIgshJUie6
+FmH5iUFMfeqaT7v557HFM0GB9FeIeSbvd88YmiBAcRopZ3DfMkDH+DT73yJ+/TKG
+2nrQtdhyuTIs4bwHqeS2BBJYs7PK9R2rratF3l34Tf7mjlvyOgygHdUCgYEAxBo2
+8hEBlAVNcNb1hTYUxe1w1B6675/mFlmw98Xmj9dRYfICXNhahs8tX3/lsBEd+vBu
+fI0oyHaff8m5bPgGzD1ZMybfeROujNrgxaKVk7Ef0FDRRCop4bm18OroFlFAt9l8
+wMp++ToACbdvQvL/mjWMPYlIxhB/YxHswICZZvkCgYAexxKYwdo6sGAGlC7cWT9x
+X5cjowcjyEQZRHXkeUgCbufpvcOM7aLnXJE5nY8yCwbHsBM0MlBA2GDPKylAANjk
+aDEJAZneIHAuWodngl1Wi0m2bU7+ECqs6s2uiU9eH2sZVh1RBQK7kLGkBx6ys6KX
+L3ZZGYRAT6GplWFzRsx0JQKBgCeVlxPD5QqpC1nEumi6YvUVGdpnnZpzL3HBhxxs
+wT612wKnZFyze4qM1X7ahVXGDsQxtkvD/sCAWW/lG13orw6ZL6FIroF1PJ3ILOkY
+CZN3hJF7TtKwpCWhZB2OfWzL2AGEkE8mUP0j/Q/5DCd6f6f0OSvOw3bfq6cm3iB5
+lP2ZAoGAXsRN5TZTX4AQ2xTlrDQ8A5XgcvyWQpJOmEXMTyHV7VaJVzmNWFVAvndK
+5UIq8ALDwB2t7vjmMUW6euvIwqtXiop7G79UOb3e3NhzeyWFGQyBLqCRznGaXQTT
+dlFy73xhukZMhFnj006bjKCYvOPnwuGl3+0fuWil5Rq3jOuY5c8=
+-----END RSA PRIVATE KEY-----
* 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.ssh;
+package org.opendaylight.controller.netconf;
import ch.ethz.ssh2.Connection;
-import ch.ethz.ssh2.Session;
-import java.io.IOException;
import java.net.InetSocketAddress;
import junit.framework.Assert;
-import org.apache.commons.io.IOUtils;
import org.junit.Test;
+import org.opendaylight.controller.netconf.ssh.NetconfSSHServer;
+import org.opendaylight.controller.netconf.ssh.authentication.AuthProvider;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
private static final int PORT = 1830;
private static final InetSocketAddress tcpAddress = new InetSocketAddress("127.0.0.1", 8383);
private static final Logger logger = LoggerFactory.getLogger(SSHServerTest.class);
+ private Thread sshServerThread;
+
+
+
-// @Before
public void startSSHServer() throws Exception{
- logger.info("Creating SSH server");
- NetconfSSHServer server = NetconfSSHServer.start(PORT,tcpAddress);
- Thread sshServerThread = new Thread(server);
- sshServerThread.setDaemon(true);
- sshServerThread.start();
- logger.info("SSH server on");
+ logger.info("Creating SSH server");
+ StubUserManager um = new StubUserManager(USER,PASSWORD);
+ AuthProvider ap = new AuthProvider(um);
+ NetconfSSHServer server = NetconfSSHServer.start(PORT,tcpAddress,ap);
+ sshServerThread = new Thread(server);
+ sshServerThread.setDaemon(true);
+ sshServerThread.start();
+ logger.info("SSH server on");
}
@Test
public void connect(){
- Connection conn = new Connection(HOST,PORT);
- Assert.assertNotNull(conn);
try {
+ this.startSSHServer();
+ Connection conn = new Connection(HOST,PORT);
+ Assert.assertNotNull(conn);
logger.info("connecting to SSH server");
conn.connect();
logger.info("authenticating ...");
boolean isAuthenticated = conn.authenticateWithPassword(USER,PASSWORD);
Assert.assertTrue(isAuthenticated);
- logger.info("opening session");
- Session sess = conn.openSession();
- logger.info("subsystem netconf");
- sess.startSubSystem("netconf");
- sess.getStdin().write("<?xml version=\"1.0\" encoding=\"UTF-8\"?><hello xmlns=\"urn:ietf:params:xml:ns:netconf:base:1.0\"><capabilities><capability>urn:ietf:params:netconf:base:1.1</capability></capabilities></hello>]]>]]>".getBytes());
- IOUtils.copy(sess.getStdout(), System.out);
- } catch (IOException e) {
- e.printStackTrace();
+ } catch (Exception e) {
+ logger.error("Error while starting SSH server.", e);
}
+
}
}
--- /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;
+
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+import org.opendaylight.controller.sal.authorization.AuthResultEnum;
+import org.opendaylight.controller.sal.authorization.UserLevel;
+import org.opendaylight.controller.sal.utils.Status;
+import org.opendaylight.controller.sal.utils.StatusCode;
+import org.opendaylight.controller.usermanager.AuthorizationConfig;
+import org.opendaylight.controller.usermanager.ISessionManager;
+import org.opendaylight.controller.usermanager.IUserManager;
+import org.opendaylight.controller.usermanager.ServerConfig;
+import org.opendaylight.controller.usermanager.UserConfig;
+import org.springframework.security.core.userdetails.UserDetails;
+import org.springframework.security.core.userdetails.UsernameNotFoundException;
+import org.springframework.security.web.context.SecurityContextRepository;
+
+public class StubUserManager implements IUserManager{
+
+
+ private static String user;
+ private static String password;
+
+ public StubUserManager(String user, String password){
+ this.user = user;
+ this.password = password;
+ }
+ @Override
+ public List<String> getUserRoles(String userName) {
+ return null;
+ }
+
+ @Override
+ public AuthResultEnum authenticate(String username, String password) {
+ if (this.user.equals(username) && this.password.equals(password)){
+ return AuthResultEnum.AUTH_ACCEPT_LOC;
+ }
+ return AuthResultEnum.AUTH_REJECT_LOC;
+ }
+
+ @Override
+ public Status addAAAServer(ServerConfig configObject) {
+ return null;
+ }
+
+ @Override
+ public Status removeAAAServer(ServerConfig configObject) {
+ return null;
+ }
+
+ @Override
+ public Status addLocalUser(UserConfig configObject) {
+ return new Status(StatusCode.SUCCESS);
+ }
+
+ @Override
+ public Status modifyLocalUser(UserConfig configObject) {
+ return null;
+ }
+
+ @Override
+ public Status removeLocalUser(UserConfig configObject) {
+ return null;
+ }
+
+ @Override
+ public Status removeLocalUser(String userName) {
+ return null;
+ }
+
+ @Override
+ public Status addAuthInfo(AuthorizationConfig AAAconf) {
+ return null;
+ }
+
+ @Override
+ public Status removeAuthInfo(AuthorizationConfig AAAconf) {
+ return null;
+ }
+
+ @Override
+ public List<AuthorizationConfig> getAuthorizationList() {
+ return null;
+ }
+
+ @Override
+ public Set<String> getAAAProviderNames() {
+ return null;
+ }
+
+ @Override
+ public Status changeLocalUserPassword(String user, String curPassword, String newPassword) {
+ return null;
+ }
+
+ @Override
+ public List<ServerConfig> getAAAServerList() {
+ return null;
+ }
+
+ @Override
+ public List<UserConfig> getLocalUserList() {
+ return null;
+ }
+
+ @Override
+ public Status saveLocalUserList() {
+ return null;
+ }
+
+ @Override
+ public Status saveAAAServerList() {
+ return null;
+ }
+
+ @Override
+ public Status saveAuthorizationList() {
+ return null;
+ }
+
+ @Override
+ public void userLogout(String username) {
+
+ }
+
+ @Override
+ public void userTimedOut(String username) {
+
+ }
+
+ @Override
+ public Map<String, List<String>> getUserLoggedIn() {
+ return null;
+ }
+
+ @Override
+ public String getAccessDate(String user) {
+ return null;
+ }
+
+ @Override
+ public UserLevel getUserLevel(String userName) {
+ return null;
+ }
+
+ @Override
+ public List<UserLevel> getUserLevels(String userName) {
+ return null;
+ }
+
+ @Override
+ public SecurityContextRepository getSecurityContextRepo() {
+ return null;
+ }
+
+ @Override
+ public ISessionManager getSessionManager() {
+ return null;
+ }
+
+ @Override
+ public boolean isRoleInUse(String role) {
+ return false;
+ }
+
+ @Override
+ public String getPassword(String username) {
+ return null;
+ }
+
+ @Override
+ public UserDetails loadUserByUsername(String s) throws UsernameNotFoundException {
+ return null;
+ }
+
+}
import com.google.common.base.Optional;
import com.google.common.base.Preconditions;
-
import io.netty.channel.Channel;
+import io.netty.channel.ChannelHandler;
+import io.netty.channel.ChannelHandlerContext;
import io.netty.handler.ssl.SslHandler;
import io.netty.util.Timeout;
import io.netty.util.Timer;
import io.netty.util.concurrent.Future;
import io.netty.util.concurrent.GenericFutureListener;
import io.netty.util.concurrent.Promise;
-
-import org.opendaylight.controller.netconf.api.NetconfSession;
import org.opendaylight.controller.netconf.api.NetconfMessage;
+import org.opendaylight.controller.netconf.api.NetconfSession;
import org.opendaylight.controller.netconf.api.NetconfSessionPreferences;
import org.opendaylight.controller.netconf.util.handler.FramingMechanismHandlerFactory;
import org.opendaylight.controller.netconf.util.handler.NetconfMessageAggregator;
// TODO what time ?
private static final long INITIAL_HOLDTIMER = 1;
+
private static final Logger logger = LoggerFactory.getLogger(AbstractNetconfSessionNegotiator.class);
+ public static final String NAME_OF_EXCEPTION_HANDLER = "lastExceptionHandler";
protected final P sessionPreferences;
private final SessionListener sessionListener;
+ private Timeout timeout;
/**
* Possible states for Finite State Machine
}
@Override
- protected void startNegotiation() throws Exception {
+ protected void startNegotiation() {
final Optional<SslHandler> sslHandler = getSslHandler(channel);
if (sslHandler.isPresent()) {
Future<Channel> future = sslHandler.get().handshakeFuture();
final NetconfMessage helloMessage = this.sessionPreferences.getHelloMessage();
logger.debug("Session negotiation started with hello message {}", XmlUtil.toString(helloMessage.getDocument()));
- sendMessage(helloMessage);
- changeState(State.OPEN_WAIT);
+ channel.pipeline().addLast(NAME_OF_EXCEPTION_HANDLER, new ChannelHandler() {
+ @Override
+ public void handlerAdded(ChannelHandlerContext ctx) throws Exception {
+ }
+
+ @Override
+ public void handlerRemoved(ChannelHandlerContext ctx) throws Exception {
+ }
+
+ @Override
+ public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception {
+ logger.warn("An exception occurred during negotiation on channel {}", channel.localAddress(), cause);
+ cancelTimeout();
+ negotiationFailed(cause);
+ changeState(State.FAILED);
+ }
+ });
- this.timer.newTimeout(new TimerTask() {
+ timeout = this.timer.newTimeout(new TimerTask() {
@Override
public void run(final Timeout timeout) throws Exception {
synchronized (this) {
"Session was not established after " + timeout);
negotiationFailed(cause);
changeState(State.FAILED);
+ } else if(channel.isOpen()) {
+ channel.pipeline().remove(NAME_OF_EXCEPTION_HANDLER);
}
}
}
}, INITIAL_HOLDTIMER, TimeUnit.MINUTES);
+
+ sendMessage(helloMessage);
+ changeState(State.OPEN_WAIT);
+ }
+
+ private void cancelTimeout() {
+ if(timeout!=null)
+ timeout.cancel();
}
private void sendMessage(NetconfMessage message) {
--- /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.util.messages;
+
+import com.google.common.base.Optional;
+import com.google.common.base.Preconditions;
+
+/**
+ * Additional header can be used with hello message to carry information about
+ * session's connection. Provided information can be reported via netconf
+ * monitoring.
+ * <pre>
+ * It has pattern "[username; host-address:port; transport; session-identifier;]"
+ * username - name of account on a remote
+ * host-address - client's IP address
+ * port - port number
+ * transport - tcp, ssh
+ * session-identifier - persister, client
+ * Session-identifier is optional, others mandatory.
+ * </pre>
+ */
+public class NetconfMessageAdditionalHeader {
+
+ private static final String SC = ";";
+
+ public static String toString(String userName, String hostAddress, String port, String transport,
+ Optional<String> sessionIdentifier) {
+ Preconditions.checkNotNull(userName);
+ Preconditions.checkNotNull(hostAddress);
+ Preconditions.checkNotNull(port);
+ Preconditions.checkNotNull(transport);
+ String identifier = sessionIdentifier.isPresent() ? sessionIdentifier.get() : "";
+ return "[" + userName + SC + hostAddress + ":" + port + SC + transport + SC + identifier + SC + "]"
+ + System.lineSeparator();
+ }
+}
package org.opendaylight.controller.netconf.util.messages;
-import com.google.common.base.Charsets;
-import com.google.common.base.Optional;
-import com.google.common.collect.Lists;
+import java.io.ByteArrayInputStream;
+import java.io.IOException;
+import java.nio.ByteBuffer;
+import java.util.Arrays;
+import java.util.List;
+
import org.opendaylight.controller.netconf.api.NetconfDeserializerException;
import org.opendaylight.controller.netconf.api.NetconfMessage;
import org.opendaylight.controller.netconf.util.xml.XmlUtil;
import org.w3c.dom.Document;
import org.xml.sax.SAXException;
-import java.io.ByteArrayInputStream;
-import java.io.IOException;
-import java.nio.ByteBuffer;
-import java.util.Arrays;
-import java.util.List;
+import com.google.common.base.Charsets;
+import com.google.common.base.Optional;
+import com.google.common.collect.Lists;
/**
* NetconfMessageFactory for (de)serializing DOM documents.
Comment comment = netconfMessage.getDocument().createComment("clientId:" + clientId.get());
netconfMessage.getDocument().appendChild(comment);
}
- final ByteBuffer msgBytes = Charsets.UTF_8.encode(xmlToString(netconfMessage.getDocument()));
+ ByteBuffer msgBytes;
+ if(netconfMessage.getAdditionalHeader().isPresent()) {
+ String header = netconfMessage.getAdditionalHeader().get();
+ logger.trace("Header of netconf message parsed \n{}", header);
+ msgBytes = Charsets.UTF_8.encode(header + xmlToString(netconfMessage.getDocument()));
+ } else {
+ msgBytes = Charsets.UTF_8.encode(xmlToString(netconfMessage.getDocument()));
+ }
String content = xmlToString(netconfMessage.getDocument());
logger.trace("Putting message \n{}", content);
<modules xmlns="urn:opendaylight:params:xml:ns:yang:controller:config">
<module>
- <name>dep</name>
+ <name>instance-from-code_dep</name>
<type xmlns:test-impl="urn:opendaylight:params:xml:ns:yang:controller:test:impl">
test-impl:impl-dep
</type>
test-impl:impl-netconf
</type>
- <name>test1</name>
+ <name>instance-from-code</name>
<sleep-factor>
2.58
</peers>
<testing-dep>
<type xmlns:prefix="urn:opendaylight:params:xml:ns:yang:controller:test">prefix:testing</type>
- <name>ref_dep</name>
+ <name>ref_dep_user</name>
</testing-dep>
<testing-deps>
<type xmlns:prefix="urn:opendaylight:params:xml:ns:yang:controller:test">prefix:testing</type>
- <name>ref_dep</name>
+ <name>ref_dep_user</name>
</testing-deps>
<testing-deps>
<type xmlns:prefix="urn:opendaylight:params:xml:ns:yang:controller:test">prefix:testing</type>
- <name>ref_dep_2</name>
+ <name>ref_dep_user_two</name>
</testing-deps>
</module>
<testing-dep>
<type xmlns:prefix="urn:opendaylight:params:xml:ns:yang:controller:test">prefix:testing</type>
- <name>ref_dep_2</name>
+ <name>ref_dep_user_two</name>
</testing-dep>
</module>
</modules>
<service>
<type xmlns:prefix="urn:opendaylight:params:xml:ns:yang:controller:test">prefix:testing</type>
<instance>
- <name>ref_dep</name>
- <provider>/modules/module[type='impl-dep'][name='dep']
+ <name>ref_dep_user</name>
+ <provider>/modules/module[type='impl-dep'][name='instance-from-code_dep']
</provider>
</instance>
<instance>
- <name>ref_dep_2</name>
+ <name>ref_dep_user_two</name>
<provider>/config/modules/module[name='impl-dep']/instance[name='dep2']
</provider>
</instance>
<instance>
- <name>ref_test1</name>
+ <name>user_to_instance_from_code</name>
<provider>
- /modules/module[type='impl-netconf'][name='test1']
+ /modules/module[type='impl-netconf'][name='instance-from-code']
</provider>
</instance>
</service>
--- /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>
+ <name>instance-from-code_dep</name>
+ <type xmlns:test-impl="urn:opendaylight:params:xml:ns:yang:controller:test:impl">
+ test-impl:impl-dep
+ </type>
+ </module>
+
+ </modules>
+
+ <services xmlns="urn:opendaylight:params:xml:ns:yang:controller:config">
+ <service>
+ <type xmlns:prefix="urn:opendaylight:params:xml:ns:yang:controller:test">prefix:testing</type>
+ <instance>
+ <name>ref_dep_user_another</name>
+ <provider>/modules/module[type='impl-dep'][name='instance-from-code_dep']
+ </provider>
+ </instance>
+ </service>
+ </services>
+ </config>
+ </edit-config>
+</rpc>
-<?xml version="1.0" encoding="UTF-8"?>
+<?xml version="1.0" encoding="UTF-8" ?>
<rpc message-id="6"
xmlns="urn:ietf:params:xml:ns:netconf:base:1.0">
<edit-config xmlns="urn:ietf:params:xml:ns:netconf:base:1.0">
</name-prefix>
</module>
</modules>
+ <services xmlns="urn:opendaylight:params:xml:ns:yang:controller:config">
+ <service>
+ <type xmlns:prefix="urn:opendaylight:params:xml:ns:yang:controller:threadpool:impl">prefix:threadfactory</type>
+ <instance>
+ <name>user_to_instance_from_code</name>
+ <provider>
+ /modules/module[type='threadfactory-naming'][name='threadfactory-naming-instance']</provider>
+ </instance>
+ </service>
+ </services>
</config>
</edit-config>
</rpc>
<config>
<modules xmlns="urn:opendaylight:params:xml:ns:yang:controller:config">
<module>
- <name>dep</name>
+ <name>instance-from-code_dep</name>
<type xmlns:test-impl="urn:opendaylight:params:xml:ns:yang:controller:test:impl">
test-impl:impl-dep
</type>
</type>
</module>
+
<module>
<type xmlns:test-impl="urn:opendaylight:params:xml:ns:yang:controller:test:impl">
test-impl:impl-netconf
<simple-int3>456</simple-int3>
<core-size>44</core-size>
</peers>
- <testing-dep>
- <type xmlns:prefix="urn:opendaylight:params:xml:ns:yang:controller:test">prefix:testing</type>
- <name>ref_dep</name>
- </testing-dep>
</module>
<module>
<type xmlns:test-impl="urn:opendaylight:params:xml:ns:yang:controller:test:impl">
test-impl:impl-netconf
</type>
<name>test2</name>
- <testing-dep>
- <type xmlns:prefix="urn:opendaylight:params:xml:ns:yang:controller:test">prefix:testing</type>
- <name>ref_dep</name>
- </testing-dep>
</module>
</modules>
+
<services xmlns="urn:opendaylight:params:xml:ns:yang:controller:config">
- <service>
- <type xmlns:prefix="urn:opendaylight:params:xml:ns:yang:controller:test">prefix:testing</type>
- <instance>
- <name>ref_dep</name>
- <provider>/modules/module[type='impl-dep'][name='dep']
- </provider>
- </instance>
- <instance>
- <name>ref_dep_2</name>
- <provider>/modules/module[type='impl-dep'][name='dep2']
- </provider>
- </instance>
- <instance>
- <name>ref_test1</name>
- <provider>
- /modules/module[type='impl-netconf'][name='test1']
- </provider>
- </instance>
- </service>
</services>
</config>
</edit-config>
<default-operation>none</default-operation>
<config>
<modules xmlns="urn:opendaylight:params:xml:ns:yang:controller:config">
+ <module xmlns:nc="urn:ietf:params:xml:ns:netconf:base:1.0"
+ nc:operation="remove">
+ <name>instance-from-code_dep</name>
+ <type xmlns:test-impl="urn:opendaylight:params:xml:ns:yang:controller:test:impl">
+ test-impl:impl-dep
+ </type>
+ </module>
+
+
<module xmlns:nc="urn:ietf:params:xml:ns:netconf:base:1.0"
nc:operation="remove">
<name>dep</name>
<type xmlns:test-impl="urn:opendaylight:params:xml:ns:yang:controller:test:impl">
test-impl:impl-netconf
</type>
- <name>test1</name>
+ <name>instance-from-code</name>
</module>
<module xmlns:nc="urn:ietf:params:xml:ns:netconf:base:1.0"
--- /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-netconf
+ </type>
+
+ <name>instance-from-code</name>
+
+ <ip xmlns="urn:opendaylight:params:xml:ns:yang:controller:test:impl">127.1.2.3</ip>
+ <union-test-attr xmlns="urn:opendaylight:params:xml:ns:yang:controller:test:impl">randomStringForUnion</union-test-attr>
+
+ </module>
+ </modules>
+
+ <services xmlns="urn:opendaylight:params:xml:ns:yang:controller:config">
+
+ </services>
+ </config>
+ </edit-config>
+</rpc>
<rpc message-id="a" a="64" xmlns="urn:ietf:params:xml:ns:netconf:base:1.0">
<no-arg xmlns="urn:opendaylight:params:xml:ns:yang:controller:test:impl">
- <context-instance>/modules/module[type='impl-netconf' and name='test1']</context-instance>
+ <context-instance>/modules/module[type='impl-netconf' and name='instance-from-code']</context-instance>
<arg1>
testarg1
</arg1>
<rpc message-id="a" a="64" xmlns="urn:ietf:params:xml:ns:netconf:base:1.0">
<noArgInner xmlns="urn:opendaylight:params:xml:ns:yang:controller:test:impl">
<context-instance>
- /modules/module[name='test1'][type='impl-netconf']/inner-running-data-additional[key='1']
+ /modules/module[name='instance-from-code'][type='impl-netconf']/inner-running-data-additional[key='1']
</context-instance>
</noArgInner>
</rpc>
<leaf-list-output
xmlns="urn:opendaylight:params:xml:ns:yang:controller:test:impl">
<context-instance>
- /modules/module[type='impl-netconf'][name='test1']/inner-running-data[key='0']/inner-inner-running-data[key='1']
+ /modules/module[type='impl-netconf'][name='instance-from-code']/inner-running-data[key='0']/inner-inner-running-data[key='1']
</context-instance>
</leaf-list-output>
</rpc>
<module>../../third-party/com.siemens.ct.exi</module>
<module>netconf-monitoring</module>
<module>ietf-netconf-monitoring</module>
+ <module>ietf-netconf-monitoring-extension</module>
</modules>
<profiles>
<artifactId>netconf-ssh</artifactId>
<version>${netconf.version}</version>
</dependency>
+ <dependency>
+ <groupId>${project.groupId}</groupId>
+ <artifactId>netconf-ssh</artifactId>
+ <version>${netconf.version}</version>
+ <type>test-jar</type>
+ </dependency>
<dependency>
<groupId>${project.groupId}</groupId>
<artifactId>netconf-mapping-api</artifactId>
public NorthboundApplication() {
_singletons = new HashSet<Object>();
_singletons.add(new ContextResolver<JAXBContext>() {
- JAXBContext jaxbContext = newJAXBContext();
+ JAXBContext jaxbContext;
@Override
- public JAXBContext getContext(Class<?> type) {
+ public synchronized JAXBContext getContext(Class<?> type) {
+ if (jaxbContext == null) {
+ jaxbContext = newJAXBContext();
+ }
return jaxbContext;
}
</init-param>
<init-param>
<param-name>cors.allowed.methods</param-name>
- <param-value>GET,POST,HEAD,OPTIONS,PUT</param-value>
+ <param-value>GET,POST,HEAD,OPTIONS,PUT,DELETE</param-value>
</init-param>
<init-param>
<param-name>cors.allowed.headers</param-name>
private Boolean throttling = false; // if true, no more batching.
private volatile Boolean shuttingDown = false;
- private LLDPTLV chassisIdTlv, portIdTlv, ttlTlv, customTlv;
+ private LLDPTLV chassisIdTlv, systemNameTlv, portIdTlv, ttlTlv, customTlv;
private IPluginOutConnectionService connectionOutService;
class DiscoveryTransmit implements Runnable {
chassisIdTlv.setType(LLDPTLV.TLVType.ChassisID.getValue()).setLength((short) cidValue.length)
.setValue(cidValue);
+ // Create LLDP SystemName TLV
+ byte[] snValue = LLDPTLV.createSystemNameTLVValue(nodeConnector.getNode().toString());
+ systemNameTlv.setType(LLDPTLV.TLVType.SystemName.getValue()).setLength((short) snValue.length)
+ .setValue(snValue);
+
// Create LLDP PortID TLV
String portId = nodeConnector.getNodeConnectorIDString();
byte[] pidValue = LLDPTLV.createPortIDTLVValue(portId);
// Create discovery pkt
LLDP discoveryPkt = new LLDP();
- discoveryPkt.setChassisId(chassisIdTlv).setPortId(portIdTlv).setTtl(ttlTlv).setOptionalTLVList(customList);
+ discoveryPkt.setChassisId(chassisIdTlv).setPortId(portIdTlv).setTtl(ttlTlv).setSystemNameId(systemNameTlv)
+ .setOptionalTLVList(customList);
RawPacket rawPkt = null;
try {
chassisIdTlv = new LLDPTLV();
chassisIdTlv.setType(LLDPTLV.TLVType.ChassisID.getValue());
+ // Create LLDP SystemName TLV
+ systemNameTlv = new LLDPTLV();
+ systemNameTlv.setType(LLDPTLV.TLVType.SystemName.getValue());
+
// Create LLDP PortID TLV
portIdTlv = new LLDPTLV();
portIdTlv.setType(LLDPTLV.TLVType.PortID.getValue());
public class LLDP extends Packet {
private static final String CHASSISID = "ChassisId";
+ private static final String SYSTEMNAMEID = "SystemNameID";
private static final String PORTID = "PortId";
private static final String TTL = "TTL";
- private static final int LLDPDefaultTlvs = 3;
+ private static final int LLDPDefaultTlvs = 4;
private static LLDPTLV emptyTLV = new LLDPTLV().setLength((short) 0)
.setType((byte) 0);
public static final byte[] LLDPMulticastMac = { 1, (byte) 0x80,
return this;
}
+ /**
+ * @return the SystemName TLV
+ */
+ public LLDPTLV getSystemNameId() {
+ return getTLV(SYSTEMNAMEID);
+ }
+
+ /**
+ * @param LLDPTLV
+ * - the chassisId to set
+ */
+ public LLDP setSystemNameId(LLDPTLV systemNameId) {
+ tlvList.put(getType(SYSTEMNAMEID), systemNameId);
+ return this;
+ }
+
/**
* @return LLDPTLV - the portId TLV
*/
getfieldnumBits(VALUE)); // variable
}
+ /**
+ * Creates the SystemName TLV value
+ *
+ * @param nodeId
+ * node identifier string
+ * @return the SystemName TLV value in byte array
+ */
+ static public byte[] createSystemNameTLVValue(String nodeId) {
+ byte[] nid = nodeId.getBytes();
+ return nid;
+ }
+
/**
* Creates the ChassisID TLV value including the subtype and ChassisID
* string
public static NodeConnector createNodeConnector(
String nodeConnectorType, Object portId, Node node) {
try {
- return new NodeConnector(nodeConnectorType, portId, node);
+ if (nodeConnectorType.equals(Node.NodeIDType.OPENFLOW) && (portId.getClass() == String.class)) {
+ return new NodeConnector(nodeConnectorType, Short.parseShort((String) portId), node);
+ } else {
+ return new NodeConnector(nodeConnectorType, portId, node);
+ }
} catch (ConstructionException e1) {
logger.error("",e1);
return null;
if (p == null) {
return false;
}
- if (this.isFlatLayer2()) {
- return true;
- }
- return this.nodeConnectors.contains(p);
+ return isFlatLayer2() || nodeConnectors.contains(p);
}
public boolean isMutualExclusive(Subnet otherSubnet) {
@Override
public SubnetConfig getSubnetConfig(String subnet) {
// if there are no subnets, return the default subnet
- if(subnetsConfigList.size() == 0 && subnet == DEFAULT_SUBNET_NAME){
+ if(subnetsConfigList.isEmpty() && subnet.equalsIgnoreCase(DEFAULT_SUBNET_NAME)){
return DEFAULT_SUBNETCONFIG;
}else{
return subnetsConfigList.get(subnet);
}
private Status semanticCheck(SubnetConfig conf) {
- Subnet newSubnet = new Subnet(conf);
Set<InetAddress> IPs = subnets.keySet();
if (IPs == null) {
return new Status(StatusCode.SUCCESS);
}
+ Subnet newSubnet = new Subnet(conf);
for (InetAddress i : IPs) {
Subnet existingSubnet = subnets.get(i);
if ((existingSubnet != null) && !existingSubnet.isMutualExclusive(newSubnet)) {
return status;
}
} else {
- if (conf.getName().equals(DEFAULT_SUBNET_NAME)) {
+ if (conf.getName().equalsIgnoreCase(DEFAULT_SUBNET_NAME)) {
return new Status(StatusCode.NOTALLOWED, "The specified subnet gateway cannot be removed");
}
}
status = updateConfig(conf, isAdding);
if(!status.isSuccess()) {
updateDatabase(conf, (!isAdding));
+ } else {
+ // update the listeners
+ Subnet subnetCurr = subnets.get(conf.getIPAddress());
+ Subnet subnet;
+ if (subnetCurr == null) {
+ subnet = new Subnet(conf);
+ } else {
+ subnet = subnetCurr.clone();
+ }
+ notifySubnetChange(subnet, isAdding);
}
}
@Override
public Status removeSubnet(String name) {
- if (name.equals(DEFAULT_SUBNET_NAME)) {
+ if (name.equalsIgnoreCase(DEFAULT_SUBNET_NAME)) {
return new Status(StatusCode.NOTALLOWED, "The specified subnet gateway cannot be removed");
}
SubnetConfig conf = subnetsConfigList.get(name);
return DEFAULT_SUBNET;
}
- Subnet sub;
- Set<InetAddress> indices = subnets.keySet();
- for (InetAddress i : indices) {
- sub = subnets.get(i);
- if (sub.isSubnetOf(networkAddress)) {
- return sub;
+ for(Map.Entry<InetAddress,Subnet> subnetEntry : subnets.entrySet()) {
+ if(subnetEntry.getValue().isSubnetOf(networkAddress)) {
+ return subnetEntry.getValue();
}
}
return null;
<artifactId>topologymanager.integrationtest</artifactId>
<version>0.4.0-SNAPSHOT</version>
<dependencies>
+ <dependency>
+ <groupId>org.ops4j.pax.exam</groupId>
+ <artifactId>pax-exam-container-native</artifactId>
+ <version>${exam.version}</version>
+ <scope>test</scope>
+ </dependency>
<dependency>
<groupId>org.opendaylight.controller</groupId>
<artifactId>protocol_plugins.stub</artifactId>
org.opendaylight.controller.usermanager
</Import-Package>
<Export-Package>
-<!--
+ <!--
org.opendaylight.controller.usermanager,
org.opendaylight.controller.usermanager.internal
- -->
+ -->
</Export-Package>
<Bundle-Activator>
org.opendaylight.controller.usermanager.internal.Activator