module ${artifactId} {
yang-version 1;
- namespace "urn:opendaylight:params:xml:ns:yang:example";
+ namespace "urn:opendaylight:params:xml:ns:yang:${artifactId}";
prefix "${artifactId}";
revision "2015-01-05" {
<?xml version="1.0" encoding="UTF-8"?>
<!-- vi: set et smarttab sw=4 tabstop=4: -->
<!--
-Necessary TODO: Put your copyright statement here
+${copyright}
This program and the accompanying materials are made available under the
terms of the Eclipse Public License v1.0 which accompanies this distribution,
#set( $symbol_dollar = '$' )
#set( $symbol_escape = '\' )
<?xml version="1.0" encoding="UTF-8"?>
-<!-- TODO: Put your copyright here:
-<your copyright> and others. All rights reserved.
+<!--
+${copyright} 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 INTERNAL
<?xml version="1.0" encoding="UTF-8"?>
-<!-- TODO: Put your copyright here:
-<your copyright> and others. All rights reserved.
+<!--
+${copyright} 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 INTERNAL
<T> T resolveInstance(Class<T> expectedType, ObjectName objectName,
JmxAttribute jmxAttribute);
+
/**
* To be used during commit phase to resolve identity-ref config attributes.
*
*/
<T> T newMXBeanProxy(ObjectName objectName, Class<T> interfaceClass);
+ /**
+ * Check whether a dependency will be reused or (re)created. Useful when deciding if current module could be also reused.
+ *
+ * @param objectName ObjectName ID of a dependency
+ * @param jmxAttribute JMXAttribute ID of a dependency
+ * @return true if the dependency will be reused false otherwise
+ */
+ boolean canReuseDependency(ObjectName objectName, JmxAttribute jmxAttribute);
}
--- /dev/null
+package org.opendaylight.controller.config.spi;
+
+import org.opendaylight.controller.config.api.DependencyResolver;
+import org.opendaylight.controller.config.api.ModuleIdentifier;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ * Base implementation of Module. This implementation contains base logic for Module reconfiguration with associated fields.
+ * @param <M> Type of module implementation. Enables easier implementation for the {@link #isSame} method
+ */
+public abstract class AbstractModule<M extends AbstractModule<M>> implements org.opendaylight.controller.config.spi.Module {
+
+ private static final Logger LOG = LoggerFactory.getLogger(AbstractModule.class);
+
+ private final M oldModule;
+ private final AutoCloseable oldInstance;
+ protected final ModuleIdentifier identifier;
+ private AutoCloseable instance;
+ protected final DependencyResolver dependencyResolver;
+
+ /**
+ * Called when module is configured.
+ *
+ * @param identifier id of current instance.
+ * @param dependencyResolver resolver used in dependency injection and validation.
+ */
+ public AbstractModule(ModuleIdentifier identifier, DependencyResolver dependencyResolver) {
+ this(identifier, dependencyResolver, null, null);
+ }
+
+ /**
+ * Called when module is reconfigured.
+ *
+ * @param identifier id of current instance.
+ * @param dependencyResolver resolver used in dependency injection and validation.
+ * @param oldModule old instance of module that is being reconfigred(replaced) by current instance. The old instance can be examined for reuse.
+ * @param oldInstance old instance wrapped by the old module. This is the resource that is actually being reused if possible or closed otherwise.
+ */
+ public AbstractModule(ModuleIdentifier identifier, DependencyResolver dependencyResolver, M oldModule, AutoCloseable oldInstance) {
+ this.identifier = identifier;
+ this.dependencyResolver = dependencyResolver;
+ this.oldModule = oldModule;
+ this.oldInstance = oldInstance;
+ }
+
+ @Override
+ public ModuleIdentifier getIdentifier() {
+ return identifier;
+ }
+
+ /**
+ *
+ * General algorithm for spawning/closing and reusing wrapped instances.
+ *
+ * @return current instance of wrapped resource either by reusing the old one (if present) or constructing a brand new.
+ */
+ @Override
+ public final AutoCloseable getInstance() {
+ if(instance==null) {
+ if(oldInstance!=null && canReuseInstance(oldModule)) {
+ resolveDependencies();
+ instance = reuseInstance(oldInstance);
+ } else {
+ if(oldInstance!=null) {
+ try {
+ oldInstance.close();
+ } catch(Exception e) {
+ LOG.error("An error occurred while closing old instance {} for module {}", oldInstance, getIdentifier(), e);
+ }
+ }
+ resolveDependencies();
+ instance = createInstance();
+ if (instance == null) {
+ throw new IllegalStateException("Error in createInstance - null is not allowed as return value. Module: " + getIdentifier());
+ }
+ }
+ }
+ return instance;
+ }
+
+ /**
+ * @return Brand new instance of wrapped class in case no previous instance is present or reconfiguration is impossible.
+ */
+ protected abstract AutoCloseable createInstance();
+
+ @Override
+ public final boolean canReuse(Module oldModule) {
+ // Just cast into a specific instance
+ // TODO unify this method with canReuseInstance (required Module interface to be generic which requires quite a lot of changes)
+ return getClass().isInstance(oldModule) ? canReuseInstance((M) oldModule) : false;
+ }
+
+ /**
+ *
+ * Users are welcome to override this method to provide custom logic for advanced reusability detection.
+ *
+ * @param oldModule old instance of a Module
+ * @return true if the old instance is reusable false if a new one should be spawned
+ */
+ protected abstract boolean canReuseInstance(final M oldModule);
+
+ /**
+ * By default the oldInstance is returned since this method is by default called only if the oldModule had the same configuration and dependencies configured.
+ * Users are welcome to override this method to provide custom logic for advanced reusability.
+ *
+ * @param oldInstance old instance of a class wrapped by the module
+ * @return reused instance
+ */
+ protected AutoCloseable reuseInstance(AutoCloseable oldInstance) {
+ // implement if instance reuse should be supported. Override canReuseInstance to change the criteria.
+ return oldInstance;
+ }
+
+ /**
+ * Inject all the dependencies using dependency resolver instance.
+ */
+ protected abstract void resolveDependencies();
+}
*/
AutoCloseable getInstance();
+
+ /**
+ * Compare current module with oldModule and if the instance/live object
+ * produced by the old module can be reused in this module as well return true.
+ * Typically true should be returned if the old module had the same configuration.
+ *
+ *
+ * @param oldModule old instance of Module
+ * @return true if the instance produced by oldModule can be reused with current instance as well.
+ */
+ public boolean canReuse(Module oldModule);
+
+
}
}
}
- // destroy all live objects one after another in order of the dependency
- // hierarchy
+ // destroy all live objects one after another in order of the dependency hierarchy, from top to bottom
List<DestroyedModule> destroyedModules = currentConfig
.getModulesToBeDestroyed();
for (DestroyedModule destroyedModule : destroyedModules) {
import static com.google.common.base.Preconditions.checkNotNull;
import static java.lang.String.format;
+import com.google.common.collect.Lists;
import java.util.ArrayList;
import java.util.Collection;
import java.util.HashSet;
LOG.trace("Committing transaction {}", getTransactionIdentifier());
- // call getInstance()
- for (Entry<ModuleIdentifier, Module> entry : dependencyResolverManager
- .getAllModules().entrySet()) {
- Module module = entry.getValue();
- ModuleIdentifier name = entry.getKey();
+ Map<ModuleIdentifier, Module> allModules = dependencyResolverManager.getAllModules();
+
+ // call getInstance() on all Modules from top to bottom (from source to target of the dependency relation)
+ // The source of a dependency closes itself and calls getInstance recursively on the dependencies (in case of reconfiguration)
+ // This makes close() calls from top to bottom while createInstance() calls are performed bottom to top
+ List<ModuleIdentifier> sortedModuleIdentifiers = Lists.reverse(dependencyResolverManager.getSortedModuleIdentifiers());
+ for (ModuleIdentifier moduleIdentifier : sortedModuleIdentifiers) {
+ Module module = allModules.get(moduleIdentifier);
+
try {
LOG.debug("About to commit {} in transaction {}",
- name, getTransactionIdentifier());
+ moduleIdentifier, getTransactionIdentifier());
AutoCloseable instance = module.getInstance();
- checkNotNull(instance, "Instance is null:{} in transaction {}", name, getTransactionIdentifier());
+ checkNotNull(instance, "Instance is null:{} in transaction {}", moduleIdentifier, getTransactionIdentifier());
} catch (Exception e) {
- LOG.error("Commit failed on {} in transaction {}", name,
+ LOG.error("Commit failed on {} in transaction {}", moduleIdentifier,
getTransactionIdentifier(), e);
internalAbort();
throw new IllegalStateException(
format("Error - getInstance() failed for %s in transaction %s",
- name, getTransactionIdentifier()), e);
+ moduleIdentifier, getTransactionIdentifier()), e);
}
}
- // count dependency order
-
LOG.trace("Committed configuration {}", getTransactionIdentifier());
transactionStatus.setCommitted();
- return dependencyResolverManager.getSortedModuleIdentifiers();
+ return sortedModuleIdentifiers;
}
@Override
import static java.lang.String.format;
+import com.google.common.base.Preconditions;
import java.util.HashSet;
import java.util.LinkedHashSet;
import java.util.Set;
@Override
public <T> T resolveInstance(Class<T> expectedType, ObjectName dependentReadOnlyON,
JmxAttribute jmxAttribute) {
- if (expectedType == null || dependentReadOnlyON == null || jmxAttribute == null) {
- throw new IllegalArgumentException(format(
- "Null parameters not allowed, got %s %s %s", expectedType,
- dependentReadOnlyON, jmxAttribute));
- }
- ObjectName translatedDependentReadOnlyON = translateServiceRefIfPossible(dependentReadOnlyON);
- transactionStatus.checkCommitStarted();
- transactionStatus.checkNotCommitted();
+ Module module = resolveModuleInstance(dependentReadOnlyON, jmxAttribute);
- ModuleIdentifier dependentModuleIdentifier = ObjectNameUtil.fromON(
- translatedDependentReadOnlyON, ObjectNameUtil.TYPE_MODULE);
- Module module = modulesHolder.findModule(dependentModuleIdentifier,
- jmxAttribute);
synchronized (this) {
- dependencies.add(dependentModuleIdentifier);
+ dependencies.add(module.getIdentifier());
}
AutoCloseable instance = module.getInstance();
if (instance == null) {
String message = format(
"Error while %s resolving instance %s. getInstance() returned null. "
+ "Expected type %s , attribute %s", name,
- dependentModuleIdentifier, expectedType, jmxAttribute
+ module.getIdentifier(), expectedType, jmxAttribute
);
throw new JmxAttributeValidationException(message, jmxAttribute);
}
}
}
+ private Module resolveModuleInstance(ObjectName dependentReadOnlyON,
+ JmxAttribute jmxAttribute) {
+ Preconditions.checkArgument(dependentReadOnlyON != null ,"dependentReadOnlyON");
+ Preconditions.checkArgument(jmxAttribute != null, "jmxAttribute");
+ ObjectName translatedDependentReadOnlyON = translateServiceRefIfPossible(dependentReadOnlyON);
+ transactionStatus.checkCommitStarted();
+ transactionStatus.checkNotCommitted();
+
+ ModuleIdentifier dependentModuleIdentifier = ObjectNameUtil.fromON(
+ translatedDependentReadOnlyON, ObjectNameUtil.TYPE_MODULE);
+
+ return Preconditions.checkNotNull(modulesHolder.findModule(dependentModuleIdentifier, jmxAttribute));
+ }
+
+ @Override
+ public boolean canReuseDependency(ObjectName objectName, JmxAttribute jmxAttribute) {
+ Preconditions.checkNotNull(objectName);
+ Preconditions.checkNotNull(jmxAttribute);
+
+ Module currentModule = resolveModuleInstance(objectName, jmxAttribute);
+ ModuleIdentifier identifier = currentModule.getIdentifier();
+ ModuleInternalTransactionalInfo moduleInternalTransactionalInfo = modulesHolder.findModuleInternalTransactionalInfo(identifier);
+
+ if(moduleInternalTransactionalInfo.hasOldModule()) {
+ Module oldModule = moduleInternalTransactionalInfo.getOldInternalInfo().getReadableModule().getModule();
+ return currentModule.canReuse(oldModule);
+ }
+ return false;
+ }
+
@Override
public <T extends BaseIdentity> Class<? extends T> resolveIdentity(IdentityAttributeRef identityRef, Class<T> expectedBaseClass) {
final QName qName = QName.create(identityRef.getqNameOfIdentity());
@Override
public int compareTo(DependencyResolverImpl o) {
- transactionStatus.checkCommitted();
+ transactionStatus.checkCommitStarted();
return Integer.compare(getMaxDependencyDepth(),
o.getMaxDependencyDepth());
}
}
void countMaxDependencyDepth(DependencyResolverManager manager) {
- transactionStatus.checkCommitted();
+ // We can calculate the dependency after second phase commit was started
+ // Second phase commit starts after validation and validation adds the dependencies into the dependency resolver, which are necessary for the calculation
+ // FIXME generated code for abstract module declares validate method as non-final
+ // Overriding the validate would cause recreate every time instead of reuse + also possibly wrong close order if there is another module depending
+ transactionStatus.checkCommitStarted();
if (maxDependencyDepth == null) {
maxDependencyDepth = getMaxDepth(this, manager,
new LinkedHashSet<ModuleIdentifier>());
* things?
*/
private List<DependencyResolverImpl> getAllSorted() {
- transactionStatus.checkCommitted();
+ transactionStatus.checkCommitStarted();
List<DependencyResolverImpl> sorted = new ArrayList<>(
moduleIdentifiersToDependencyResolverMap.values());
for (DependencyResolverImpl dri : sorted) {
*/
package org.opendaylight.controller.config.manager.impl.dependencyresolver;
+import com.google.common.base.Preconditions;
import javax.annotation.Nullable;
import org.opendaylight.controller.config.api.ModuleIdentifier;
import org.opendaylight.controller.config.manager.impl.ModuleInternalInfo;
@Nullable
public ModuleInternalInfo getOldInternalInfo() {
- if (maybeOldInternalInfo == null) {
- throw new NullPointerException();
- }
- return maybeOldInternalInfo;
+ return Preconditions.checkNotNull(maybeOldInternalInfo);
}
public TransactionModuleJMXRegistration getTransactionModuleJMXRegistration() {
this.id = id==null ? new ModuleIdentifier(getClass().getCanonicalName(), "mock") : id;
}
+
+ @Override
+ public boolean canReuse(Module oldModule) {
+ return instance!=null;
+ }
+
@Override
public void validate() {
}
moduleName124, instanceName134);
assertEquals(Sets.newHashSet(name1), beans);
}
-
-}
+}
\ No newline at end of file
// switch to second phase committed
reset(transactionStatus);
+ doNothing().when(transactionStatus).checkCommitStarted();
doNothing().when(transactionStatus).checkCommitted();
+ doNothing().when(transactionStatus).checkNotCommitted();
+
List<ModuleIdentifier> sortedModuleIdentifiers = tested
.getSortedModuleIdentifiers();
assertEquals(
private static Module mockedModule() {
Module mockedModule = mock(Module.class);
doReturn(mock(AutoCloseable.class)).when(mockedModule).getInstance();
+ doReturn(new ModuleIdentifier("fact", "instance")).when(mockedModule).getIdentifier();
return mockedModule;
}
return instance;
}
+ @Override
+ public boolean canReuse(final Module oldModule) {
+ return false;
+ }
+
@Override
public ModuleIdentifier getIdentifier() {
return identifier;
}
+ @Override
+ public boolean canReuse(Module oldModule) {
+ return false;
+ }
+
@Override
public Closeable getInstance() {
return new MockedThreadPool(threadCount);
"Parameter 'ThreadCount' must be greater than 0");
}
+ @Override
+ public boolean canReuse(final Module oldModule) {
+ return false;
+ }
+
@Override
public int getThreadCount() {
return threadCount;
"Parameter 'threadCount' must be greater than 0");
}
+ @Override
+ public boolean canReuse(final Module oldModule) {
+ return isReusable() && triggerNewInstanceCreation == false;
+ }
+
@Override
public Closeable getInstance() {
if (instance == null) {
private FixedThreadPoolModuleFactory factory;
private final String nameInstance = "fixedInstance";
+ private ObjectName threadFactoryON;
@Before
public void setUp() {
assertBeanCount(1, factory.getImplementationName());
transaction = configRegistryClient.createTransaction();
+ NamingThreadFactoryModuleMXBean namingThreadFactoryModuleMXBean = transaction.newMXBeanProxy(threadFactoryON, NamingThreadFactoryModuleMXBean.class);
+ namingThreadFactoryModuleMXBean.setNamePrefix("newPrefix");
CommitStatus status = transaction.commit();
assertBeanCount(1, factory.getImplementationName());
- assertStatus(status, 0, 0, 2);
+ assertStatus(status, 0, 2, 0);
}
@Test
FixedThreadPoolModuleMXBean mxBean = transaction.newMXBeanProxy(nameCreated, FixedThreadPoolModuleMXBean.class);
mxBean.setMaxThreadCount(numberOfThreads);
- ObjectName threadFactoryON = transaction.createModule(NamingThreadFactoryModuleFactory.NAME, "naming");
+ threadFactoryON = transaction.createModule(NamingThreadFactoryModuleFactory.NAME, "naming");
NamingThreadFactoryModuleMXBean namingThreadFactoryModuleMXBean = transaction.newMXBeanProxy(threadFactoryON,
NamingThreadFactoryModuleMXBean.class);
namingThreadFactoryModuleMXBean.setNamePrefix(prefix);
doReturn(mock(ExecutorService.class)).when(pool).getExecutor();
return pool;
}
-
}
return fact;
}
+ @Override
+ public boolean canReuse(Module oldModule) {
+ return false;
+ }
+
}
private final String registratorType;
public AbstractModuleTemplate(Header header, String packageName,
- String abstractModuleName, List<String> implementedIfcs,
- List<ModuleField> moduleFields, List<MethodDefinition> methods,
+ String abstractModuleName, List<String> extendedClasses,
+ List<String> implementedIfcs, List<ModuleField> moduleFields, List<MethodDefinition> methods,
boolean isRuntime, String registratorType) {
- super(header, packageName, abstractModuleName, Collections
- .<String> emptyList(), implementedIfcs, Collections
- .<Field> emptyList(), methods, true, false, Collections
- .<Constructor> emptyList());
+ super(header, packageName, abstractModuleName, extendedClasses,
+ implementedIfcs, Collections.<Field> emptyList(), methods,
+ true, false, Collections.<Constructor> emptyList());
this.moduleFields = moduleFields;
this.runtime = isRuntime;
this.registratorType = registratorType;
static List<String> checkCardinality(List<String> extendedClass) {
if (extendedClass.size() > 1) {
throw new IllegalArgumentException(
- "Class cannot have more than one super " + "class");
+ "Class cannot have more than one super class, found: " + extendedClass);
}
return extendedClass;
}
import org.opendaylight.controller.config.api.RuntimeBeanRegistratorAwareModule;
import org.opendaylight.controller.config.api.annotations.AbstractServiceInterface;
import org.opendaylight.controller.config.api.runtime.RuntimeBean;
-import org.opendaylight.controller.config.spi.Module;
+import org.opendaylight.controller.config.spi.AbstractModule;
import org.opendaylight.controller.config.yangjmxgenerator.AbstractEntry;
import org.opendaylight.controller.config.yangjmxgenerator.ModuleMXBeanEntry;
import org.opendaylight.controller.config.yangjmxgenerator.RuntimeBeanEntry;
List<ModuleField> moduleFields = attrProcessor.getModuleFields();
List<String> implementedIfcs = Lists.newArrayList(
- Module.class.getCanonicalName(),
mbe.getFullyQualifiedName(mbe.getMXBeanInterfaceName()));
for (String implementedService : mbe.getProvidedServices().keySet()) {
.getCanonicalName());
}
+ List<String> extendedClasses = Collections.singletonList(AbstractModule.class.getCanonicalName() + "<" + mbe.getAbstractModuleName() + ">");
+
AbstractModuleTemplate abstractModuleTemplate = new AbstractModuleTemplate(
getHeaderFromEntry(mbe), mbe.getPackageName(),
- mbe.getAbstractModuleName(), implementedIfcs, moduleFields,
+ mbe.getAbstractModuleName(), extendedClasses, implementedIfcs, moduleFields,
attrProcessor.getMethods(), generateRuntime,
registratorFullyQualifiedName);
import static com.google.common.base.Preconditions.checkState;
import static java.lang.String.format;
+import com.google.common.base.Function;
import com.google.common.base.Joiner;
import com.google.common.base.Optional;
-import java.util.ArrayList;
+import com.google.common.collect.Collections2;
+import com.google.common.collect.Iterables;
+import com.google.common.collect.Lists;
+import java.util.Collections;
import java.util.HashMap;
import java.util.LinkedHashMap;
import java.util.List;
import org.opendaylight.controller.config.yangjmxgenerator.plugin.ftl.AbstractModuleTemplate;
import org.opendaylight.controller.config.yangjmxgenerator.plugin.ftl.TemplateFactory;
import org.opendaylight.controller.config.yangjmxgenerator.plugin.ftl.model.Annotation;
+import org.opendaylight.controller.config.yangjmxgenerator.plugin.ftl.model.Field;
import org.opendaylight.controller.config.yangjmxgenerator.plugin.ftl.model.IdentityRefModuleField;
import org.opendaylight.controller.config.yangjmxgenerator.plugin.ftl.model.Method;
+import org.opendaylight.controller.config.yangjmxgenerator.plugin.ftl.model.MethodDefinition;
import org.opendaylight.controller.config.yangjmxgenerator.plugin.ftl.model.ModuleField;
import org.opendaylight.controller.config.yangjmxgenerator.plugin.java.FullyQualifiedName;
import org.opendaylight.controller.config.yangjmxgenerator.plugin.java.GeneratedObject;
public class AbsModuleGeneratedObjectFactory {
+ private static final Function<String, FullyQualifiedName> FULLY_QUALIFIED_NAME_FUNCTION = new Function<String, FullyQualifiedName>() {
+ @Override
+ public FullyQualifiedName apply(final String input) {
+ return FullyQualifiedName.fromString(input);
+ }
+ };
+
public GeneratedObject toGeneratedObject(ModuleMXBeanEntry mbe, Optional<String> copyright) {
FullyQualifiedName abstractFQN = new FullyQualifiedName(mbe.getPackageName(), mbe.getAbstractModuleName());
Optional<String> classJavaDoc = Optional.fromNullable(mbe.getNullableDescription());
AbstractModuleTemplate abstractModuleTemplate = TemplateFactory.abstractModuleTemplateFromMbe(mbe);
Optional<String> header = abstractModuleTemplate.getHeaderString();
- List<FullyQualifiedName> implementedInterfaces = new ArrayList<>();
- for(String implemented: abstractModuleTemplate.getTypeDeclaration().getImplemented()) {
- implementedInterfaces.add(FullyQualifiedName.fromString(implemented));
- }
+ List<FullyQualifiedName> implementedInterfaces = Lists.transform(abstractModuleTemplate.getTypeDeclaration().getImplemented(), FULLY_QUALIFIED_NAME_FUNCTION);
+
+ Optional<FullyQualifiedName> extended =
+ Optional.fromNullable(
+ Iterables.getFirst(
+ Collections2.transform(abstractModuleTemplate.getTypeDeclaration().getExtended(), FULLY_QUALIFIED_NAME_FUNCTION), null));
+
Optional<FullyQualifiedName> maybeRegistratorType;
if (abstractModuleTemplate.isRuntime()) {
maybeRegistratorType = Optional.of(FullyQualifiedName.fromString(abstractModuleTemplate.getRegistratorType()));
maybeRegistratorType = Optional.absent();
}
- return toGeneratedObject(abstractFQN, copyright, header, classJavaDoc, implementedInterfaces,
+ return toGeneratedObject(abstractFQN, copyright, header, classJavaDoc, extended, implementedInterfaces,
abstractModuleTemplate.getModuleFields(), maybeRegistratorType, abstractModuleTemplate.getMethods(),
mbe.getYangModuleQName());
}
Optional<String> copyright,
Optional<String> header,
Optional<String> classJavaDoc,
+ Optional<FullyQualifiedName> extended,
List<FullyQualifiedName> implementedInterfaces,
List<ModuleField> moduleFields,
Optional<FullyQualifiedName> maybeRegistratorType,
for(FullyQualifiedName implemented: implementedInterfaces) {
b.addImplementsFQN(implemented);
}
+ if(extended.isPresent()) {
+ b.addExtendsFQN(extended.get());
+ }
if (classJavaDoc.isPresent()) {
b.addClassAnnotation(format("@%s(value=\"%s\")", Description.class.getCanonicalName(), classJavaDoc.get()));
}
b.addToBody("//attributes end");
- b.addToBody(getCommonFields(abstractFQN));
-
-
b.addToBody(getNewConstructor(abstractFQN));
b.addToBody(getCopyFromOldConstructor(abstractFQN));
b.addToBody(getCachesOfResolvedDependencies(moduleFields));
b.addToBody(getCachesOfResolvedIdentityRefs(moduleFields));
- b.addToBody(getGetInstance(moduleFields));
+ b.addToBody(getResolveDependencies(moduleFields));
b.addToBody(getReuseLogic(moduleFields, abstractFQN));
b.addToBody(getEqualsAndHashCode(abstractFQN));
b.addToBody(getMethods(methods));
+ b.addToBody(getGetLogger());
return new GeneratedObjectBuilder(b.build()).toGeneratedObject();
}
// loop through fields, do deep equals on each field
for (ModuleField moduleField : moduleFields) {
+ result += format(
+ "if (java.util.Objects.deepEquals(%s, other.%1$s) == false) {\n"+
+ "return false;\n"+
+ "}\n", moduleField.getName());
+
if (moduleField.isListOfDependencies()) {
result += format(
- "if (%1$sDependency.equals(other.%1$sDependency) == false) {\n"+
- "return false;\n"+
- "}\n"+
- "for (int idx = 0; idx < %1$sDependency.size(); idx++) {\n"+
- "if (%1$sDependency.get(idx) != other.%1$sDependency.get(idx)) {\n"+
- "return false;\n"+
- "}\n"+
- "}\n" ,moduleField.getName());
+ "for (int idx = 0; idx < %1$s.size(); idx++) {\n"+
+ "if (!dependencyResolver.canReuseDependency(%1$s.get(idx), %1$sJmxAttribute)) {\n"+
+ "return false;\n"+
+ "}\n"+
+ "}\n" , moduleField.getName());
} else if (moduleField.isDependent()) {
result += format(
- "if (%sDependency != other.%1$sDependency) { // reference to dependency must be same\n"+
- "return false;\n"+
- "}\n",moduleField.getName());
- } else {
- result += format(
- "if (java.util.Objects.deepEquals(%s, other.%1$s) == false) {\n"+
- "return false;\n"+
- "}\n", moduleField.getName());
+ // If a reference is null (ie optional reference) it makes no sens to call canReuse on it
+ // In such case we continue in the isSame method because if we have null here, the previous value was null as well
+ // If the previous value was not null and current is or vice verse, the deepEquals comparison would return false
+ "if(%1$s!= null) {\n" +
+ "if (!dependencyResolver.canReuseDependency(%1$s, %1$sJmxAttribute)) { // reference to dependency must be reusable as well\n" +
+ "return false;\n" +
+ "}\n" +
+ "}\n", moduleField.getName());
}
}
+
result += "\n"+
"return true;\n"+
"}\n";
return result;
}
- private static String getGetInstance(List<ModuleField> moduleFields) {
- String result = "\n"+
- "@Override\n"+
- format("public final %s getInstance() {\n", AutoCloseable.class.getCanonicalName())+
- "if(instance==null) {\n";
- // create instance start
-
+ private static String getResolveDependencies(final List<ModuleField> moduleFields) {
// loop through dependent fields, use dependency resolver to instantiate dependencies. Do it in loop in case field represents list of dependencies.
Map<ModuleField, String> resolveDependenciesMap = new HashMap<>();
for(ModuleField moduleField: moduleFields) {
String osgi = moduleField.getDependency().getSie().getExportedOsgiClassName();
if (moduleField.isList()) {
str = format(
- "%sDependency = new java.util.ArrayList<%s>();\n"+
- "for(javax.management.ObjectName dep : %1$s) {\n"+
- "%1$sDependency.add(dependencyResolver.resolveInstance(%2$s.class, dep, %1$sJmxAttribute));\n"+
- "}\n", moduleField.getName(), osgi);
+ "%sDependency = new java.util.ArrayList<%s>();\n"+
+ "for(javax.management.ObjectName dep : %1$s) {\n"+
+ "%1$sDependency.add(dependencyResolver.resolveInstance(%2$s.class, dep, %1$sJmxAttribute));\n"+
+ "}\n", moduleField.getName(), osgi);
} else {
str = format(
- "%1$sDependency = dependencyResolver.resolveInstance(%2$s.class, %1$s, %1$sJmxAttribute);\n",
- moduleField.getName(), osgi);
+ "%1$sDependency = dependencyResolver.resolveInstance(%2$s.class, %1$s, %1$sJmxAttribute);\n",
+ moduleField.getName(), osgi);
}
resolveDependenciesMap.put(moduleField, str);
}
}
+ String result = "\n"
+ + "protected final void resolveDependencies() {\n";
// wrap each field resolvation statement with if !=null when dependency is not mandatory
for (Map.Entry<ModuleField, String> entry : resolveDependenciesMap.entrySet()) {
if (entry.getKey().getDependency().isMandatory() == false) {
result += format("if (%s!=null){\n", moduleField.getName());
if (moduleField.isList()) {
result += format(
- "for(%s candidate : %s) {\n"+
- "candidate.injectDependencyResolver(dependencyResolver);\n"+
- "}\n", moduleField.getGenericInnerType(), moduleField.getName());
+ "for(%s candidate : %s) {\n"+
+ "candidate.injectDependencyResolver(dependencyResolver);\n"+
+ "}\n", moduleField.getGenericInnerType(), moduleField.getName());
} else {
result += format("%s.injectDependencyResolver(dependencyResolver);\n", moduleField.getName());
}
result += "}\n";
}
}
-
- // create instance end: reuse and recreate logic
- result += "if(oldInstance!=null && canReuseInstance(oldModule)) {\n"+
- "instance = reuseInstance(oldInstance);\n"+
- "} else {\n"+
- "if(oldInstance!=null) {\n"+
- "try {\n"+
- "oldInstance.close();\n"+
- "} catch(Exception e) {\n"+
- "logger.error(\"An error occurred while closing old instance \" + oldInstance, e);\n"+
- "}\n"+
- "}\n"+
- "instance = createInstance();\n"+
- "if (instance == null) {\n"+
- "throw new IllegalStateException(\"Error in createInstance - null is not allowed as return value\");\n"+
- "}\n"+
- "}\n"+
- "}\n"+
- "return instance;\n"+
- "}\n"+
- format("public abstract %s createInstance();\n", AutoCloseable.class.getCanonicalName());
-
+ result += "}\n";
return result;
}
- private static String getCommonFields(FullyQualifiedName abstractFQN) {
- return "\n"+
- format("private final %s oldModule;\n", abstractFQN.getTypeName())+
- format("private final %s oldInstance;\n", AutoCloseable.class.getCanonicalName())+
- format("private %s instance;\n", AutoCloseable.class.getCanonicalName())+
- format("protected final %s dependencyResolver;\n", DependencyResolver.class.getCanonicalName())+
- format("private final %s identifier;\n", ModuleIdentifier.class.getCanonicalName())+
- "@Override\n"+
- format("public %s getIdentifier() {\n", ModuleIdentifier.class.getCanonicalName())+
- "return identifier;\n"+
- "}\n";
- }
-
private static String getCachesOfResolvedIdentityRefs(List<ModuleField> moduleFields) {
StringBuilder result = new StringBuilder();
for (ModuleField moduleField : moduleFields) {
"public void validate() {\n";
// validate each mandatory dependency
for(ModuleField moduleField: moduleFields) {
- if (moduleField.isDependent() && moduleField.getDependency().isMandatory()) {
+ if (moduleField.isDependent()) {
if (moduleField.isList()) {
result += "" +
format("for(javax.management.ObjectName dep : %s) {\n", moduleField.getName()) +
moduleField.getDependency().getSie().getFullyQualifiedName(), moduleField.getName()) +
"}\n";
} else {
- result += format("dependencyResolver.validateDependency(%s.class, %s, %sJmxAttribute);",
+ if(moduleField.getDependency().isMandatory() == false) {
+ result += format("if(%s != null) {\n", moduleField.getName());
+ }
+ result += format("dependencyResolver.validateDependency(%s.class, %s, %sJmxAttribute);\n",
moduleField.getDependency().getSie().getFullyQualifiedName(), moduleField.getName(), moduleField.getName());
+ if(moduleField.getDependency().isMandatory() == false) {
+ result += "}\n";
+ }
}
}
}
}
private static String getLoggerDefinition(FullyQualifiedName fqn) {
- return format("private static final %s logger = %s.getLogger(%s.class);",
+ return format("private static final %s LOGGER = %s.getLogger(%s.class);",
Logger.class.getCanonicalName(), LoggerFactory.class.getCanonicalName(), fqn);
}
private static String getConstructorStart(FullyQualifiedName fqn,
LinkedHashMap<String, String> parameters, String after) {
String paramString = Joiner.on(",").withKeyValueSeparator(" ").join(parameters);
- String setters = "";
- for (String paramName : parameters.values()) {
- setters += format("this.%s = %1$s;\n", paramName);
- }
return format("public %s(", fqn.getTypeName()) +
paramString +
") {\n" +
- setters +
after +
"}\n";
}
LinkedHashMap<String, String> parameters = new LinkedHashMap<>();
parameters.put(ModuleIdentifier.class.getCanonicalName(), "identifier");
parameters.put(DependencyResolver.class.getCanonicalName(), "dependencyResolver");
-
- String setToNulls = "this.oldInstance=null;\n" +
- "this.oldModule=null;\n";
- return getConstructorStart(abstractFQN, parameters, setToNulls);
+ String init = "super(identifier, dependencyResolver);\n";
+ return getConstructorStart(abstractFQN, parameters, init);
}
private static String getCopyFromOldConstructor(FullyQualifiedName abstractFQN) {
parameters.put(DependencyResolver.class.getCanonicalName(), "dependencyResolver");
parameters.put(abstractFQN.getTypeName(), "oldModule");
parameters.put(AutoCloseable.class.getCanonicalName(), "oldInstance");
- return getConstructorStart(abstractFQN, parameters, "");
+ String init = "super(identifier, dependencyResolver, oldModule, oldInstance);\n";
+ return getConstructorStart(abstractFQN, parameters, init);
+ }
+
+ public String getGetLogger() {
+ return new MethodDefinition(Logger.class.getCanonicalName(), "getLogger", Collections.<Field>emptyList(), "return LOGGER;").toString();
}
}
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.controller.config.spi.AbstractModule;
import org.opendaylight.controller.config.spi.Module;
import org.opendaylight.controller.config.spi.ModuleFactory;
import org.opendaylight.controller.config.yangjmxgenerator.ConfigConstants;
assertContains(visitor.implmts,
PackageTranslatorTest.EXPECTED_PACKAGE_PREFIX
+ ".threads.java.DynamicThreadPoolModuleMXBean",
- Module.class.getCanonicalName(),
PackageTranslatorTest.EXPECTED_PACKAGE_PREFIX
+ ".threads.ScheduledThreadPoolServiceInterface",
PackageTranslatorTest.EXPECTED_PACKAGE_PREFIX
+ ".threads.ThreadPoolServiceInterface");
+ assertContains(visitor.extnds, AbstractModule.class.getCanonicalName());
assertEquals(2, visitor.constructors.size());
Set<String> fieldDeclarations = visitor.fieldDeclarations;
assertDeclaredField(fieldDeclarations,
assertDeclaredField(fieldDeclarations,
"private java.lang.Long coreSize");
assertDeclaredField(fieldDeclarations, "private byte[] binary");
- assertEquals(22, fieldDeclarations.size());
+ assertEquals(17, fieldDeclarations.size());
assertEquals(1, visitor.requireIfc.size());
String reqIfc = visitor.requireIfc.get("setThreadfactory");
assertContains(reqIfc, PackageTranslatorTest.EXPECTED_PACKAGE_PREFIX
+ ".threads.ThreadFactoryServiceInterface");
- assertEquals("Incorrenct number of generated methods", 27,
+ assertEquals("Incorrenct number of generated methods", 26,
visitor.methods.size());
assertEquals("Incorrenct number of generated method descriptions", 3,
visitor.methodDescriptions.size());
import static com.google.common.base.Preconditions.checkState;
import static java.lang.String.format;
import static org.opendaylight.controller.config.yangjmxgenerator.ConfigConstants.createConfigQName;
-
import com.google.common.annotations.VisibleForTesting;
import com.google.common.base.Function;
import com.google.common.base.Optional;
String moduleLocalNameFromXPath = matcher.group(1);
IdentitySchemaNode moduleIdentity = moduleIdentities.get(moduleLocalNameFromXPath);
unaugmentedModuleIdentities.remove(moduleLocalNameFromXPath);
- checkState(moduleIdentity != null, "Cannot find identity " + moduleLocalNameFromXPath
- + " matching augmentation " + augmentation);
+ checkState(moduleIdentity != null, "Cannot find identity %s matching augmentation %s", moduleLocalNameFromXPath, augmentation);
Map<String, QName> providedServices = findProvidedServices(moduleIdentity, currentModule, qNamesToSIEs,
schemaContext);
- if (moduleIdentity == null) {
- throw new IllegalStateException("Cannot find identity specified by augmentation xpath constraint: "
- + moduleLocalNameFromXPath + " of " + augmentation);
- }
String javaNamePrefix = TypeProviderWrapper.findJavaNamePrefix(moduleIdentity);
Map<String, AttributeIfc> yangToAttributes = null;
}
}
- private void checkUniqueAttributesWithGeneratedClass(final Map<String, QName> uniqueGeneratedClassNames,
+ private static void checkUniqueAttributesWithGeneratedClass(final Map<String, QName> uniqueGeneratedClassNames,
final QName parentQName, final Map<String, AttributeIfc> yangToAttributes) {
for (Map.Entry<String, AttributeIfc> attr : yangToAttributes.entrySet()) {
if (attr.getValue() instanceof TOAttribute) {
}
}
- private void checkUniqueTOAttr(final Map<String, QName> uniqueGeneratedClassNames, final QName parentQName, final TOAttribute attr) {
+ private static void checkUniqueTOAttr(final Map<String, QName> uniqueGeneratedClassNames, final QName parentQName, final TOAttribute attr) {
final String upperCaseCamelCase = attr.getUpperCaseCammelCase();
if (uniqueGeneratedClassNames.containsKey(upperCaseCamelCase)) {
QName firstDefinedQName = uniqueGeneratedClassNames.get(upperCaseCamelCase);
import static com.google.common.base.Preconditions.checkArgument;
import static com.google.common.base.Preconditions.checkState;
-
import com.google.common.annotations.VisibleForTesting;
import com.google.common.base.Function;
import com.google.common.base.Optional;
final List<RuntimeBeanEntry> children, final Set<Rpc> rpcs) {
checkArgument(isRoot == false || keyYangName.isPresent() == false,
- "Root RuntimeBeanEntry must not have key " + "set");
+ "Root RuntimeBeanEntry must not have key set");
this.packageName = packageName;
this.isRoot = isRoot;
this.yangName = yangName;
for (AttributeIfc a : attributes) {
checkState(map.containsKey(a.getAttributeYangName()) == false,
- "Attribute already defined: " + a.getAttributeYangName()
- + " in " + nodeForReporting);
+ "Attribute already defined: %s in %s", a.getAttributeYangName(), nodeForReporting);
map.put(a.getAttributeYangName(), a);
}
if (keyYangName.isPresent()) {
AttributeIfc keyJavaName = map.get(keyYangName.get());
- checkArgument(keyJavaName != null, "Key " + keyYangName.get()
- + " not found in attribute " + "list " + attributes
- + " in " + nodeForReporting);
+ checkArgument(keyJavaName != null, "Key %s not found in attribute list %s in %s", keyYangName.get(),
+ attributes, nodeForReporting);
this.keyJavaName = Optional
.of(keyJavaName.getUpperCaseCammelCase());
} else {
package org.opendaylight.controller.config.yangjmxgenerator;
import static org.hamcrest.CoreMatchers.is;
+import static org.hamcrest.CoreMatchers.isA;
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.mockito.Mockito.doReturn;
import static org.mockito.Mockito.mock;
-
import com.google.common.collect.Sets;
import java.net.URI;
import java.net.URISyntaxException;
is("threadFactory"));
assertThat(threadFactoryAttribute.getUpperCaseCammelCase(),
is("ThreadFactory"));
- assertThat(threadFactoryAttribute.getOpenType(), is(SimpleType.class));
+ assertThat(threadFactoryAttribute.getOpenType(), isA(SimpleType.class));
assertNull(threadFactoryAttribute.getNullableDefault());
assertNull(threadFactoryAttribute.getNullableDescription());
assertThat(threadFactoryAttribute.getType().getName(), is("ObjectName"));
assertThat(toAttr.getAttributeYangName(), is("peer"));
assertThat(toAttr.getLowerCaseCammelCase(), is("peer"));
assertThat(toAttr.getUpperCaseCammelCase(), is("Peer"));
- assertThat(toAttr.getOpenType(), is(CompositeType.class));
+ assertThat(toAttr.getOpenType(), isA(CompositeType.class));
Set<String> propsExpected = new HashSet<String>(2);
propsExpected.add("port");
propsExpected.add("core-size");
is("innerStreamList"));
assertThat(innerStream.getUpperCaseCammelCase(),
is("InnerStreamList"));
- assertThat(innerStream.getOpenType(), is(ArrayType.class));
+ assertThat(innerStream.getOpenType(), isA(ArrayType.class));
}
*.java
+!CheckedAutoCloseable.java
--- /dev/null
+package org.opendaylight.controller.config.yang.test.impl;
+
+import com.google.common.base.Preconditions;
+
+public class CheckedAutoCloseable implements AutoCloseable {
+ private boolean closed = false;
+
+ @Override
+ public synchronized void close() throws Exception {
+ Preconditions.checkState(closed == false);
+ this.closed = true;
+ }
+
+ public synchronized boolean isClosed() {
+ return this.closed;
+ }
+}
- return new AutoCloseable() {
- @Override
- public void close() throws Exception {
- }
- };
+ return new org.opendaylight.controller.config.yang.test.impl.CheckedAutoCloseable();
}
logger.info("IdentityContainer Afi class: {}", getIdentitiesContainer().resolveAfi());
- return new AutoCloseable() {
- @Override
- public void close() throws Exception {
- }
- };
+ return new org.opendaylight.controller.config.yang.test.impl.CheckedAutoCloseable();
- return new AutoCloseable() {
+ return new org.opendaylight.controller.config.yang.test.impl.CheckedAutoCloseable() {
@Override
- public void close() throws Exception {
+ public synchronized void close() throws Exception {
+ if(getSingleDependency() != null && getSingleDependency().isClosed() == true) {
+ // Simulate a cleanup on dependencies that should not be closed yet
+ throw new java.lang.Error("Dependency was closed first");
+ }
+ for (org.opendaylight.controller.config.yang.test.impl.CheckedAutoCloseable autoCloseable : getTestingDepsDependency()) {
+ if(autoCloseable.isClosed() == true) {
+ // Simulate a cleanup on dependencies that should not be closed yet
+ throw new java.lang.Error("Dependency was closed first");
+ }
+ }
+ super.close();
}
- };
+ };
\ No newline at end of file
- return org.opendaylight.controller.config.yang.test.util.NetconfTestImplModuleUtil.registerRuntimeBeans(this);
+ final AutoCloseable runtime = org.opendaylight.controller.config.yang.test.util.NetconfTestImplModuleUtil.registerRuntimeBeans(this);
+ return new org.opendaylight.controller.config.yang.test.impl.CheckedAutoCloseable() {
+ @Override
+ public synchronized void close() throws Exception {
+ runtime.close();
+ }
+ };
\ No newline at end of file
- return new AutoCloseable() {
- @Override
- public void close() throws Exception {
- }
- };
+ return new org.opendaylight.controller.config.yang.test.impl.CheckedAutoCloseable();
\ No newline at end of file
}
}
}
+
}
+
}
}
}
}
}
+ container single {
+ uses config:service-ref {
+ refine type {
+ mandatory false;
+ config:required-identity test:testing;
+ }
+ }
+ }
+
+ leaf simple {
+ type boolean;
+ default false;
+ }
}
}
}
"Test api";
base "config:service-type";
- config:java-class "java.lang.AutoCloseable";
+ config:java-class "org.opendaylight.controller.config.yang.test.impl.CheckedAutoCloseable";
}
}
import static java.util.Arrays.asList;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNull;
+import static org.junit.Assert.assertThat;
+import static org.junit.Assert.fail;
import static org.opendaylight.controller.config.api.jmx.ObjectNameUtil.getInstanceName;
import static org.opendaylight.controller.config.api.jmx.ObjectNameUtil.getTransactionName;
import java.util.List;
import javax.management.ObjectName;
+import org.hamcrest.CoreMatchers;
import org.junit.Before;
import org.junit.Test;
+import org.opendaylight.controller.config.api.ValidationException;
import org.opendaylight.controller.config.manager.impl.AbstractConfigTest;
import org.opendaylight.controller.config.manager.impl.factoriesresolver.HardcodedModuleFactoriesResolver;
import org.opendaylight.controller.config.util.ConfigTransactionJMXClient;
assertNull(getTransactionName(d1WithoutTxName));
transaction.commit();
}
+
+ @Test
+ public void testCloseOrdering() throws Exception {
+ // Tests whether close is called in correct order on the module instances on following graph
+ // Each module tests whether its dependencies were closed before it (to simulate resource clean up failure)
+ // R1
+ // | \
+ // M1 M2
+ // |
+ // L1
+ ConfigTransactionJMXClient transaction = configRegistryClient.createTransaction();
+ ObjectName r1 = transaction.createModule(factory.getImplementationName(), "root1");
+ ObjectName m1 = transaction.createModule(factory.getImplementationName(), "middle1");
+ ObjectName m2 = transaction.createModule(factory.getImplementationName(), "middle2");
+ ObjectName l1 = transaction.createModule(factory.getImplementationName(), "leaf1");
+
+ MultipleDependenciesModuleMXBean r1Proxy = transaction.newMXBeanProxy(r1, MultipleDependenciesModuleMXBean.class);
+ MultipleDependenciesModuleMXBean i1Proxy = transaction.newMXBeanProxy(m1, MultipleDependenciesModuleMXBean.class);
+ r1Proxy.setSingle(m1);
+ i1Proxy.setSingle(l1);
+ r1Proxy.setTestingDeps(asList(m2));
+ transaction.commit();
+
+ configRegistryClient.createTransaction().commit();
+ transaction = configRegistryClient.createTransaction();
+ MultipleDependenciesModuleMXBean l1Proxy = transaction.newMXBeanProxy(l1, MultipleDependenciesModuleMXBean.class);
+ l1Proxy.setSimple(true);
+ transaction.commit();
+ }
+
+ @Test
+ public void testDestroyModuleDependency() throws Exception {
+ ConfigTransactionJMXClient transaction = configRegistryClient.createTransaction();
+ ObjectName r1 = transaction.createModule(factory.getImplementationName(), "root1");
+ ObjectName m1 = transaction.createModule(factory.getImplementationName(), "middle1");
+
+ MultipleDependenciesModuleMXBean r1Proxy = transaction.newMXBeanProxy(r1, MultipleDependenciesModuleMXBean.class);
+ r1Proxy.setSingle(m1);
+ transaction.commit();
+
+ transaction = configRegistryClient.createTransaction();
+ transaction.destroyModule(factory.getImplementationName(), "middle1");
+ try {
+ transaction.commit();
+ fail("Validation exception expected");
+ } catch (ValidationException e) {
+ assertThat(e.getFailedValidations().keySet(), CoreMatchers.hasItem("multiple-dependencies"));
+ }
+ }
}
private int currentRecoveryBatchCount;
+
+
public RaftActor(String id, Map<String, String> peerAddresses) {
this(id, peerAddresses, Optional.<ConfigParams>absent());
}
if (oldBehavior != currentBehavior){
onStateChanged();
}
- if (oldBehavior != null) {
- // it can happen that the state has not changed but the leader has changed.
- onLeaderChanged(oldBehavior.getLeaderId(), currentBehavior.getLeaderId());
- if (getRoleChangeNotifier().isPresent() && oldBehavior.state() != currentBehavior.state()) {
- // we do not want to notify when the behavior/role is set for the first time (i.e follower)
- getRoleChangeNotifier().get().tell(new RoleChanged(getId(), oldBehavior.state().name(),
- currentBehavior.state().name()), getSelf());
- }
+ String oldBehaviorLeaderId = oldBehavior == null? null : oldBehavior.getLeaderId();
+ String oldBehaviorState = oldBehavior == null? null : oldBehavior.state().name();
+
+ // it can happen that the state has not changed but the leader has changed.
+ onLeaderChanged(oldBehaviorLeaderId, currentBehavior.getLeaderId());
+
+ if (getRoleChangeNotifier().isPresent() &&
+ (oldBehavior == null || (oldBehavior.state() != currentBehavior.state()))) {
+ getRoleChangeNotifier().get().tell(
+ new RoleChanged(getId(), oldBehaviorState , currentBehavior.state().name()),
+ getSelf());
}
}
* @param identifier
* @param data
*/
- protected void persistData(ActorRef clientActor, String identifier,
- Payload data) {
+ protected void persistData(final ActorRef clientActor, final String identifier,
+ final Payload data) {
ReplicatedLogEntry replicatedLogEntry = new ReplicatedLogImplEntry(
context.getReplicatedLog().lastIndex() + 1,
LOG.debug("Persist data {}", replicatedLogEntry);
}
+ final RaftActorContext raftContext = getRaftActorContext();
+
replicatedLog
- .appendAndPersist(clientActor, identifier, replicatedLogEntry);
- }
+ .appendAndPersist(replicatedLogEntry, new Procedure<ReplicatedLogEntry>() {
+ @Override
+ public void apply(ReplicatedLogEntry replicatedLogEntry) throws Exception {
+ if(!hasFollowers()){
+ // Increment the Commit Index and the Last Applied values
+ raftContext.setCommitIndex(replicatedLogEntry.getIndex());
+ raftContext.setLastApplied(replicatedLogEntry.getIndex());
+
+ // Apply the state immediately
+ applyState(clientActor, identifier, data);
+
+ // Send a ApplyLogEntries message so that we write the fact that we applied
+ // the state to durable storage
+ self().tell(new ApplyLogEntries((int) replicatedLogEntry.getIndex()), self());
+
+ // Check if the "real" snapshot capture has been initiated. If no then do the fake snapshot
+ if(!hasSnapshotCaptureInitiated){
+ raftContext.getReplicatedLog().snapshotPreCommit(raftContext.getLastApplied(),
+ raftContext.getTermInformation().getCurrentTerm());
+ raftContext.getReplicatedLog().snapshotCommit();
+ } else {
+ LOG.debug("Skipping fake snapshotting for {} because real snapshotting is in progress", getId());
+ }
+ } else if (clientActor != null) {
+ // Send message for replication
+ currentBehavior.handleMessage(getSelf(),
+ new Replicate(clientActor, identifier,
+ replicatedLogEntry)
+ );
+ }
+
+ }
+ }); }
protected String getId() {
return context.getId();
hasSnapshotCaptureInitiated = false;
}
+ protected boolean hasFollowers(){
+ return getRaftActorContext().getPeerAddresses().keySet().size() > 0;
+ }
+
private class ReplicatedLogImpl extends AbstractReplicatedLogImpl {
+ private static final int DATA_SIZE_DIVIDER = 5;
+ private long dataSizeSinceLastSnapshot = 0;
+
public ReplicatedLogImpl(Snapshot snapshot) {
super(snapshot.getLastAppliedIndex(), snapshot.getLastAppliedTerm(),
snapshot.getUnAppliedEntries());
@Override public void appendAndPersist(
final ReplicatedLogEntry replicatedLogEntry) {
- appendAndPersist(null, null, replicatedLogEntry);
+ appendAndPersist(replicatedLogEntry, null);
}
@Override
return dataSize;
}
- public void appendAndPersist(final ActorRef clientActor,
- final String identifier,
- final ReplicatedLogEntry replicatedLogEntry) {
+ public void appendAndPersist(
+ final ReplicatedLogEntry replicatedLogEntry,
+ final Procedure<ReplicatedLogEntry> callback) {
if(LOG.isDebugEnabled()) {
LOG.debug("Append log entry and persist {} ", replicatedLogEntry);
new Procedure<ReplicatedLogEntry>() {
@Override
public void apply(ReplicatedLogEntry evt) throws Exception {
- dataSize += replicatedLogEntry.size();
+ int logEntrySize = replicatedLogEntry.size();
+
+ dataSize += logEntrySize;
+ long dataSizeForCheck = dataSize;
+
+ dataSizeSinceLastSnapshot += logEntrySize;
+ long journalSize = lastIndex()+1;
+
+ if(!hasFollowers()) {
+ // When we do not have followers we do not maintain an in-memory log
+ // due to this the journalSize will never become anything close to the
+ // snapshot batch count. In fact will mostly be 1.
+ // Similarly since the journal's dataSize depends on the entries in the
+ // journal the journal's dataSize will never reach a value close to the
+ // memory threshold.
+ // By maintaining the dataSize outside the journal we are tracking essentially
+ // what we have written to the disk however since we no longer are in
+ // need of doing a snapshot just for the sake of freeing up memory we adjust
+ // the real size of data by the DATA_SIZE_DIVIDER so that we do not snapshot as often
+ // as if we were maintaining a real snapshot
+ dataSizeForCheck = dataSizeSinceLastSnapshot / DATA_SIZE_DIVIDER;
+ }
long dataThreshold = Runtime.getRuntime().totalMemory() *
getRaftActorContext().getConfigParams().getSnapshotDataThresholdPercentage() / 100;
// when a snaphsot is being taken, captureSnapshot != null
if (hasSnapshotCaptureInitiated == false &&
- ( journal.size() % context.getConfigParams().getSnapshotBatchCount() == 0 ||
- dataSize > dataThreshold)) {
+ ( journalSize % context.getConfigParams().getSnapshotBatchCount() == 0 ||
+ dataSizeForCheck > dataThreshold)) {
+
+ dataSizeSinceLastSnapshot = 0;
LOG.info("Initiating Snapshot Capture..");
long lastAppliedIndex = -1;
long lastAppliedTerm = -1;
ReplicatedLogEntry lastAppliedEntry = get(context.getLastApplied());
- if (lastAppliedEntry != null) {
+ if (!hasFollowers()) {
+ lastAppliedIndex = replicatedLogEntry.getIndex();
+ lastAppliedTerm = replicatedLogEntry.getTerm();
+ } else if (lastAppliedEntry != null) {
lastAppliedIndex = lastAppliedEntry.getIndex();
lastAppliedTerm = lastAppliedEntry.getTerm();
}
null);
hasSnapshotCaptureInitiated = true;
}
- // Send message for replication
- if (clientActor != null) {
- currentBehavior.handleMessage(getSelf(),
- new Replicate(clientActor, identifier,
- replicatedLogEntry)
- );
+ if(callback != null){
+ callback.apply(replicatedLogEntry);
}
}
}
TestActorRef<MockRaftActor> mockActorRef = TestActorRef.create(getSystem(), MockRaftActor.props(id,
Collections.<String,String>emptyMap(), Optional.<ConfigParams>of(config), notifierActor), id);
- MockRaftActor mockRaftActor = mockActorRef.underlyingActor();
- mockRaftActor.setCurrentBehavior(new Follower(mockRaftActor.getRaftActorContext()));
-
// sleeping for a minimum of 2 seconds, if it spans more its fine.
Uninterruptibles.sleepUninterruptibly(2, TimeUnit.SECONDS);
List<Object> matches = MessageCollectorActor.getAllMatching(notifierActor, RoleChanged.class);
assertNotNull(matches);
- assertEquals(2, matches.size());
+ assertEquals(3, matches.size());
- // check if the notifier got a role change from Follower to Candidate
+ // check if the notifier got a role change from null to Follower
RoleChanged raftRoleChanged = (RoleChanged) matches.get(0);
assertEquals(id, raftRoleChanged.getMemberId());
+ assertNull(raftRoleChanged.getOldRole());
+ assertEquals(RaftState.Follower.name(), raftRoleChanged.getNewRole());
+
+ // check if the notifier got a role change from Follower to Candidate
+ raftRoleChanged = (RoleChanged) matches.get(1);
+ assertEquals(id, raftRoleChanged.getMemberId());
assertEquals(RaftState.Follower.name(), raftRoleChanged.getOldRole());
assertEquals(RaftState.Candidate.name(), raftRoleChanged.getNewRole());
// check if the notifier got a role change from Candidate to Leader
- raftRoleChanged = (RoleChanged) matches.get(1);
+ raftRoleChanged = (RoleChanged) matches.get(2);
assertEquals(id, raftRoleChanged.getMemberId());
assertEquals(RaftState.Candidate.name(), raftRoleChanged.getOldRole());
assertEquals(RaftState.Leader.name(), raftRoleChanged.getNewRole());
--- /dev/null
+/*
+ * Copyright (c) 2014 Cisco Systems, Inc. and others. All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+package org.opendaylight.controller.md.sal.binding.api;
+
+import java.util.concurrent.TimeUnit;
+import org.opendaylight.yangtools.yang.binding.Notification;
+
+/**
+ * A {@link NotificationService} which also allows its users to
+ * submit YANG-modeled notifications for delivery. There are three
+ * methods of submission, following the patters from {@link java.util.concurrent.BlockingQueue}:
+ * - {@link #putNotification(Notification)}, which may block indefinitely
+ * if the implementation cannot allocate resources to accept the notification,
+ * - {@link #offerNotification(Notification)}, which does not block if face
+ * of resource starvation,
+ * - {@link #offerNotification(Notification, int, TimeUnit)}, which may block
+ * for specified time if resources are thin.
+ *
+ * The actual delivery to listeners is asynchronous and implementation-specific.
+ * Users of this interface should not make any assumptions as to whether the
+ * notification has or has not been seen.
+ */
+public interface NotificationPublishService extends BindingService {
+ /**
+ * Publishes a notification to subscribed listeners. This initiates
+ * the process of sending the notification, but delivery to the
+ * listeners can happen asynchronously, potentially after a call to
+ * this method returns.
+ *
+ * <b>Note:</b> This call will block when the notification queue is full.
+ *
+ * @param notification
+ * the notification to publish.
+ * @throws InterruptedException if interrupted while waiting
+ * @throws NullPointerException if the notification is null
+ */
+ void putNotification(Notification notification) throws InterruptedException;
+
+ /**
+ * Publishes a notification to subscribed listeners. This initiates
+ * the process of sending the notification, but delivery to the
+ * listeners can happen asynchronously, potentially after a call to
+ * this method returns.
+ *
+ * This method is guaranteed not to block.
+ *
+ * @param notification
+ * the notification to publish.
+ * @return true if the notification was accepted for processing, false otherwise
+ * @throws NullPointerException if the notification is null
+ */
+ boolean offerNotification(Notification notification);
+
+ /**
+ * Publishes a notification to subscribed listeners. This initiates
+ * the process of sending the notification, but delivery to the
+ * listeners can happen asynchronously, potentially after a call to
+ * this method returns. This method is guaranteed not to block more
+ * than the specified timeout.
+ *
+ * @param notification
+ * the notification to publish.
+ * @param timeout how long to wait before giving up, in units of unit
+ * @param unit a TimeUnit determining how to interpret the
+ * timeout parameter
+ * @return true if the notification was accepted for processing, false otherwise
+ * @throws InterruptedException if interrupted while waiting
+ * @throws NullPointerException if the notification or unit is null
+ * @throws IllegalArgumentException if timeout is negative.
+ */
+ boolean offerNotification(Notification notification, int timeout, TimeUnit unit)
+ throws InterruptedException;
+}
--- /dev/null
+/*
+ * Copyright (c) 2014 Cisco Systems, Inc. and others. All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+package org.opendaylight.controller.md.sal.binding.api;
+
+import org.opendaylight.yangtools.concepts.ListenerRegistration;
+import org.opendaylight.yangtools.yang.binding.NotificationListener;
+
+/**
+ * Notification broker which allows clients to subscribe for and publish YANG-modeled notifications.
+ *
+ * Each YANG module which defines notifications results in a generated interface <code>{ModuleName}Listener</code>
+ * which handles all the notifications defined in the YANG model. Each notification type translates to
+ * a specific method of the form <code>on{NotificationType}</code> on the generated interface.
+ * The generated interface also extends the
+ * {@link org.opendaylight.yangtools.yang.binding.NotificationListener} interface and implementations
+ * are registered using {@link #registerNotificationListener(org.opendaylight.yangtools.yang.binding.NotificationListener)}
+ * method.
+ *
+ * <h5>Dispatch Listener Example</h5>
+ * <p>
+ * Lets assume we have following YANG model:
+ *
+ * <pre>
+ * module example {
+ * ...
+ *
+ * notification start {
+ * ...
+ * }
+ *
+ * notification stop {
+ * ...
+ * }
+ * }
+ * </pre>
+ *
+ * The generated interface will be:
+ * <pre>
+ * public interface ExampleListener extends NotificationListener {
+ * void onStart(Start notification);
+ * void onStop(Stop notification);
+ * }
+ * </pre>
+ * The following defines an implementation of the generated interface:
+ * <pre>
+ * public class MyExampleListener implements ExampleListener {
+ * public void onStart(Start notification) {
+ * // do something
+ * }
+ *
+ * public void onStop(Stop notification) {
+ * // do something
+ * }
+ * }
+ * </pre>
+ * The implementation is registered as follows:
+ * <pre>
+ * MyExampleListener listener = new MyExampleListener();
+ * ListenerRegistration<NotificationListener> reg = service.registerNotificationListener( listener );
+ * </pre>
+ * The <code>onStart</code> method will be invoked when someone publishes a <code>Start</code> notification and
+ * the <code>onStop</code> method will be invoked when someone publishes a <code>Stop</code> notification.
+ */
+public interface NotificationService extends BindingService {
+ /**
+ * Registers a listener which implements a YANG-generated notification interface derived from
+ * {@link NotificationListener}. The listener is registered for all notifications present in
+ * the implemented interface.
+ *
+ * @param listener the listener implementation that will receive notifications.
+ * @return a {@link ListenerRegistration} instance that should be used to unregister the listener
+ * by invoking the {@link ListenerRegistration#close()} method when no longer needed.
+ */
+ <T extends NotificationListener> ListenerRegistration<T> registerNotificationListener(T listener);
+}
private Cancellable txCommitTimeoutCheckSchedule;
- private Optional<ActorRef> roleChangeNotifier;
+ private final Optional<ActorRef> roleChangeNotifier;
/**
* Coordinates persistence recovery on startup.
// currently uses a same thread executor anyway.
cohortEntry.getCohort().preCommit().get();
- Shard.this.persistData(getSender(), transactionID,
- new CompositeModificationByteStringPayload(cohortEntry.getModification().toSerializable()));
+ // If we do not have any followers and we are not using persistence we can
+ // apply modification to the state immediately
+ if(!hasFollowers() && !persistence().isRecoveryApplicable()){
+ applyModificationToState(getSender(), transactionID, cohortEntry.getModification());
+ } else {
+ Shard.this.persistData(getSender(), transactionID,
+ new CompositeModificationByteStringPayload(cohortEntry.getModification().toSerializable()));
+ }
} catch (InterruptedException | ExecutionException e) {
LOG.error(e, "An exception occurred while preCommitting transaction {}",
cohortEntry.getTransactionID());
doAbortTransaction(abort.getTransactionID(), getSender());
}
- private void doAbortTransaction(final String transactionID, final ActorRef sender) {
+ void doAbortTransaction(final String transactionID, final ActorRef sender) {
final CohortEntry cohortEntry = commitCoordinator.getCohortEntryIfCurrent(transactionID);
if(cohortEntry != null) {
LOG.debug("Aborting transaction {}", transactionID);
new JavaTestKit(getSystem()) {{
final ActorRef shardManager = getSystem().actorOf(newShardMgrProps());
- shardManager.tell(new UpdateSchemaContext(TestModel.createTestContext()), getRef());
-
shardManager.tell(new FindPrimary(Shard.DEFAULT_NAME, false).toSerializable(), getRef());
expectMsgClass(duration("5 seconds"), ActorNotInitialized.class);
new JavaTestKit(getSystem()) {{
final ActorRef shardManager = getSystem().actorOf(newShardMgrProps());
- shardManager.tell(new UpdateSchemaContext(TestModel.createTestContext()), getRef());
-
shardManager.tell(new FindLocalShard(Shard.DEFAULT_NAME, false), getRef());
expectMsgClass(duration("5 seconds"), ActorNotInitialized.class);
import org.mockito.InOrder;
import org.mockito.invocation.InvocationOnMock;
import org.mockito.stubbing.Answer;
+import org.opendaylight.controller.cluster.datastore.DatastoreContext.Builder;
import org.opendaylight.controller.cluster.datastore.identifiers.ShardIdentifier;
import org.opendaylight.controller.cluster.datastore.messages.AbortTransaction;
import org.opendaylight.controller.cluster.datastore.messages.AbortTransactionReply;
private final ShardIdentifier shardID = ShardIdentifier.builder().memberName("member-1")
.shardName("inventory").type("config" + NEXT_SHARD_NUM.getAndIncrement()).build();
- private DatastoreContext dataStoreContext = DatastoreContext.newBuilder().
+ private final Builder dataStoreContextBuilder = DatastoreContext.newBuilder().
shardJournalRecoveryLogBatchSize(3).shardSnapshotBatchCount(5000).
- shardHeartbeatIntervalInMillis(100).build();
+ shardHeartbeatIntervalInMillis(100);
@Before
public void setUp() {
+ Builder newBuilder = DatastoreContext.newBuilder();
InMemorySnapshotStore.clear();
InMemoryJournal.clear();
}
InMemoryJournal.clear();
}
+ private DatastoreContext newDatastoreContext() {
+ return dataStoreContextBuilder.build();
+ }
+
private Props newShardProps() {
return Shard.props(shardID, Collections.<ShardIdentifier,String>emptyMap(),
- dataStoreContext, SCHEMA_CONTEXT);
+ newDatastoreContext(), SCHEMA_CONTEXT);
}
@Test
@Override
public Shard create() throws Exception {
return new Shard(shardID, Collections.<ShardIdentifier,String>emptyMap(),
- dataStoreContext, SCHEMA_CONTEXT) {
+ newDatastoreContext(), SCHEMA_CONTEXT) {
@Override
public void onReceiveCommand(final Object message) throws Exception {
if(message instanceof ElectionTimeout && firstElectionTimeout) {
class TestShard extends Shard {
TestShard() {
super(shardID, Collections.<ShardIdentifier, String>singletonMap(shardID, null),
- dataStoreContext, SCHEMA_CONTEXT);
+ newDatastoreContext(), SCHEMA_CONTEXT);
}
Map<String, String> getPeerAddresses() {
@Override
public Shard create() throws Exception {
return new Shard(shardID, Collections.<ShardIdentifier,String>emptyMap(),
- dataStoreContext, SCHEMA_CONTEXT) {
+ newDatastoreContext(), SCHEMA_CONTEXT) {
@Override
protected void onRecoveryComplete() {
try {
assertTrue("Missing leaf " + TestModel.ID_QNAME.getLocalName(), idLeaf.isPresent());
assertEquals(TestModel.ID_QNAME.getLocalName() + " value", 1, idLeaf.get().getValue());
- for(int i = 0; i < 20 * 5; i++) {
- long lastLogIndex = shard.underlyingActor().getShardMBean().getLastLogIndex();
- if(lastLogIndex == 2) {
- break;
- }
- Uninterruptibles.sleepUninterruptibly(50, TimeUnit.MILLISECONDS);
+ verifyLastLogIndex(shard, 2);
+
+ shard.tell(PoisonPill.getInstance(), ActorRef.noSender());
+ }};
+ }
+
+ private void verifyLastLogIndex(TestActorRef<Shard> shard, long expectedValue) {
+ for(int i = 0; i < 20 * 5; i++) {
+ long lastLogIndex = shard.underlyingActor().getShardMBean().getLastLogIndex();
+ if(lastLogIndex == expectedValue) {
+ break;
}
+ Uninterruptibles.sleepUninterruptibly(50, TimeUnit.MILLISECONDS);
+ }
+
+ assertEquals("Last log index", expectedValue, shard.underlyingActor().getShardMBean().getLastLogIndex());
+ }
+
+ @Test
+ public void testCommitWithPersistenceDisabled() throws Throwable {
+ dataStoreContextBuilder.persistent(false);
+ new ShardTestKit(getSystem()) {{
+ final TestActorRef<Shard> shard = TestActorRef.create(getSystem(),
+ newShardProps().withDispatcher(Dispatchers.DefaultDispatcherId()),
+ "testCommitPhaseFailure");
- assertEquals("Last log index", 2, shard.underlyingActor().getShardMBean().getLastLogIndex());
+ waitUntilLeader(shard);
+
+ InMemoryDOMDataStore dataStore = shard.underlyingActor().getDataStore();
+
+ // Setup a simulated transactions with a mock cohort.
+
+ String transactionID = "tx";
+ MutableCompositeModification modification = new MutableCompositeModification();
+ NormalizedNode<?, ?> containerNode = ImmutableNodes.containerNode(TestModel.TEST_QNAME);
+ DOMStoreThreePhaseCommitCohort cohort = setupMockWriteTransaction("cohort", dataStore,
+ TestModel.TEST_PATH, containerNode, modification);
+
+ FiniteDuration duration = duration("5 seconds");
+
+ // Simulate the ForwardedReadyTransaction messages that would be sent
+ // by the ShardTransaction.
+
+ shard.tell(new ForwardedReadyTransaction(transactionID, CURRENT_VERSION,
+ cohort, modification, true), getRef());
+ expectMsgClass(duration, ReadyTransactionReply.SERIALIZABLE_CLASS);
+
+ // Send the CanCommitTransaction message.
+
+ shard.tell(new CanCommitTransaction(transactionID).toSerializable(), getRef());
+ CanCommitTransactionReply canCommitReply = CanCommitTransactionReply.fromSerializable(
+ expectMsgClass(duration, CanCommitTransactionReply.SERIALIZABLE_CLASS));
+ assertEquals("Can commit", true, canCommitReply.getCanCommit());
+
+ // Send the CanCommitTransaction message.
+
+ shard.tell(new CommitTransaction(transactionID).toSerializable(), getRef());
+ expectMsgClass(duration, CommitTransactionReply.SERIALIZABLE_CLASS);
+
+ InOrder inOrder = inOrder(cohort);
+ inOrder.verify(cohort).canCommit();
+ inOrder.verify(cohort).preCommit();
+ inOrder.verify(cohort).commit();
+
+ NormalizedNode<?, ?> actualNode = readStore(shard, TestModel.TEST_PATH);
+ assertEquals(TestModel.TEST_QNAME.getLocalName(), containerNode, actualNode);
shard.tell(PoisonPill.getInstance(), ActorRef.noSender());
}};
waitUntilLeader(shard);
final FiniteDuration duration = duration("5 seconds");
- final Timeout timeout = new Timeout(duration);
-
InMemoryDOMDataStore dataStore = shard.underlyingActor().getDataStore();
final String transactionID = "tx1";
- final CountDownLatch abortComplete = new CountDownLatch(1);
Function<DOMStoreThreePhaseCommitCohort,ListenableFuture<Void>> preCommit =
new Function<DOMStoreThreePhaseCommitCohort,ListenableFuture<Void>>() {
@Override
public ListenableFuture<Void> apply(final DOMStoreThreePhaseCommitCohort cohort) {
ListenableFuture<Void> preCommitFuture = cohort.preCommit();
- Future<Object> abortFuture = Patterns.ask(shard,
- new AbortTransaction(transactionID).toSerializable(), timeout);
- abortFuture.onComplete(new OnComplete<Object>() {
- @Override
- public void onComplete(final Throwable e, final Object resp) {
- abortComplete.countDown();
- }
- }, getSystem().dispatcher());
+ // Simulate an AbortTransaction message occurring during replication, after
+ // persisting and before finishing the commit to the in-memory store.
+ // We have no followers so due to optimizations in the RaftActor, it does not
+ // attempt replication and thus we can't send an AbortTransaction message b/c
+ // it would be processed too late after CommitTransaction completes. So we'll
+ // simulate an AbortTransaction message occurring during replication by calling
+ // the shard directly.
+ //
+ shard.underlyingActor().doAbortTransaction(transactionID, null);
return preCommitFuture;
}
expectMsgClass(duration, CanCommitTransactionReply.SERIALIZABLE_CLASS));
assertEquals("Can commit", true, canCommitReply.getCanCommit());
- Future<Object> commitFuture = Patterns.ask(shard,
- new CommitTransaction(transactionID).toSerializable(), timeout);
-
- assertEquals("Abort complete", true, abortComplete.await(5, TimeUnit.SECONDS));
-
- Await.result(commitFuture, duration);
+ shard.tell(new CommitTransaction(transactionID).toSerializable(), getRef());
+ expectMsgClass(duration, CommitTransactionReply.SERIALIZABLE_CLASS);
NormalizedNode<?, ?> node = readStore(shard, TestModel.TEST_PATH);
+
+ // Since we're simulating an abort occurring during replication and before finish commit,
+ // the data should still get written to the in-memory store since we've gotten past
+ // canCommit and preCommit and persisted the data.
assertNotNull(TestModel.TEST_QNAME.getLocalName() + " not found", node);
shard.tell(PoisonPill.getInstance(), ActorRef.noSender());
@Test
public void testTransactionCommitTimeout() throws Throwable {
- dataStoreContext = DatastoreContext.newBuilder().shardTransactionCommitTimeoutInSeconds(1).build();
+ dataStoreContextBuilder.shardTransactionCommitTimeoutInSeconds(1);
new ShardTestKit(getSystem()) {{
final TestActorRef<Shard> shard = TestActorRef.create(getSystem(),
@Test
public void testTransactionCommitQueueCapacityExceeded() throws Throwable {
- dataStoreContext = DatastoreContext.newBuilder().shardTransactionCommitQueueCapacity(1).build();
+ dataStoreContextBuilder.shardTransactionCommitQueueCapacity(1);
new ShardTestKit(getSystem()) {{
final TestActorRef<Shard> shard = TestActorRef.create(getSystem(),
// Wait for the 2nd Tx to complete the canCommit phase.
- final CountDownLatch latch = new CountDownLatch(1);
- canCommitFuture.onComplete(new OnComplete<Object>() {
- @Override
- public void onComplete(final Throwable t, final Object resp) {
- latch.countDown();
- }
- }, getSystem().dispatcher());
-
- assertEquals("2nd CanCommit complete", true, latch.await(5, TimeUnit.SECONDS));
+ Await.ready(canCommitFuture, duration);
InOrder inOrder = inOrder(cohort1, cohort2);
inOrder.verify(cohort1).canCommit();
@Override
public Shard create() throws Exception {
return new Shard(shardID, Collections.<ShardIdentifier,String>emptyMap(),
- dataStoreContext, SCHEMA_CONTEXT) {
+ newDatastoreContext(), SCHEMA_CONTEXT) {
@Override
protected void commitSnapshot(final long sequenceNumber) {
super.commitSnapshot(sequenceNumber);
import org.opendaylight.controller.sal.core.api.RpcProvisionRegistry;
import org.opendaylight.controller.sal.core.api.data.DataBrokerService;
import org.opendaylight.controller.sal.core.api.data.DataProviderService;
-import org.opendaylight.controller.sal.core.api.data.DataStore;
import org.opendaylight.controller.sal.core.api.model.SchemaService;
import org.opendaylight.controller.sal.core.api.mount.MountProvisionService;
import org.opendaylight.controller.sal.core.api.mount.MountService;
import org.opendaylight.controller.sal.dom.broker.BackwardsCompatibleMountPointManager;
import org.opendaylight.controller.sal.dom.broker.BrokerImpl;
-import org.opendaylight.controller.sal.dom.broker.DataBrokerImpl;
import org.opendaylight.controller.sal.dom.broker.GlobalBundleScanningSchemaServiceImpl;
-import org.opendaylight.controller.sal.dom.broker.impl.SchemaAwareDataStoreAdapter;
import org.opendaylight.controller.sal.dom.broker.impl.SchemaAwareRpcBroker;
import org.opendaylight.controller.sal.dom.broker.impl.SchemaContextProviders;
-import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier;
/**
*
@Override
public java.lang.AutoCloseable createInstance() {
- final DataStore legacyStore = getDataStoreDependency();
final DOMDataBroker asyncBroker= getAsyncDataBrokerDependency();
- ClassToInstanceMap<BrokerService> services = MutableClassToInstanceMap.create();
+ final ClassToInstanceMap<BrokerService> services = MutableClassToInstanceMap.create();
- SchemaService schemaService = getSchemaServiceImpl();
+ final SchemaService schemaService = getSchemaServiceImpl();
services.putInstance(SchemaService.class, schemaService);
- SchemaAwareRpcBroker router = new SchemaAwareRpcBroker("/", SchemaContextProviders
+ final SchemaAwareRpcBroker router = new SchemaAwareRpcBroker("/", SchemaContextProviders
.fromSchemaService(schemaService));
services.putInstance(RpcProvisionRegistry.class, router);
- final DataProviderService legacyData;
- if(asyncBroker != null) {
- services.putInstance(DOMDataBroker.class, asyncBroker);
- legacyData = new BackwardsCompatibleDataBroker(asyncBroker,schemaService);
- } else {
- legacyData = createLegacyDataService(legacyStore,schemaService);
- }
+ services.putInstance(DOMDataBroker.class, asyncBroker);
+ final DataProviderService legacyData = new BackwardsCompatibleDataBroker(asyncBroker,schemaService);
services.putInstance(DataProviderService.class,legacyData);
services.putInstance(DataBrokerService.class, legacyData);
return new BrokerImpl(router, services);
}
- @Deprecated
- private DataProviderService createLegacyDataService(final DataStore legacyStore, final SchemaService schemaService) {
- YangInstanceIdentifier rootPath = YangInstanceIdentifier.builder().toInstance();
- DataBrokerImpl dataService = new DataBrokerImpl();
- SchemaAwareDataStoreAdapter wrappedStore = new SchemaAwareDataStoreAdapter();
- wrappedStore.changeDelegate(legacyStore);
- wrappedStore.setValidationEnabled(false);
-
- schemaService.registerSchemaContextListener(wrappedStore);
-
- dataService.registerConfigurationReader(rootPath, wrappedStore);
- dataService.registerCommitHandler(rootPath, wrappedStore);
- dataService.registerOperationalReader(rootPath, wrappedStore);
- return dataService;
- }
-
private SchemaService getSchemaServiceImpl() {
final SchemaService schemaService;
if(getRootSchemaService() != null) {
*/
private static final AtomicReferenceFieldUpdater<PingPongTransactionChain, PingPongTransaction> READY_UPDATER =
AtomicReferenceFieldUpdater.newUpdater(PingPongTransactionChain.class, PingPongTransaction.class, "readyTx");
- @SuppressWarnings("unused") // Accessed via READY_UPDATER
private volatile PingPongTransaction readyTx;
/**
return oldTx;
}
- // This forces allocateTransaction() on a slow path
+ /*
+ * This forces allocateTransaction() on a slow path, which has to happen after
+ * this method has completed executing.
+ */
@GuardedBy("this")
private void processIfReady() {
final PingPongTransaction tx = READY_UPDATER.getAndSet(this, null);
}
private void readyTransaction(final @Nonnull PingPongTransaction tx) {
+ // First mark the transaction as not locked.
final boolean lockedMatch = LOCKED_UPDATER.compareAndSet(this, tx, null);
Preconditions.checkState(lockedMatch, "Attempted to submit transaction %s while we have %s", tx, lockedTx);
-
LOG.debug("Transaction {} unlocked", tx);
+ /*
+ * The transaction is ready. It will then be picked up by either next allocation,
+ * or a background transaction completion callback.
+ */
+ final boolean success = READY_UPDATER.compareAndSet(this, null, tx);
+ Preconditions.checkState(success, "Transaction %s collided on ready state", tx, readyTx);
+ LOG.debug("Transaction {} readied");
+
+ /*
+ * We do not see a transaction being in-flight, so we need to take care of dispatching
+ * the transaction to the backend. We are in the ready case, we cannot short-cut
+ * the checking of readyTx, as an in-flight transaction may have completed between us
+ * setting the field above and us checking.
+ */
if (inflightTx == null) {
synchronized (this) {
- processTransaction(tx);
+ processIfReady();
}
}
}
+++ /dev/null
-/*
- * Copyright (c) 2014 Cisco Systems, Inc. and others. All rights reserved.
- *
- * This program and the accompanying materials are made available under the
- * terms of the Eclipse Public License v1.0 which accompanies this distribution,
- * and is available at http://www.eclipse.org/legal/epl-v10.html
- */
-package org.opendaylight.controller.sal.dom.broker.impl;
-
-import java.util.concurrent.atomic.AtomicLong;
-
-import org.opendaylight.controller.md.sal.common.api.data.DataModification;
-import org.opendaylight.controller.sal.core.api.data.DataStore;
-import org.opendaylight.yangtools.concepts.Delegator;
-import org.opendaylight.yangtools.yang.data.api.CompositeNode;
-import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier;
-
-@Deprecated
-public class DataStoreStatsWrapper implements Delegator<DataStore>, DataStore {
-
- private final DataStore delegate;
-
- private AtomicLong cfgReadCount = new AtomicLong();
- private AtomicLong cfgReadTimeTotal = new AtomicLong();
-
- private AtomicLong operReadCount = new AtomicLong();
- private AtomicLong operReadTimeTotal = new AtomicLong();
-
- private AtomicLong requestCommitCount = new AtomicLong();
- private AtomicLong requestCommitTimeTotal = new AtomicLong();
-
- public DataStoreStatsWrapper(DataStore store) {
- delegate = store;
- }
-
- @Override
- public DataStore getDelegate() {
- return delegate;
- }
-
- @Override
- public CompositeNode readConfigurationData(YangInstanceIdentifier path) {
- cfgReadCount.incrementAndGet();
- final long startTime = System.nanoTime();
- try {
- return delegate.readConfigurationData(path);
- } finally {
- final long endTime = System.nanoTime();
- final long runTime = endTime - startTime;
- cfgReadTimeTotal.addAndGet(runTime);
- }
- }
-
- @Override
- public CompositeNode readOperationalData(YangInstanceIdentifier path) {
- operReadCount.incrementAndGet();
- final long startTime = System.nanoTime();
- try {
- return delegate.readOperationalData(path);
- } finally {
- final long endTime = System.nanoTime();
- final long runTime = endTime - startTime;
- operReadTimeTotal.addAndGet(runTime);
- }
- }
-
- public DataCommitTransaction<YangInstanceIdentifier, CompositeNode> requestCommit(
- DataModification<YangInstanceIdentifier, CompositeNode> modification) {
- requestCommitCount.incrementAndGet();
- final long startTime = System.nanoTime();
- try {
- return delegate.requestCommit(modification);
- } finally {
- final long endTime = System.nanoTime();
- final long runTime = endTime - startTime;
- requestCommitTimeTotal.addAndGet(runTime);
- }
- };
-
- @Override
- public boolean containsConfigurationPath(YangInstanceIdentifier path) {
- return delegate.containsConfigurationPath(path);
- }
-
- public Iterable<YangInstanceIdentifier> getStoredConfigurationPaths() {
- return delegate.getStoredConfigurationPaths();
- }
-
- public Iterable<YangInstanceIdentifier> getStoredOperationalPaths() {
- return delegate.getStoredOperationalPaths();
- }
-
- public boolean containsOperationalPath(YangInstanceIdentifier path) {
- return delegate.containsOperationalPath(path);
- }
-
- public final long getConfigurationReadCount() {
- return cfgReadCount.get();
- }
-
- public final long getOperationalReadCount() {
- return operReadCount.get();
- }
-
- public final long getRequestCommitCount() {
- return requestCommitCount.get();
- }
-
- public final double getConfigurationReadTotalTime() {
- return cfgReadTimeTotal.get() / 1000.0d;
- }
-
- public final double getOperationalReadTotalTime() {
- return operReadTimeTotal.get() / 1000.0d;
- }
-
- public final double getRequestCommitTotalTime() {
- return requestCommitTimeTotal.get() / 1000.0d;
- }
-
- public final double getConfigurationReadAverageTime() {
- long readCount = cfgReadCount.get();
- if(readCount == 0) {
- return 0;
- }
- return getConfigurationReadTotalTime() / readCount;
- }
-
- public final double getOperationalReadAverageTime() {
- long readCount = operReadCount.get();
- if(readCount == 0) {
- return 0;
- }
- return getOperationalReadTotalTime() / readCount;
- }
-
- public final double getRequestCommitAverageTime() {
- long count = requestCommitCount.get();
- if(count == 0) {
- return 0;
- }
- return getRequestCommitTotalTime() / count;
- }
-
-}
+++ /dev/null
-/*
- * Copyright (c) 2014 Cisco Systems, Inc. and others. All rights reserved.
- *
- * This program and the accompanying materials are made available under the
- * terms of the Eclipse Public License v1.0 which accompanies this distribution,
- * and is available at http://www.eclipse.org/legal/epl-v10.html
- */
-package org.opendaylight.controller.sal.dom.broker.impl;
-
-import static com.google.common.base.Preconditions.checkState;
-import com.google.common.base.Predicate;
-import com.google.common.collect.FluentIterable;
-import com.google.common.collect.ImmutableSet;
-import com.google.common.collect.Iterables;
-import java.util.ArrayList;
-import java.util.Comparator;
-import java.util.HashMap;
-import java.util.List;
-import java.util.Map;
-import java.util.Map.Entry;
-import java.util.concurrent.Future;
-import org.opendaylight.controller.md.sal.common.api.TransactionStatus;
-import org.opendaylight.controller.md.sal.common.api.data.DataModification;
-import org.opendaylight.controller.md.sal.common.api.data.DataReader;
-import org.opendaylight.controller.md.sal.common.impl.AbstractDataModification;
-import org.opendaylight.controller.md.sal.common.impl.util.AbstractLockableDelegator;
-import org.opendaylight.controller.sal.core.api.data.DataStore;
-import org.opendaylight.controller.sal.dom.broker.util.YangDataOperations;
-import org.opendaylight.controller.sal.dom.broker.util.YangSchemaUtils;
-import org.opendaylight.yangtools.yang.common.QName;
-import org.opendaylight.yangtools.yang.common.RpcResult;
-import org.opendaylight.yangtools.yang.data.api.CompositeNode;
-import org.opendaylight.yangtools.yang.data.api.Node;
-import org.opendaylight.yangtools.yang.data.api.SimpleNode;
-import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier;
-import org.opendaylight.yangtools.yang.data.impl.CompositeNodeTOImpl;
-import org.opendaylight.yangtools.yang.model.api.ContainerSchemaNode;
-import org.opendaylight.yangtools.yang.model.api.DataSchemaNode;
-import org.opendaylight.yangtools.yang.model.api.ListSchemaNode;
-import org.opendaylight.yangtools.yang.model.api.SchemaContext;
-import org.opendaylight.yangtools.yang.model.api.SchemaContextListener;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-
-@Deprecated
-public class SchemaAwareDataStoreAdapter extends AbstractLockableDelegator<DataStore> implements DataStore, SchemaContextListener, AutoCloseable {
-
- private final static Logger LOG = LoggerFactory.getLogger(SchemaAwareDataStoreAdapter.class);
-
- private SchemaContext schema = null;
- private boolean validationEnabled = false;
- private final DataReader<YangInstanceIdentifier, CompositeNode> reader = new MergeFirstLevelReader();
-
- @Override
- public boolean containsConfigurationPath(final YangInstanceIdentifier path) {
- try {
- getDelegateReadLock().lock();
- return getDelegate().containsConfigurationPath(path);
-
- } finally {
- getDelegateReadLock().unlock();
- }
- }
-
- @Override
- public boolean containsOperationalPath(final YangInstanceIdentifier path) {
- try {
- getDelegateReadLock().lock();
- return getDelegate().containsOperationalPath(path);
-
- } finally {
- getDelegateReadLock().unlock();
- }
- }
-
- @Override
- public Iterable<YangInstanceIdentifier> getStoredConfigurationPaths() {
- try {
- getDelegateReadLock().lock();
- return getDelegate().getStoredConfigurationPaths();
-
- } finally {
- getDelegateReadLock().unlock();
- }
- }
-
- @Override
- public Iterable<YangInstanceIdentifier> getStoredOperationalPaths() {
- try {
- getDelegateReadLock().lock();
- return getDelegate().getStoredOperationalPaths();
-
- } finally {
- getDelegateReadLock().unlock();
- }
- }
-
- @Override
- public CompositeNode readConfigurationData(final YangInstanceIdentifier path) {
- return reader.readConfigurationData(path);
- }
-
- @Override
- public CompositeNode readOperationalData(final YangInstanceIdentifier path) {
- return reader.readOperationalData(path);
- }
-
- @Override
- public org.opendaylight.controller.md.sal.common.api.data.DataCommitHandler.DataCommitTransaction<YangInstanceIdentifier, CompositeNode> requestCommit(
- final DataModification<YangInstanceIdentifier, CompositeNode> modification) {
- validateAgainstSchema(modification);
- NormalizedDataModification cleanedUp = prepareMergedTransaction(modification);
- cleanedUp.status = TransactionStatus.SUBMITED;
- return retrieveDelegate().requestCommit(cleanedUp);
- }
-
- public boolean isValidationEnabled() {
- return validationEnabled;
- }
-
- public void setValidationEnabled(final boolean validationEnabled) {
- this.validationEnabled = validationEnabled;
- }
-
- private void validateAgainstSchema(final DataModification<YangInstanceIdentifier, CompositeNode> modification) {
- if (!validationEnabled) {
- return;
- }
-
- if (schema == null) {
- LOG.warn("Validation not performed for {}. Reason: YANG Schema not present.", modification.getIdentifier());
- return;
- }
- }
-
- @Override
- protected void onDelegateChanged(final DataStore oldDelegate, final DataStore newDelegate) {
- // NOOP
- }
-
- @Override
- public void onGlobalContextUpdated(final SchemaContext context) {
- this.schema = context;
- }
-
- @Override
- public void close() throws Exception {
- this.schema = null;
- }
-
- protected CompositeNode mergeData(final YangInstanceIdentifier path, final CompositeNode stored, final CompositeNode modified,
- final boolean config) {
- // long startTime = System.nanoTime();
- try {
- DataSchemaNode node = schemaNodeFor(path);
- return YangDataOperations.merge(node, stored, modified, config);
- } finally {
- // System.out.println("Merge time: " + ((System.nanoTime() -
- // startTime) / 1000.0d));
- }
- }
-
- private DataSchemaNode schemaNodeFor(final YangInstanceIdentifier path) {
- checkState(schema != null, "YANG Schema is not available");
- return YangSchemaUtils.getSchemaNode(schema, path);
- }
-
- private NormalizedDataModification prepareMergedTransaction(
- final DataModification<YangInstanceIdentifier, CompositeNode> original) {
- NormalizedDataModification normalized = new NormalizedDataModification(original);
- LOG.trace("Transaction: {} Removed Configuration {}, Removed Operational {}", original.getIdentifier(),
- original.getRemovedConfigurationData(), original.getRemovedConfigurationData());
- LOG.trace("Transaction: {} Created Configuration {}, Created Operational {}", original.getIdentifier(),
- original.getCreatedConfigurationData().entrySet(), original.getCreatedOperationalData().entrySet());
- LOG.trace("Transaction: {} Updated Configuration {}, Updated Operational {}", original.getIdentifier(),
- original.getUpdatedConfigurationData().entrySet(), original.getUpdatedOperationalData().entrySet());
-
- for (YangInstanceIdentifier entry : original.getRemovedConfigurationData()) {
- normalized.deepRemoveConfigurationData(entry);
- }
- for (YangInstanceIdentifier entry : original.getRemovedOperationalData()) {
- normalized.deepRemoveOperationalData(entry);
- }
- for (Entry<YangInstanceIdentifier, CompositeNode> entry : original.getUpdatedConfigurationData().entrySet()) {
- normalized.putDeepConfigurationData(entry.getKey(), entry.getValue());
- }
- for (Entry<YangInstanceIdentifier, CompositeNode> entry : original.getUpdatedOperationalData().entrySet()) {
- normalized.putDeepOperationalData(entry.getKey(), entry.getValue());
- }
- return normalized;
- }
-
- private Iterable<YangInstanceIdentifier> getConfigurationSubpaths(final YangInstanceIdentifier entry) {
- // FIXME: This should be replaced by index
- Iterable<YangInstanceIdentifier> paths = getStoredConfigurationPaths();
-
- return getChildrenPaths(entry, paths);
-
- }
-
- public Iterable<YangInstanceIdentifier> getOperationalSubpaths(final YangInstanceIdentifier entry) {
- // FIXME: This should be indexed
- Iterable<YangInstanceIdentifier> paths = getStoredOperationalPaths();
-
- return getChildrenPaths(entry, paths);
- }
-
- private static final Iterable<YangInstanceIdentifier> getChildrenPaths(final YangInstanceIdentifier entry,
- final Iterable<YangInstanceIdentifier> paths) {
- ImmutableSet.Builder<YangInstanceIdentifier> children = ImmutableSet.builder();
- for (YangInstanceIdentifier potential : paths) {
- if (entry.contains(potential)) {
- children.add(entry);
- }
- }
- return children.build();
- }
-
- private final Comparator<Entry<YangInstanceIdentifier, CompositeNode>> preparationComparator = new Comparator<Entry<YangInstanceIdentifier, CompositeNode>>() {
- @Override
- public int compare(final Entry<YangInstanceIdentifier, CompositeNode> o1, final Entry<YangInstanceIdentifier, CompositeNode> o2) {
- YangInstanceIdentifier o1Key = o1.getKey();
- YangInstanceIdentifier o2Key = o2.getKey();
- return Integer.compare(Iterables.size(o1Key.getPathArguments()), Iterables.size(o2Key.getPathArguments()));
- }
- };
-
- private class MergeFirstLevelReader implements DataReader<YangInstanceIdentifier, CompositeNode> {
-
- @Override
- public CompositeNode readConfigurationData(final YangInstanceIdentifier path) {
- getDelegateReadLock().lock();
- try {
- if (Iterables.isEmpty(path.getPathArguments())) {
- return null;
- }
- QName qname = null;
- CompositeNode original = getDelegate().readConfigurationData(path);
- ArrayList<Node<?>> childNodes = new ArrayList<Node<?>>();
- if (original != null) {
- childNodes.addAll(original.getValue());
- qname = original.getNodeType();
- } else {
- qname = path.getLastPathArgument().getNodeType();
- }
-
- FluentIterable<YangInstanceIdentifier> directChildren = FluentIterable.from(getStoredConfigurationPaths())
- .filter(new Predicate<YangInstanceIdentifier>() {
- @Override
- public boolean apply(final YangInstanceIdentifier input) {
- if (path.contains(input)) {
- int nesting = Iterables.size(input.getPathArguments()) - Iterables.size(path.getPathArguments());
- if (nesting == 1) {
- return true;
- }
- }
- return false;
- }
- });
- for (YangInstanceIdentifier instanceIdentifier : directChildren) {
- childNodes.add(getDelegate().readConfigurationData(instanceIdentifier));
- }
- if (original == null && childNodes.isEmpty()) {
- return null;
- }
-
- return new CompositeNodeTOImpl(qname, null, childNodes);
- } finally {
- getDelegateReadLock().unlock();
- }
- }
-
- @Override
- public CompositeNode readOperationalData(final YangInstanceIdentifier path) {
- getDelegateReadLock().lock();
- try {
- if (Iterables.isEmpty(path.getPathArguments())) {
- return null;
- }
- QName qname = null;
- CompositeNode original = getDelegate().readOperationalData(path);
- ArrayList<Node<?>> childNodes = new ArrayList<Node<?>>();
- if (original != null) {
- childNodes.addAll(original.getValue());
- qname = original.getNodeType();
- } else {
- qname = path.getLastPathArgument().getNodeType();
- }
-
- FluentIterable<YangInstanceIdentifier> directChildren = FluentIterable.from(getStoredOperationalPaths())
- .filter(new Predicate<YangInstanceIdentifier>() {
- @Override
- public boolean apply(final YangInstanceIdentifier input) {
- if (path.contains(input)) {
- int nesting = Iterables.size(input.getPathArguments()) - Iterables.size(path.getPathArguments());
- if (nesting == 1) {
- return true;
- }
- }
- return false;
- }
- });
-
- for (YangInstanceIdentifier instanceIdentifier : directChildren) {
- childNodes.add(getDelegate().readOperationalData(instanceIdentifier));
- }
- if (original == null && childNodes.isEmpty()) {
- return null;
- }
-
- return new CompositeNodeTOImpl(qname, null, childNodes);
- } finally {
- getDelegateReadLock().unlock();
- }
- }
- }
-
- private class NormalizedDataModification extends AbstractDataModification<YangInstanceIdentifier, CompositeNode> {
-
- private final String CONFIGURATIONAL_DATA_STORE_MARKER = "configurational";
- private final String OPERATIONAL_DATA_STORE_MARKER = "operational";
- private final Object identifier;
- private TransactionStatus status;
-
- public NormalizedDataModification(final DataModification<YangInstanceIdentifier, CompositeNode> original) {
- super(getDelegate());
- identifier = original;
- status = TransactionStatus.NEW;
- }
-
- /**
- *
- * Ensures all subpaths are removed - this currently does slow lookup in
- * all keys.
- *
- * @param entry
- */
- public void deepRemoveOperationalData(final YangInstanceIdentifier entry) {
- Iterable<YangInstanceIdentifier> paths = getOperationalSubpaths(entry);
- removeOperationalData(entry);
- for (YangInstanceIdentifier potential : paths) {
- removeOperationalData(potential);
- }
- }
-
- public void deepRemoveConfigurationData(final YangInstanceIdentifier entry) {
- Iterable<YangInstanceIdentifier> paths = getConfigurationSubpaths(entry);
- removeConfigurationData(entry);
- for (YangInstanceIdentifier potential : paths) {
- removeConfigurationData(potential);
- }
- }
-
- public void putDeepConfigurationData(final YangInstanceIdentifier entryKey, final CompositeNode entryData) {
- this.putCompositeNodeData(entryKey, entryData, CONFIGURATIONAL_DATA_STORE_MARKER);
- }
-
- public void putDeepOperationalData(final YangInstanceIdentifier entryKey, final CompositeNode entryData) {
- this.putCompositeNodeData(entryKey, entryData, OPERATIONAL_DATA_STORE_MARKER);
- }
-
- @Override
- public Object getIdentifier() {
- return this.identifier;
- }
-
- @Override
- public TransactionStatus getStatus() {
- return status;
- }
-
- @Override
- public Future<RpcResult<TransactionStatus>> commit() {
- throw new UnsupportedOperationException("Commit should not be invoked on this");
- }
-
- @Override
- protected CompositeNode mergeConfigurationData(final YangInstanceIdentifier path, final CompositeNode stored,
- final CompositeNode modified) {
- return mergeData(path, stored, modified, true);
- }
-
- @Override
- protected CompositeNode mergeOperationalData(final YangInstanceIdentifier path, final CompositeNode stored,
- final CompositeNode modified) {
- return mergeData(path, stored, modified, false);
- }
-
- private void putData(final YangInstanceIdentifier entryKey, final CompositeNode entryData, final String dataStoreIdentifier) {
- if (dataStoreIdentifier != null && entryKey != null && entryData != null) {
- switch (dataStoreIdentifier) {
- case (CONFIGURATIONAL_DATA_STORE_MARKER):
- this.putConfigurationData(entryKey, entryData);
- break;
- case (OPERATIONAL_DATA_STORE_MARKER):
- this.putOperationalData(entryKey, entryData);
- break;
-
- default:
- LOG.error(dataStoreIdentifier + " is NOT valid DataStore switch marker");
- throw new RuntimeException(dataStoreIdentifier + " is NOT valid DataStore switch marker");
- }
- }
- }
-
- private void putCompositeNodeData(final YangInstanceIdentifier entryKey, final CompositeNode entryData,
- final String dataStoreIdentifier) {
- this.putData(entryKey, entryData, dataStoreIdentifier);
-
- for (Node<?> child : entryData.getValue()) {
- YangInstanceIdentifier subEntryId = YangInstanceIdentifier.builder(entryKey).node(child.getNodeType())
- .toInstance();
- if (child instanceof CompositeNode) {
- DataSchemaNode subSchema = schemaNodeFor(subEntryId);
- CompositeNode compNode = (CompositeNode) child;
- YangInstanceIdentifier instanceId = null;
-
- if (subSchema instanceof ListSchemaNode) {
- ListSchemaNode listSubSchema = (ListSchemaNode) subSchema;
- Map<QName, Object> mapOfSubValues = this.getValuesFromListSchema(listSubSchema,
- (CompositeNode) child);
- if (mapOfSubValues != null) {
- instanceId = YangInstanceIdentifier.builder(entryKey)
- .nodeWithKey(listSubSchema.getQName(), mapOfSubValues).toInstance();
- }
- } else if (subSchema instanceof ContainerSchemaNode) {
- ContainerSchemaNode containerSchema = (ContainerSchemaNode) subSchema;
- instanceId = YangInstanceIdentifier.builder(entryKey).node(subSchema.getQName()).toInstance();
- }
- if (instanceId != null) {
- this.putCompositeNodeData(instanceId, compNode, dataStoreIdentifier);
- }
- }
- }
- }
-
- private Map<QName, Object> getValuesFromListSchema(final ListSchemaNode listSchema, final CompositeNode entryData) {
- List<QName> keyDef = listSchema.getKeyDefinition();
- if (keyDef != null && !keyDef.isEmpty()) {
- Map<QName, Object> map = new HashMap<QName, Object>();
- for (QName key : keyDef) {
- List<Node<?>> data = entryData.get(key);
- if (data != null && !data.isEmpty()) {
- for (Node<?> nodeData : data) {
- if (nodeData instanceof SimpleNode<?>) {
- map.put(key, data.get(0).getValue());
- }
- }
- }
- }
- return map;
- }
- return null;
- }
- }
-}
+++ /dev/null
-/*
- * Copyright (c) 2013 Cisco Systems, Inc. and others. All rights reserved.
- *
- * This program and the accompanying materials are made available under the
- * terms of the Eclipse Public License v1.0 which accompanies this distribution,
- * and is available at http://www.eclipse.org/legal/epl-v10.html
- */
-package org.opendaylight.controller.sal.dom.broker.impl;
-
-/**
- * @deprecated Use org.opendaylight.yangtools.yang.model.api.SchemaContextProvider instead
- */
-@Deprecated
-public interface SchemaContextProvider extends org.opendaylight.yangtools.yang.model.api.SchemaContextProvider{
-
-}
+++ /dev/null
-/*
- * Copyright (c) 2014 Cisco Systems, Inc. and others. All rights reserved.
- *
- * This program and the accompanying materials are made available under the
- * terms of the Eclipse Public License v1.0 which accompanies this distribution,
- * and is available at http://www.eclipse.org/legal/epl-v10.html
- */
-package org.opendaylight.controller.sal.dom.broker.util;
-
-import static com.google.common.base.Preconditions.checkArgument;
-
-import com.google.common.base.Preconditions;
-import com.google.common.collect.Iterables;
-
-import java.util.ArrayList;
-import java.util.Arrays;
-import java.util.Collections;
-import java.util.HashSet;
-import java.util.List;
-import java.util.Map;
-import java.util.Objects;
-import java.util.Set;
-
-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.CompositeNodeTOImpl;
-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;
-
-@Deprecated
-public class YangDataOperations {
-
- public static CompositeNode merge(final DataSchemaNode schema,
- final CompositeNode stored, final CompositeNode modified,
- final boolean config) {
- if (stored == null) {
- return modified;
- }
-
- Preconditions.checkArgument(schema instanceof ListSchemaNode
- || schema instanceof ContainerSchemaNode,
- "Supplied node is not data node container.");
-
- return YangDataOperations.mergeContainer((DataNodeContainer) schema,
- stored, modified, config);
- }
-
- private static Iterable<? extends Node<?>> _mergeMultiple(
- final LeafSchemaNode node, final List<Node<?>> original,
- final List<Node<?>> modified, final boolean configurational) {
- checkArgument(original.size() == 1);
- checkArgument(modified.size() == 1);
-
- return modified;
- }
-
- private static Iterable<? extends Node<?>> _mergeMultiple(
- final LeafListSchemaNode node, final List<Node<?>> original,
- final List<Node<?>> modified, final boolean configurational) {
- return modified;
- }
-
- private static Iterable<? extends Node<?>> _mergeMultiple(
- final ContainerSchemaNode node, final List<Node<?>> original,
- final List<Node<?>> modified, final boolean configurational) {
- checkArgument(original.size() == 1);
- checkArgument(modified.size() == 1);
- return Collections.singletonList(merge(node,
- (CompositeNode) original.get(0),
- (CompositeNode) modified.get(0), configurational));
- }
-
- private static Iterable<? extends Node<?>> _mergeMultiple(
- final ListSchemaNode node, final List<Node<?>> original,
- final List<Node<?>> modified, final boolean configurational) {
-
- if (node.getKeyDefinition() == null
- || node.getKeyDefinition().isEmpty()) {
- return modified;
- }
- @SuppressWarnings({ "unchecked", "rawtypes" })
- final Map<Map<QName, Object>, CompositeNode> originalMap = YangDataUtils
- .toIndexMap((List) original, node.getKeyDefinition());
- @SuppressWarnings({ "unchecked", "rawtypes" })
- final Map<Map<QName, Object>, CompositeNode> modifiedMap = YangDataUtils
- .toIndexMap((List) modified, node.getKeyDefinition());
-
- final List<Node<?>> mergedNodes = new ArrayList<Node<?>>(
- original.size() + modified.size());
- for (final Map.Entry<Map<QName, Object>, CompositeNode> entry : modifiedMap
- .entrySet()) {
- final CompositeNode originalEntry = originalMap.get(entry.getKey());
- if (originalEntry != null) {
- originalMap.remove(entry.getKey());
- mergedNodes.add(merge(node, originalEntry, entry.getValue(),
- configurational));
- } else {
- mergedNodes.add(entry.getValue());
- }
- }
- mergedNodes.addAll(originalMap.values());
- return mergedNodes;
- }
-
- private static Iterable<? extends Node<?>> mergeMultiple(
- final DataSchemaNode node, final List<Node<?>> original,
- final List<Node<?>> modified, final boolean configurational) {
- if (node instanceof ContainerSchemaNode) {
- return _mergeMultiple((ContainerSchemaNode) node, original,
- modified, configurational);
- } else if (node instanceof LeafListSchemaNode) {
- return _mergeMultiple((LeafListSchemaNode) node, original,
- modified, configurational);
- } else if (node instanceof LeafSchemaNode) {
- return _mergeMultiple((LeafSchemaNode) node, original, modified,
- configurational);
- } else if (node instanceof ListSchemaNode) {
- return _mergeMultiple((ListSchemaNode) node, original, modified,
- configurational);
- } else {
- throw new IllegalArgumentException("Unhandled parameter types: "
- + Arrays.<Object> asList(node, original, modified,
- configurational).toString());
- }
- }
-
- private static CompositeNode mergeContainer(final DataNodeContainer schema,
- final CompositeNode stored, final CompositeNode modified,
- final boolean config) {
- if (stored == null) {
- return modified;
- }
- Preconditions.checkNotNull(stored);
- Preconditions.checkNotNull(modified);
- Preconditions.checkArgument(Objects.equals(stored.getNodeType(),
- modified.getNodeType()));
-
- final List<Node<?>> mergedChildNodes = new ArrayList<Node<?>>(stored
- .getValue().size() + modified.getValue().size());
- final Set<QName> toProcess = new HashSet<QName>(stored.keySet());
- toProcess.addAll(modified.keySet());
-
- for (QName qname : toProcess) {
- final DataSchemaNode schemaChild = schema.getDataChildByName(qname);
- final List<Node<?>> storedChildren = stored.get(qname);
- final List<Node<?>> modifiedChildren = modified.get(qname);
-
- if (modifiedChildren != null && !modifiedChildren.isEmpty()) {
- if (storedChildren == null || storedChildren.isEmpty()
- || schemaChild == null) {
- mergedChildNodes.addAll(modifiedChildren);
- } else {
- final Iterable<? extends Node<?>> _mergeMultiple = mergeMultiple(
- schemaChild, storedChildren, modifiedChildren,
- config);
- Iterables.addAll(mergedChildNodes, _mergeMultiple);
- }
- } else if (storedChildren != null && !storedChildren.isEmpty()) {
- mergedChildNodes.addAll(storedChildren);
- }
- }
- return new CompositeNodeTOImpl(stored.getNodeType(), null,
- mergedChildNodes);
- }
-}
+++ /dev/null
-/*
- * Copyright (c) 2014 Cisco Systems, Inc. and others. All rights reserved.
- *
- * This program and the accompanying materials are made available under the
- * terms of the Eclipse Public License v1.0 which accompanies this distribution,
- * and is available at http://www.eclipse.org/legal/epl-v10.html
- */
-package org.opendaylight.controller.sal.dom.broker.util;
-
-import static com.google.common.base.Preconditions.checkArgument;
-
-import java.util.HashMap;
-import java.util.List;
-import java.util.Map;
-import java.util.concurrent.ConcurrentHashMap;
-
-import org.opendaylight.yangtools.yang.common.QName;
-import org.opendaylight.yangtools.yang.data.api.CompositeNode;
-import org.opendaylight.yangtools.yang.data.api.SimpleNode;
-
-@Deprecated
-public final class YangDataUtils {
-
- private YangDataUtils() {
- throw new UnsupportedOperationException("Utility class");
- }
-
- public static Map<Map<QName,Object>,CompositeNode> toIndexMap(final List<CompositeNode> nodes,final List<QName> keys) {
- ConcurrentHashMap<Map<QName,Object>,CompositeNode> ret = new ConcurrentHashMap<>();
- for(CompositeNode node : nodes) {
- Map<QName, Object> key = getKeyMap(node,keys);
- ret.put(key, node);
- }
- return ret;
- }
-
- public static Map<QName,Object> getKeyMap(final CompositeNode node, final List<QName> keys) {
- Map<QName,Object> map = new HashMap<>();
- for(QName key : keys) {
- SimpleNode<?> keyNode = node.getFirstSimpleByName(QName.create(node.getNodeType(), key.getLocalName()));
- checkArgument(keyNode != null,"Node must contains all keys.");
- Object value = keyNode.getValue();
- map.put(key, value);
-
- }
- return map;
- }
-}
getSchemaServiceDependency().registerSchemaContextListener(xsqlAdapter);
xsqlAdapter.setDataBroker(getAsyncDataBrokerDependency());
XSQLProvider p = new XSQLProvider();
- p.buildXSQL(getDataBrokerDependency());
+ //p.buildXSQL(getDataBrokerDependency());
return p;
}
import org.opendaylight.yangtools.yang.data.api.CompositeNode;
import org.opendaylight.yangtools.yang.model.api.RpcDefinition;
import org.opendaylight.yangtools.yang.model.api.SchemaContext;
+import org.opendaylight.yangtools.yang.model.api.SchemaContextProvider;
import org.osgi.framework.BundleContext;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
final NetconfSessionCapabilities netconfSessionPreferences, final RpcImplementation deviceRpc) {
// TODO move SchemaAwareRpcBroker from sal-broker-impl, now we have depend on the whole sal-broker-impl
- final RpcProvisionRegistry rpcRegistry = new SchemaAwareRpcBroker(id.getPath().toString(), new org.opendaylight.controller.sal.dom.broker.impl.SchemaContextProvider() {
+ final RpcProvisionRegistry rpcRegistry = new SchemaAwareRpcBroker(id.getPath().toString(), new SchemaContextProvider() {
@Override
public SchemaContext getSchemaContext() {
return schemaContext;
final DataNodeContainer parentSchema = (DataNodeContainer) incompleteInstIdWithData.getSchemaNode();
DOMMountPoint mountPoint = incompleteInstIdWithData.getMountPoint();
final Module module = findModule(mountPoint, payload);
- if (module == null) {
- throw new RestconfDocumentedException("Module was not found for \"" + payloadNS + "\"",
- ErrorType.PROTOCOL, ErrorTag.UNKNOWN_ELEMENT);
- }
String payloadName = this.getName(payload);
final DataSchemaNode schemaNode = ControllerContext.findInstanceDataChildByNameAndNamespace(
}
final Module module = this.findModule(null, payload);
- if (module == null) {
- throw new RestconfDocumentedException(
- "Data has bad format. Root element node has incorrect namespace (XML format) or module name(JSON format)",
- ErrorType.PROTOCOL, ErrorTag.UNKNOWN_NAMESPACE);
- }
String payloadName = this.getName(payload);
final DataSchemaNode schemaNode = ControllerContext.findInstanceDataChildByNameAndNamespace(module,
}
private Module findModule(final DOMMountPoint mountPoint, final Node<?> data) {
+ Module module = null;
if (data instanceof NodeWrapper) {
- return findModule(mountPoint, (NodeWrapper<?>) data);
+ module = findModule(mountPoint, (NodeWrapper<?>) data);
} else if (data != null) {
URI namespace = data.getNodeType().getNamespace();
if (mountPoint != null) {
- return this.controllerContext.findModuleByNamespace(mountPoint, namespace);
+ module = this.controllerContext.findModuleByNamespace(mountPoint, namespace);
} else {
- return this.controllerContext.findModuleByNamespace(namespace);
+ module = this.controllerContext.findModuleByNamespace(namespace);
}
- } else {
- throw new IllegalArgumentException("Unhandled parameter types: "
- + Arrays.<Object> asList(mountPoint, data).toString());
}
+ if (module != null) {
+ return module;
+ }
+ throw new RestconfDocumentedException(
+ "Data has bad format. Root element node has incorrect namespace (XML format) or module name(JSON format)",
+ ErrorType.PROTOCOL, ErrorTag.UNKNOWN_NAMESPACE);
}
private Module findModule(final DOMMountPoint mountPoint, final NodeWrapper<?> data) {
*/
private synchronized EditAndCommitResponse pushConfigWithConflictingVersionRetries(ConfigSnapshotHolder configSnapshotHolder) throws NetconfDocumentedException {
ConflictingVersionException lastException;
- Stopwatch stopwatch = new Stopwatch().start();
+ Stopwatch stopwatch = new Stopwatch();
do {
String idForReporting = configSnapshotHolder.toString();
SortedSet<String> expectedCapabilities = checkNotNull(configSnapshotHolder.getCapabilities(),
"Expected capabilities must not be null - %s, check %s", idForReporting,
configSnapshotHolder.getClass().getName());
try (NetconfOperationService operationService = getOperationServiceWithRetries(expectedCapabilities, idForReporting)) {
+ if(!stopwatch.isRunning()) {
+ stopwatch.start();
+ }
return pushConfig(configSnapshotHolder, operationService);
} catch (ConflictingVersionException e) {
lastException = e;
- LOG.debug("Conflicting version detected, will retry after timeout");
+ LOG.info("Conflicting version detected, will retry after timeout");
sleep();
}
} while (stopwatch.elapsed(TimeUnit.MILLISECONDS) < conflictingVersionTimeoutMillis);
public static final String MAX_WAIT_FOR_CAPABILITIES_MILLIS_PROPERTY = "maxWaitForCapabilitiesMillis";
private static final long MAX_WAIT_FOR_CAPABILITIES_MILLIS_DEFAULT = TimeUnit.MINUTES.toMillis(2);
public static final String CONFLICTING_VERSION_TIMEOUT_MILLIS_PROPERTY = "conflictingVersionTimeoutMillis";
- private static final long CONFLICTING_VERSION_TIMEOUT_MILLIS_DEFAULT = TimeUnit.SECONDS.toMillis(30);
+ private static final long CONFLICTING_VERSION_TIMEOUT_MILLIS_DEFAULT = TimeUnit.MINUTES.toMillis(1);
public static final String NETCONF_CONFIG_PERSISTER = "netconf.config.persister";
<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>
<artifactId>maven-bundle-plugin</artifactId>
<configuration>
<instructions>
- <Import-Package>com.google.common.collect,
- 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.opendaylight.yangtools.yang.binding,
- org.opendaylight.yangtools.yang.common,</Import-Package>
<Export-Package>org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.netconf.monitoring.rev101004.*</Export-Package>
</instructions>
</configuration>
<artifactId>maven-bundle-plugin</artifactId>
<configuration>
<instructions>
- <Private-Package></Private-Package>
<Export-Package>org.opendaylight.controller.netconf.api,
org.opendaylight.controller.netconf.api.jmx,
org.opendaylight.controller.netconf.api.xml,
<configuration>
<instructions>
<Export-Package>org.opendaylight.controller.netconf.client.*,</Export-Package>
- <Import-Package>com.google.common.base,
- com.google.common.collect,
- io.netty.channel,
- io.netty.channel.socket,
- io.netty.util,
- io.netty.util.concurrent,
- javax.annotation,
- javax.net.ssl,
- javax.xml.namespace,
- javax.xml.parsers,
- javax.xml.xpath,
- org.opendaylight.controller.netconf.api,
- org.opendaylight.controller.netconf.util.*,
- org.opendaylight.controller.netconf.nettyutil.*,
- org.opendaylight.protocol.framework,
- org.openexi.*,
- org.slf4j,
- org.w3c.dom,
- org.xml.sax,
- io.netty.handler.codec</Import-Package>
</instructions>
</configuration>
</plugin>
<configuration>
<instructions>
<Bundle-Activator>org.opendaylight.controller.netconf.impl.osgi.NetconfImplActivator</Bundle-Activator>
- <Import-Package>com.google.common.base,
- com.google.common.collect,
- io.netty.channel,
- io.netty.channel.socket,
- io.netty.util,
- io.netty.util.concurrent,
- io.netty.buffer,
- io.netty.handler.codec,
- io.netty.channel.nio,
- io.netty.channel.local,
- javax.annotation,
- javax.management,
- javax.net.ssl,
- javax.xml.namespace,
- javax.xml.xpath,
- org.opendaylight.controller.netconf.api,
- org.opendaylight.controller.netconf.api.jmx,
- org.opendaylight.controller.netconf.mapping.api,
- org.opendaylight.controller.netconf.util.*,
- org.opendaylight.protocol.framework,
- org.osgi.framework,
- org.osgi.util.tracker,
- org.slf4j,
- org.w3c.dom,
- org.xml.sax,
- io.netty.util.internal,
- org.opendaylight.controller.netconf.api.monitoring,
- 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.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,
- 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,
- org.openexi.*,
- org.opendaylight.controller.netconf.nettyutil.*</Import-Package>
</instructions>
</configuration>
</plugin>
<artifactId>maven-bundle-plugin</artifactId>
<configuration>
<instructions>
- <Private-Package></Private-Package>
- <Import-Package>com.google.common.base,
- org.opendaylight.controller.netconf.api,
- org.w3c.dom</Import-Package>
<Export-Package>org.opendaylight.controller.netconf.mapping.api,</Export-Package>
</instructions>
</configuration>
<configuration>
<instructions>
<Bundle-Activator>org.opendaylight.controller.netconf.monitoring.osgi.NetconfMonitoringActivator</Bundle-Activator>
- <Import-Package>com.google.common.base,
- com.google.common.collect,
- com.google.common.io,
- org.opendaylight.controller.netconf.api,
- org.opendaylight.controller.netconf.mapping.api,
- org.opendaylight.controller.netconf.util.mapping,
- org.opendaylight.controller.netconf.util.exception,
- org.osgi.framework,
- org.slf4j,
- org.w3c.dom,
- javax.xml.bind,
- javax.xml.bind.annotation,
- javax.xml.transform,
- javax.xml.transform.dom,
- org.opendaylight.controller.netconf.util.xml,
- io.netty.util.internal,
- javax.annotation,
- org.opendaylight.controller.netconf.api.monitoring,
- 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>
</plugin>
<artifactId>maven-bundle-plugin</artifactId>
<configuration>
<instructions>
- <Import-Package>org.apache.sshd.*, com.google.common.base, com.google.common.collect, io.netty.buffer,
- io.netty.channel, io.netty.channel.socket, io.netty.handler.codec, io.netty.handler.ssl, io.netty.util,
- io.netty.util.concurrent, javax.xml.transform, javax.xml.transform.dom, javax.xml.transform.sax,
- javax.xml.transform.stream, org.opendaylight.controller.netconf.api,
- org.opendaylight.controller.netconf.util.messages, org.opendaylight.controller.netconf.util.xml,
- org.opendaylight.protocol.framework, org.openexi.proc, org.openexi.proc.common, org.openexi.proc.grammars,
- org.openexi.sax, org.openexi.schema, org.slf4j, org.w3c.dom, org.xml.sax</Import-Package>
<Export-Package>org.opendaylight.controller.netconf.nettyutil,
org.opendaylight.controller.netconf.nettyutil.handler,
org.opendaylight.controller.netconf.nettyutil.handler.exi,
<configuration>
<instructions>
<Bundle-Activator>org.opendaylight.controller.netconf.ssh.osgi.NetconfSSHActivator</Bundle-Activator>
- <Import-Package>*</Import-Package>
</instructions>
</configuration>
</plugin>
<configuration>
<instructions>
<Bundle-Activator>org.opendaylight.controller.netconf.tcp.osgi.NetconfTCPActivator</Bundle-Activator>
- <Import-Package>com.google.common.base, io.netty.bootstrap, io.netty.channel, io.netty.channel.local,
- io.netty.channel.nio, io.netty.channel.socket, io.netty.channel.socket.nio, io.netty.handler.logging,
- io.netty.util.concurrent, org.opendaylight.controller.netconf.util.osgi, org.osgi.framework, org.slf4j</Import-Package>
</instructions>
</configuration>
</plugin>
<artifactId>maven-bundle-plugin</artifactId>
<configuration>
<instructions>
- <Import-Package>com.google.common.base, com.google.common.collect, io.netty.channel,
- io.netty.util.concurrent, javax.annotation, javax.xml.namespace, javax.xml.parsers, javax.xml.transform,
- javax.xml.transform.dom, javax.xml.transform.stream, javax.xml.validation, javax.xml.xpath,
- org.opendaylight.controller.netconf.api, org.opendaylight.controller.netconf.api.xml,
- org.opendaylight.controller.netconf.mapping.api,
- org.osgi.framework, org.slf4j, org.w3c.dom, org.xml.sax,io.netty.channel.local</Import-Package>
<Export-Package>org.opendaylight.controller.netconf.util.*</Export-Package>
</instructions>
</configuration>