<!-- 3rd party dependencies needed by config-->
<dependency>
- <groupId>com.jcabi</groupId>
- <artifactId>jcabi-maven-slf4j</artifactId>
- <version>0.8</version>
+ <groupId>org.apache.maven</groupId>
+ <artifactId>maven-core</artifactId>
+ <version>3.1.1</version>
+ <scope>provided</scope>
</dependency>
<dependency>
<artifactId>guava</artifactId>
</dependency>
- <dependency>
- <groupId>com.jcabi</groupId>
- <artifactId>jcabi-maven-slf4j</artifactId>
- </dependency>
-
<dependency>
<groupId>commons-io</groupId>
<artifactId>commons-io</artifactId>
<artifactId>commons-lang3</artifactId>
</dependency>
- <dependency>
- <groupId>org.codehaus.gmaven.runtime</groupId>
- <artifactId>gmaven-runtime-2.0</artifactId>
- <exclusions>
- <exclusion>
- <groupId>org.sonatype.gossip</groupId>
- <artifactId>gossip</artifactId>
- </exclusion>
- </exclusions>
- </dependency>
-
<dependency>
<groupId>org.opendaylight.controller</groupId>
<artifactId>yang-jmx-generator</artifactId>
<groupId>org.opendaylight.yangtools</groupId>
<artifactId>yang-maven-plugin-spi</artifactId>
</dependency>
+ <dependency>
+ <groupId>org.apache.maven</groupId>
+ <artifactId>maven-core</artifactId>
+ </dependency>
<dependency>
<groupId>org.slf4j</groupId>
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import org.apache.commons.io.FileUtils;
-import org.apache.maven.plugin.logging.Log;
import org.apache.maven.project.MavenProject;
import org.opendaylight.controller.config.spi.ModuleFactory;
import org.opendaylight.controller.config.yangjmxgenerator.ModuleMXBeanEntry;
import org.opendaylight.yangtools.yang.model.api.IdentitySchemaNode;
import org.opendaylight.yangtools.yang.model.api.Module;
import org.opendaylight.yangtools.yang.model.api.SchemaContext;
-import org.opendaylight.yangtools.yang2sources.spi.CodeGenerator;
+import org.opendaylight.yangtools.yang2sources.spi.BasicCodeGenerator;
+import org.opendaylight.yangtools.yang2sources.spi.MavenProjectAware;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
-import org.slf4j.impl.StaticLoggerBinder;
/**
* This class interfaces with yang-maven-plugin. Gets parsed yang modules in
* {@link SchemaContext}, and parameters form the plugin configuration, and
* writes service interfaces and/or modules.
*/
-public class JMXGenerator implements CodeGenerator {
+public class JMXGenerator implements BasicCodeGenerator, MavenProjectAware {
+ private static final class NamespaceMapping {
+ private final String namespace, packageName;
+ public NamespaceMapping(final String namespace, final String packagename) {
+ this.namespace = namespace;
+ this.packageName = packagename;
+ }
+ }
+
+ @VisibleForTesting
static final String NAMESPACE_TO_PACKAGE_DIVIDER = "==";
+ @VisibleForTesting
static final String NAMESPACE_TO_PACKAGE_PREFIX = "namespaceToPackage";
+ @VisibleForTesting
static final String MODULE_FACTORY_FILE_BOOLEAN = "moduleFactoryFile";
+ private static final Logger LOG = LoggerFactory.getLogger(JMXGenerator.class);
+ private static final Pattern NAMESPACE_MAPPING_PATTERN = Pattern.compile("(.+)" + NAMESPACE_TO_PACKAGE_DIVIDER + "(.+)");
+
private PackageTranslator packageTranslator;
private final CodeWriter codeWriter;
- private static final Logger LOG = LoggerFactory
- .getLogger(JMXGenerator.class);
private Map<String, String> namespaceToPackageMapping;
private File resourceBaseDir;
private File projectBaseDir;
private boolean generateModuleFactoryFile = true;
public JMXGenerator() {
- this.codeWriter = new CodeWriter();
+ this(new CodeWriter());
}
- public JMXGenerator(CodeWriter codeWriter) {
+ public JMXGenerator(final CodeWriter codeWriter) {
this.codeWriter = codeWriter;
}
@Override
- public Collection<File> generateSources(SchemaContext context,
- File outputBaseDir, Set<Module> yangModulesInCurrentMavenModule) {
+ public Collection<File> generateSources(final SchemaContext context,
+ final File outputBaseDir, final Set<Module> yangModulesInCurrentMavenModule) {
Preconditions.checkArgument(context != null, "Null context received");
Preconditions.checkArgument(outputBaseDir != null,
return generatedFiles.getFiles();
}
- static File concatFolders(File projectBaseDir, String... folderNames) {
+ @VisibleForTesting
+ static File concatFolders(final File projectBaseDir, final String... folderNames) {
StringBuilder b = new StringBuilder();
for (String folder : folderNames) {
b.append(folder);
}
@Override
- public void setAdditionalConfig(Map<String, String> additionalCfg) {
- if (LOG != null) {
- LOG.debug(getClass().getCanonicalName(),
- ": Additional configuration received: ",
- additionalCfg.toString());
- }
+ public void setAdditionalConfig(final Map<String, String> additionalCfg) {
+ LOG.debug("{}: Additional configuration received: {}", getClass().getCanonicalName(), additionalCfg);
this.namespaceToPackageMapping = extractNamespaceMapping(additionalCfg);
this.generateModuleFactoryFile = extractModuleFactoryBoolean(additionalCfg);
}
private boolean extractModuleFactoryBoolean(
- Map<String, String> additionalCfg) {
+ final Map<String, String> additionalCfg) {
String bool = additionalCfg.get(MODULE_FACTORY_FILE_BOOLEAN);
if (bool == null) {
return true;
return true;
}
- @Override
- public void setLog(Log log) {
- StaticLoggerBinder.getSingleton().setMavenLog(log);
- }
-
private static Map<String, String> extractNamespaceMapping(
- Map<String, String> additionalCfg) {
+ final Map<String, String> additionalCfg) {
Map<String, String> namespaceToPackage = Maps.newHashMap();
for (String key : additionalCfg.keySet()) {
if (key.startsWith(NAMESPACE_TO_PACKAGE_PREFIX)) {
return namespaceToPackage;
}
- static Pattern namespaceMappingPattern = Pattern.compile("(.+)"
- + NAMESPACE_TO_PACKAGE_DIVIDER + "(.+)");
-
- private static NamespaceMapping extractNamespaceMapping(String mapping) {
- Matcher matcher = namespaceMappingPattern.matcher(mapping);
- Preconditions
- .checkArgument(matcher.matches(), String.format("Namespace to package mapping:%s is in invalid " +
- "format, requested format is: %s", mapping, namespaceMappingPattern));
+ private static NamespaceMapping extractNamespaceMapping(final String mapping) {
+ Matcher matcher = NAMESPACE_MAPPING_PATTERN.matcher(mapping);
+ Preconditions.checkArgument(matcher.matches(),
+ "Namespace to package mapping:%s is in invalid format, requested format is: %s",
+ mapping, NAMESPACE_MAPPING_PATTERN);
return new NamespaceMapping(matcher.group(1), matcher.group(2));
}
- private static class NamespaceMapping {
- public NamespaceMapping(String namespace, String packagename) {
- this.namespace = namespace;
- this.packageName = packagename;
- }
-
- private final String namespace, packageName;
- }
-
@Override
- public void setResourceBaseDir(File resourceDir) {
+ public void setResourceBaseDir(final File resourceDir) {
this.resourceBaseDir = resourceDir;
}
@Override
- public void setMavenProject(MavenProject project) {
+ public void setMavenProject(final MavenProject project) {
this.projectBaseDir = project.getBasedir();
-
- if (LOG != null) {
- LOG.debug(getClass().getCanonicalName(), " project base dir: ",
- projectBaseDir);
- }
+ LOG.debug("{}: project base dir: {}", getClass().getCanonicalName(), projectBaseDir);
}
@VisibleForTesting
static class GeneratedFilesTracker {
private final Set<File> files = Sets.newHashSet();
- void addFile(File file) {
+ void addFile(final File file) {
if (files.contains(file)) {
List<File> undeletedFiles = Lists.newArrayList();
for (File presentFile : files) {
files.add(file);
}
- void addFile(Collection<File> files) {
+ void addFile(final Collection<File> files) {
for (File file : files) {
addFile(file);
}
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.util.FullyQualifiedNameHelper;
-import org.opendaylight.yangtools.binding.generator.util.BindingGeneratorUtil;
import org.opendaylight.yangtools.sal.binding.model.api.ParameterizedType;
import org.opendaylight.yangtools.sal.binding.model.api.Type;
+import org.opendaylight.yangtools.yang.binding.BindingMapping;
public class TemplateFactory {
* bean as value that should be persisted from this instance.
*/
public static Map<String, FtlTemplate> getTOAndMXInterfaceFtlFiles(
- RuntimeBeanEntry entry) {
+ final RuntimeBeanEntry entry) {
Map<String, FtlTemplate> result = new HashMap<>();
{ // create GeneralInterfaceFtlFile for runtime MXBean. Attributes will
// be transformed to getter methods
}
// FIXME: put into Type.toString
- static String serializeType(Type type, boolean addWildcards) {
+ static String serializeType(final Type type, final boolean addWildcards) {
if (type instanceof ParameterizedType){
ParameterizedType parameterizedType = (ParameterizedType) type;
StringBuilder sb = new StringBuilder();
}
}
- static String serializeType(Type type) {
+ static String serializeType(final Type type) {
return serializeType(type, false);
}
- private static String getReturnType(AttributeIfc attributeIfc) {
+ private static String getReturnType(final AttributeIfc attributeIfc) {
String returnType;
if (attributeIfc instanceof TypedAttribute) {
Type type = ((TypedAttribute) attributeIfc).getType();
}
public static GeneralInterfaceTemplate serviceInterfaceFromSie(
- ServiceInterfaceEntry sie) {
+ final ServiceInterfaceEntry sie) {
List<String> extendedInterfaces = Lists
.newArrayList(AbstractServiceInterface.class.getCanonicalName());
}
public static AbstractFactoryTemplate abstractFactoryTemplateFromMbe(
- ModuleMXBeanEntry mbe) {
+ final ModuleMXBeanEntry mbe) {
AbstractFactoryAttributesProcessor attrProcessor = new AbstractFactoryAttributesProcessor();
attrProcessor.processAttributes(mbe.getAttributes(),
mbe.getPackageName());
}
public static AbstractModuleTemplate abstractModuleTemplateFromMbe(
- ModuleMXBeanEntry mbe) {
+ final ModuleMXBeanEntry mbe) {
AbstractModuleAttributesProcessor attrProcessor = new AbstractModuleAttributesProcessor(mbe.getAttributes());
List<ModuleField> moduleFields = attrProcessor.getModuleFields();
}
public static StubFactoryTemplate stubFactoryTemplateFromMbe(
- ModuleMXBeanEntry mbe) {
+ final ModuleMXBeanEntry mbe) {
return new StubFactoryTemplate(getHeaderFromEntry(mbe),
mbe.getPackageName(), mbe.getStubFactoryName(),
mbe.getFullyQualifiedName(mbe.getAbstractFactoryName())
}
public static GeneralInterfaceTemplate mXBeanInterfaceTemplateFromMbe(
- ModuleMXBeanEntry mbe) {
+ final ModuleMXBeanEntry mbe) {
MXBeanInterfaceAttributesProcessor attrProcessor = new MXBeanInterfaceAttributesProcessor();
attrProcessor.processAttributes(mbe.getAttributes());
GeneralInterfaceTemplate ifcTemplate = new GeneralInterfaceTemplate(
}
public static Map<String, GeneralClassTemplate> tOsFromMbe(
- ModuleMXBeanEntry mbe) {
+ final ModuleMXBeanEntry mbe) {
Map<String, GeneralClassTemplate> retVal = Maps.newHashMap();
TOAttributesProcessor processor = new TOAttributesProcessor();
processor.processAttributes(mbe.getAttributes());
}
public static Map<String, GeneralClassTemplate> tOsFromRbe(
- RuntimeBeanEntry rbe) {
+ final RuntimeBeanEntry rbe) {
Map<String, GeneralClassTemplate> retVal = Maps.newHashMap();
TOAttributesProcessor processor = new TOAttributesProcessor();
Map<String, AttributeIfc> yangPropertiesToTypesMap = Maps.newHashMap(rbe.getYangPropertiesToTypesMap());
return retVal;
}
- private static Header getHeaderFromEntry(AbstractEntry mbe) {
+ private static Header getHeaderFromEntry(final AbstractEntry mbe) {
return new Header(mbe.getYangModuleName(), mbe.getYangModuleLocalname());
}
private final List<TOInternal> tos = Lists.newArrayList();
- void processAttributes(Map<String, AttributeIfc> attributes) {
+ void processAttributes(final Map<String, AttributeIfc> attributes) {
for (Entry<String, AttributeIfc> attrEntry : attributes.entrySet()) {
AttributeIfc attributeIfc = attrEntry.getValue();
if (attributeIfc instanceof TOAttribute) {
}
}
- private void createTOInternal(TOAttribute toAttribute) {
+ private void createTOInternal(final TOAttribute toAttribute) {
Map<String, AttributeIfc> attrs = toAttribute.getCapitalizedPropertiesToTypesMap();
// recursive processing of TO's attributes
private List<Field> fields;
private List<MethodDefinition> methods;
- public TOInternal(Type type, Map<String, AttributeIfc> attrs) {
+ public TOInternal(final Type type, final Map<String, AttributeIfc> attrs) {
this(type.getFullyQualifiedName(), type.getName(), attrs, type.getPackageName());
}
- public TOInternal(String fullyQualifiedName, String name,
- Map<String, AttributeIfc> attrs, String packageName) {
+ public TOInternal(final String fullyQualifiedName, final String name,
+ final Map<String, AttributeIfc> attrs, final String packageName) {
this.fullyQualifiedName = fullyQualifiedName;
this.name = name;
processAttrs(attrs, packageName);
private final static String dependencyResolverVarName = "dependencyResolver";
private final static String dependencyResolverInjectMethodName = "injectDependencyResolver";
- private void processAttrs(Map<String, AttributeIfc> attrs, String packageName) {
+ private void processAttrs(final Map<String, AttributeIfc> attrs, final String packageName) {
fields = Lists.newArrayList();
methods = Lists.newArrayList();
for (Entry<String, AttributeIfc> attrEntry : attrs.entrySet()) {
String innerName = attrEntry.getKey();
- String varName = BindingGeneratorUtil
- .parseToValidParamName(attrEntry.getKey());
+ String varName = BindingMapping.getPropertyName(attrEntry.getKey());
String fullyQualifiedName, nullableDefault = null;
if (attrEntry.getValue() instanceof TypedAttribute) {
private static class MXBeanInterfaceAttributesProcessor {
private final List<MethodDeclaration> methods = Lists.newArrayList();
- void processAttributes(Map<String, AttributeIfc> attributes) {
+ void processAttributes(final Map<String, AttributeIfc> attributes) {
for (Entry<String, AttributeIfc> attrEntry : attributes.entrySet()) {
String returnType;
AttributeIfc attributeIfc = attrEntry.getValue();
MethodDeclaration getter = new MethodDeclaration(returnType,
getterName, Collections.<Field> emptyList());
- String varName = BindingGeneratorUtil
- .parseToValidParamName(attrEntry.getKey());
+ String varName = BindingMapping.getPropertyName(attrEntry.getKey());
String setterName = "set"
+ attributeIfc.getUpperCaseCammelCase();
MethodDeclaration setter = new MethodDeclaration("void",
private final List<Field> fields = Lists.newArrayList();
- void processAttributes(Map<String, AttributeIfc> attributes,
- String packageName) {
+ void processAttributes(final Map<String, AttributeIfc> attributes,
+ final String packageName) {
for (Entry<String, AttributeIfc> attrEntry : attributes.entrySet()) {
String type;
String nullableDefaultWrapped = null;
private final List<ModuleField> moduleFields;
private final List<MethodDefinition> methods;
- private Holder(List<ModuleField> moduleFields, List<MethodDefinition> methods) {
+ private Holder(final List<ModuleField> moduleFields, final List<MethodDefinition> methods) {
this.moduleFields = Collections.unmodifiableList(moduleFields);
this.methods = Collections.unmodifiableList(methods);
}
private final Holder holder;
- private AbstractModuleAttributesProcessor(Map<String, AttributeIfc> attributes) {
+ private AbstractModuleAttributesProcessor(final Map<String, AttributeIfc> attributes) {
this.holder = processAttributes(attributes);
}
- private static Holder processAttributes(Map<String, AttributeIfc> attributes) {
+ private static Holder processAttributes(final Map<String, AttributeIfc> attributes) {
List<ModuleField> moduleFields = new ArrayList<>();
List<MethodDefinition> methods = new ArrayList<>();
for (Entry<String, AttributeIfc> attrEntry : attributes.entrySet()) {
}
}
- String varName = BindingGeneratorUtil
- .parseToValidParamName(attrEntry.getKey());
+ String varName = BindingMapping.getPropertyName(attrEntry.getKey());
ModuleField field;
if (isIdentity) {
}
- private static boolean needsDepResolver(AttributeIfc value) {
+ private static boolean needsDepResolver(final AttributeIfc value) {
if(value instanceof TOAttribute) {
return true;
}
return false;
}
- private static String getInnerTypeFromIdentity(Type type) {
+ private static String getInnerTypeFromIdentity(final Type type) {
Preconditions.checkArgument(type instanceof ParameterizedType);
Type[] args = ((ParameterizedType) type).getActualTypeArguments();
Preconditions.checkArgument(args.length ==1);
import static org.junit.Assert.assertThat;
import static org.junit.Assert.assertTrue;
import static org.junit.Assert.fail;
-import static org.mockito.Matchers.any;
-import static org.mockito.Mockito.doNothing;
import static org.mockito.Mockito.doReturn;
import static org.mockito.Mockito.mock;
-
import com.google.common.base.Predicate;
import com.google.common.collect.Collections2;
import com.google.common.collect.Lists;
import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import org.apache.commons.io.FileUtils;
-import org.apache.maven.plugin.logging.Log;
import org.apache.maven.project.MavenProject;
import org.eclipse.jdt.core.JavaCore;
import org.eclipse.jdt.core.compiler.IProblem;
File targetDir = new File(generatorOutputPath, "target");
generatedResourcesDir = new File(targetDir, "generated-resources");
jmxGenerator.setResourceBaseDir(generatedResourcesDir);
- Log mockedLog = mock(Log.class);
- doReturn(false).when(mockedLog).isDebugEnabled();
- doNothing().when(mockedLog).debug(any(CharSequence.class));
- doNothing().when(mockedLog).info(any(CharSequence.class));
- doNothing().when(mockedLog).error(any(CharSequence.class),
- any(Throwable.class));
- jmxGenerator.setLog(mockedLog);
MavenProject project = mock(MavenProject.class);
doReturn(generatorOutputPath).when(project).getBasedir();
jmxGenerator.setMavenProject(project);
verifyModuleFactoryFile(false);
}
- private void verifyModuleFactoryFile(boolean shouldBePresent) {
+ private void verifyModuleFactoryFile(final boolean shouldBePresent) {
File factoryFile = new File(generatedResourcesDir, "META-INF"
+ File.separator + "services" + File.separator
+ ModuleFactory.class.getName());
- if (!shouldBePresent)
+ if (!shouldBePresent) {
assertFalse("Factory file should not be generated",
factoryFile.exists());
- else
+ } else {
assertTrue("Factory file should be generated", factoryFile.exists());
+ }
}
- public static List<String> toFileNames(Collection<File> files) {
+ public static List<String> toFileNames(final Collection<File> files) {
List<String> result = new ArrayList<>();
for (File f : files) {
result.add(f.getName());
new Predicate<File>() {
@Override
- public boolean apply(File input) {
+ public boolean apply(final File input) {
return input.getName().endsWith("xml");
}
});
new Predicate<File>() {
@Override
- public boolean apply(File input) {
+ public boolean apply(final File input) {
return input.getName().endsWith("java");
}
});
String name = file.getName();
MbeASTVisitor visitor = new MbeASTVisitor();
verifiers.put(name, visitor);
- if (name.equals("AbstractDynamicThreadPoolModule.java"))
+ if (name.equals("AbstractDynamicThreadPoolModule.java")) {
abstractDynamicThreadPoolModuleVisitor = visitor;
- if (name.equals("AsyncEventBusModuleMXBean.java"))
+ }
+ if (name.equals("AsyncEventBusModuleMXBean.java")) {
asyncEventBusModuleMXBeanVisitor = visitor;
- if (name.equals("AbstractNamingThreadFactoryModuleFactory.java"))
+ }
+ if (name.equals("AbstractNamingThreadFactoryModuleFactory.java")) {
abstractNamingThreadFactoryModuleFactoryVisitor = visitor;
- if (name.equals("AsyncEventBusModule.java"))
+ }
+ if (name.equals("AsyncEventBusModule.java")) {
asyncEventBusModuleVisitor = visitor;
- if (name.equals("EventBusModuleFactory.java"))
+ }
+ if (name.equals("EventBusModuleFactory.java")) {
eventBusModuleFactoryVisitor = visitor;
+ }
}
processGeneratedCode(javaFiles, verifiers);
}
- private void verifyXmlFiles(Collection<File> xmlFiles) throws Exception {
+ private void verifyXmlFiles(final Collection<File> xmlFiles) throws Exception {
ErrorHandler errorHandler = new ErrorHandler() {
@Override
- public void warning(SAXParseException exception)
+ public void warning(final SAXParseException exception)
throws SAXException {
fail("Generated blueprint xml is not well formed "
+ exception.getMessage());
}
@Override
- public void fatalError(SAXParseException exception)
+ public void fatalError(final SAXParseException exception)
throws SAXException {
fail("Generated blueprint xml is not well formed "
+ exception.getMessage());
}
@Override
- public void error(SAXParseException exception) throws SAXException {
+ public void error(final SAXParseException exception) throws SAXException {
fail("Generated blueprint xml is not well formed "
+ exception.getMessage());
}
}
- private void assertEventBusModuleFactory(MbeASTVisitor visitor) {
+ private void assertEventBusModuleFactory(final MbeASTVisitor visitor) {
assertEquals(PackageTranslatorTest.EXPECTED_PACKAGE_PREFIX
+ ".threads.java", visitor.packageName);
assertEquals("EventBusModuleFactory", visitor.type);
visitor.methodJavadoc.size());
}
- private void assertAsyncEventBusModule(MbeASTVisitor visitor) {
+ private void assertAsyncEventBusModule(final MbeASTVisitor visitor) {
assertEquals(PackageTranslatorTest.EXPECTED_PACKAGE_PREFIX
+ ".threads.java", visitor.packageName);
assertEquals("AsyncEventBusModule", visitor.type);
}
private void assertAbstractNamingThreadFactoryModuleFactory(
- MbeASTVisitor visitor) {
+ final MbeASTVisitor visitor) {
assertEquals(PackageTranslatorTest.EXPECTED_PACKAGE_PREFIX
+ ".threads.java", visitor.packageName);
assertEquals("AbstractNamingThreadFactoryModuleFactory", visitor.type);
}
- private void assertFactoryMethods(Set<String> methods, int expectedSize) {
+ private void assertFactoryMethods(final Set<String> methods, final int expectedSize) {
List<ArgumentAssertion> args = Lists.newArrayList();
ArgumentAssertion oldInstanceArg = new ArgumentAssertion(DynamicMBeanWithInstance.class.getCanonicalName(), "old");
}
- private void assertMethodPresent(Set<String> methods, MethodAssertion methodAssertion) {
+ private void assertMethodPresent(final Set<String> methods, final MethodAssertion methodAssertion) {
assertTrue(String.format("Generated methods did not contain %s, generated methods: %s",
methodAssertion.toString(), methods), methods.contains(methodAssertion.toString()));
}
- private void assertAsyncEventBusModuleMXBean(MbeASTVisitor visitor) {
+ private void assertAsyncEventBusModuleMXBean(final MbeASTVisitor visitor) {
assertEquals(PackageTranslatorTest.EXPECTED_PACKAGE_PREFIX
+ ".threads.java", visitor.packageName);
assertEquals("AsyncEventBusModuleMXBean", visitor.type);
}
- private void assertAbstractDynamicThreadPoolModule(MbeASTVisitor visitor) {
+ private void assertAbstractDynamicThreadPoolModule(final MbeASTVisitor visitor) {
assertEquals(PackageTranslatorTest.EXPECTED_PACKAGE_PREFIX
+ ".threads.java", visitor.packageName);
assertNotNull(visitor.javadoc);
visitor.methodJavadoc.get("void setMaximumSize(java.lang.Long maximumSize)"));
}
- private void assertDeclaredField(Set<String> fieldDeclarations,
- String declaration) {
+ private void assertDeclaredField(final Set<String> fieldDeclarations,
+ final String declaration) {
assertTrue("Missing field " + declaration + ", got: "
+ fieldDeclarations,
fieldDeclarations.contains(declaration + ";\n"));
protected Map<String, String> methodDescriptions = Maps.newHashMap();
@Override
- public boolean visit(PackageDeclaration node) {
+ public boolean visit(final PackageDeclaration node) {
packageName = node.getName().toString();
return super.visit(node);
}
@Override
- public boolean visit(NormalAnnotation node) {
+ public boolean visit(final NormalAnnotation node) {
if (node.getTypeName().toString()
.equals(Description.class.getCanonicalName())) {
if (node.getParent() instanceof TypeDeclaration) {
}
@Override
- public boolean visit(TypeDeclaration node) {
+ public boolean visit(final TypeDeclaration node) {
javadoc = node.getJavadoc() == null ? null : node.getJavadoc()
.toString();
type = node.getName().toString();
private final Map<String, String> methodJavadoc = Maps.newHashMap();
@Override
- public boolean visit(NormalAnnotation node) {
+ public boolean visit(final NormalAnnotation node) {
boolean result = super.visit(node);
if (node.getTypeName().toString()
.equals(RequireInterface.class.getCanonicalName())
}
@Override
- public boolean visit(FieldDeclaration node) {
+ public boolean visit(final FieldDeclaration node) {
fieldDeclarations.add(node.toString());
return super.visit(node);
}
@Override
- public boolean visit(MethodDeclaration node) {
- if (node.isConstructor())
+ public boolean visit(final MethodDeclaration node) {
+ if (node.isConstructor()) {
constructors.add(node.toString());
- else {
+ } else {
String methodSignature = node.getReturnType2() + " " + node.getName() + "(";
boolean first = true;
for (Object o : node.parameters()) {
}
@Override
- public boolean visit(TypeDeclaration node) {
+ public boolean visit(final TypeDeclaration node) {
boolean visit = super.visit(node);
List<?> superIfcs = node.superInterfaceTypes();
implmts = superIfcs != null && !superIfcs.isEmpty() ? superIfcs
}
- private void assertContains(String source, String... contained) {
+ private void assertContains(final String source, final String... contained) {
for (String string : contained) {
assertThat(source, containsString(string));
}
}
- private void processGeneratedCode(Collection<File> files,
- Map<String, ASTVisitor> verifiers) throws IOException {
+ private void processGeneratedCode(final Collection<File> files,
+ final Map<String, ASTVisitor> verifiers) throws IOException {
ASTParser parser = ASTParser.newParser(AST.JLS3);
Map<?, ?> options = JavaCore.getOptions();
JavaCore.setComplianceOptions(JavaCore.VERSION_1_7, options);
for (IProblem c : cu.getProblems()) {
// 1610613332 = Syntax error, annotations are only available if
// source level is 5.0
- if (c.getID() == 1610613332)
+ if (c.getID() == 1610613332) {
continue;
+ }
// 1610613332 = Syntax error, parameterized types are only
// available if source level is 5.0
- if (c.getID() == 1610613329)
+ if (c.getID() == 1610613329) {
continue;
- if (c.getID() == 1610613328) // 'for each' statements are only available if source level is 5.0
+ }
+ if (c.getID() == 1610613328) {
continue;
+ }
fail("Error in generated source code " + file + ":"
+ c.getSourceLineNumber() + " id: " + c.getID() + " message:" + c.toString());
}
ASTVisitor visitor = verifiers.get(file.getName());
- if (visitor == null)
+ if (visitor == null) {
fail("Unknown generated file " + file.getName());
+ }
cu.accept(visitor);
}
}
- public static char[] readFileAsChars(File file) throws IOException {
+ public static char[] readFileAsChars(final File file) throws IOException {
List<String> readLines = Files
.readLines(file, Charset.forName("utf-8"));
char[] retVal = new char[0];
private static class MethodAssertion extends ArgumentAssertion{
- private List<ArgumentAssertion> arguments;
+ private final List<ArgumentAssertion> arguments;
- MethodAssertion(String type, String name, List<ArgumentAssertion> arguments) {
+ MethodAssertion(final String type, final String name, final List<ArgumentAssertion> arguments) {
super(type, name);
this.arguments = arguments;
}
- MethodAssertion(String type, String name) {
+ MethodAssertion(final String type, final String name) {
this(type, name, Collections.<ArgumentAssertion>emptyList());
}
for (ArgumentAssertion argument : arguments) {
sb.append(argument.type).append(' ');
sb.append(argument.name);
- if(++i != arguments.size())
+ if(++i != arguments.size()) {
sb.append(',');
+ }
}
sb.append(')');
return sb.toString();
protected final String type, name;
- private ArgumentAssertion(String type, String name) {
+ private ArgumentAssertion(final String type, final String name) {
this.type = type;
this.name = name;
}
<groupId>org.osgi</groupId>
<artifactId>org.osgi.core</artifactId>
</dependency>
+
+ <dependency>
+ <groupId>junit</groupId>
+ <artifactId>junit</artifactId>
+ </dependency>
+ <dependency>
+ <groupId>org.opendaylight.controller</groupId>
+ <artifactId>sal-test-model</artifactId>
+ </dependency>
+ <dependency>
+ <groupId>org.opendaylight.yangtools</groupId>
+ <artifactId>yang-data-impl</artifactId>
+ <scope>test</scope>
+ </dependency>
</dependencies>
<build>
<plugins>
--- /dev/null
+/*
+ * Copyright (c) 2015 Cisco Systems, Inc. and others. All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+package org.opendaylight.controller.md.sal.dom.api;
+
+import com.google.common.base.Preconditions;
+
+
+/**
+ * Failure reported when a data tree is no longer accessible.
+ */
+public class DOMDataTreeInaccessibleException extends DOMDataTreeListeningException {
+ private static final long serialVersionUID = 1L;
+ private final DOMDataTreeIdentifier treeIdentifier;
+
+ public DOMDataTreeInaccessibleException(final DOMDataTreeIdentifier treeIdentifier, final String message) {
+ super(message);
+ this.treeIdentifier = Preconditions.checkNotNull(treeIdentifier);
+ }
+
+ public DOMDataTreeInaccessibleException(final DOMDataTreeIdentifier treeIdentifier, final String message, final Throwable cause) {
+ super(message);
+ this.treeIdentifier = Preconditions.checkNotNull(treeIdentifier);
+ }
+
+ public final DOMDataTreeIdentifier getTreeIdentifier() {
+ return treeIdentifier;
+ }
+}
--- /dev/null
+/*
+ * Copyright (c) 2015 Cisco Systems, Inc. and others. All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+package org.opendaylight.controller.md.sal.dom.api;
+
+import java.util.Collection;
+import java.util.EventListener;
+import java.util.Map;
+import javax.annotation.Nonnull;
+import org.opendaylight.yangtools.yang.data.api.schema.NormalizedNode;
+import org.opendaylight.yangtools.yang.data.api.schema.tree.DataTreeCandidate;
+
+/**
+ * Interface implemented by data consumers, e.g. processes wanting to act on data
+ * after it has been introduced to the conceptual data tree.
+ */
+public interface DOMDataTreeListener extends EventListener {
+ /**
+ * Invoked whenever one or more registered subtrees change. The logical changes are reported,
+ * as well as the roll up of new state for all subscribed subtrees.
+ *
+ * @param changes The set of changes being reported. Each subscribed subtree may be present
+ * at most once.
+ * @param subtrees Per-subtree state as visible after the reported changes have been applied.
+ * This includes all the subtrees this listener is subscribed to, even those
+ * which have not changed.
+ */
+ void onDataTreeChanged(@Nonnull Collection<DataTreeCandidate> changes, @Nonnull Map<DOMDataTreeIdentifier, NormalizedNode<?, ?>> subtrees);
+
+ /**
+ * Invoked when a subtree listening failure occurs. This can be triggered, for example, when
+ * a connection to external subtree source is broken. The listener will not receive any other
+ * callbacks, but its registration still needs to be closed to prevent resource leak.
+ *
+ * @param cause Collection of failure causes, may not be null or empty.
+ */
+ void onDataTreeFailed(@Nonnull Collection<DOMDataTreeListeningException> causes);
+}
--- /dev/null
+/*
+ * Copyright (c) 2015 Cisco Systems, Inc. and others. All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+package org.opendaylight.controller.md.sal.dom.api;
+
+/**
+ * Base exception for various causes why and {@link DOMDataTreeListener}
+ * may be terminated by the {@link DOMDataTreeService} implementation.
+ */
+public class DOMDataTreeListeningException extends Exception {
+ private static final long serialVersionUID = 1L;
+
+ public DOMDataTreeListeningException(final String message) {
+ super(message);
+ }
+
+ public DOMDataTreeListeningException(final String message, final Throwable cause) {
+ super(message, cause);
+ }
+}
--- /dev/null
+/*
+ * Copyright (c) 2015 Cisco Systems, Inc. and others. All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+package org.opendaylight.controller.md.sal.dom.api;
+
+import javax.annotation.Nonnull;
+
+/**
+ * Exception thrown when a loop is detected in the way {@link DOMDataTreeListener}
+ * and {@link DOMDataTreeProducer} instances would be connected.
+ */
+public class DOMDataTreeLoopException extends Exception {
+ private static final long serialVersionUID = 1L;
+
+ public DOMDataTreeLoopException(final @Nonnull String message) {
+ super(message);
+ }
+
+ public DOMDataTreeLoopException(final @Nonnull String message, final @Nonnull Throwable cause) {
+ super(message, cause);
+ }
+}
--- /dev/null
+/*
+ * Copyright (c) 2015 Cisco Systems, Inc. and others. All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+package org.opendaylight.controller.md.sal.dom.api;
+
+import java.util.Collection;
+import javax.annotation.Nonnull;
+
+/**
+ * A data producer context. It allows transactions to be submitted to the subtrees
+ * specified at instantiation time. At any given time there may be a single transaction
+ * open. It needs to be either submitted or cancelled before another one can be open.
+ * Once a transaction is submitted, it will proceed to be committed asynchronously.
+ *
+ * Each instance has an upper bound on the number of transactions which can be in-flight,
+ * once that capacity is exceeded, an attempt to create a new transaction will block
+ * until some transactions complete.
+ *
+ * Each {@link DOMDataTreeProducer} can be in two logical states, bound and unbound,
+ * which define the lifecycle rules for when is it legal to create and submit transactions
+ * in relationship with {@link DOMDataTreeListener} callbacks.
+ *
+ * When a producer is first created, it is unbound. In this state the producer can be
+ * accessed by any application thread to allocate or submit transactions, as long as
+ * the 'single open transaction' rule is maintained. The producer and any transaction
+ * object MUST NOT be accessed, directly or indirectly, from a {@link DOMDataTreeListener}
+ * callback.
+ *
+ * When a producer is referenced in a call to {@link DOMDataTreeService#registerListener(DOMDataTreeListener, java.util.Collection, boolean, java.util.Collection)},
+ * an attempt will be made to bind the producer to the specified {@link DOMDataTreeListener}.
+ * Such an attempt will fail the producer is already bound, or it has an open transaction.
+ * Once bound, the producer can only be accessed from within the {@link DOMDataTreeListener}
+ * callback on that particular instance. Any transaction which is not submitted by the
+ * time the callback returns will be implicitly cancelled. A producer becomes unbound
+ * when the listener it is bound to becomes unregistered.
+ */
+public interface DOMDataTreeProducer extends DOMDataTreeProducerFactory, AutoCloseable {
+ /**
+ * Allocate a new open transaction on this producer. Any and all transactions
+ * previously allocated must have been either submitted or cancelled by the
+ * time this method is invoked.
+ *
+ * @param barrier Indicates whether this transaction should be a barrier. A barrier
+ * transaction is processed separately from any preceding transactions.
+ * Non-barrier transactions may be merged and processed in a batch,
+ * such that any observers see the modifications contained in them as
+ * if the modifications were made in a single transaction.
+ * @return A new {@link DOMDataWriteTransaction}
+ * @throws {@link IllegalStateException} if a previous transaction was not closed.
+ * @throws {@link IllegalThreadStateException} if the calling thread context does not
+ * match the lifecycle rules enforced by the producer state (e.g. bound or unbound).
+ * This exception is thrown on a best effort basis and programs should not rely
+ * on it for correct operation.
+ */
+ @Nonnull DOMDataWriteTransaction createTransaction(boolean isolated);
+
+ /**
+ * {@inheritDoc}
+ *
+ * When invoked on a {@link DOMDataTreeProducer}, this method has additional restrictions.
+ * There may not be an open transaction from this producer. The method needs to be
+ * invoked in appropriate context, e.g. bound or unbound.
+ *
+ * Specified subtrees must be accessible by this producer. Accessible means they are a subset
+ * of the subtrees specified when the producer is instantiated. The set is further reduced as
+ * child producers are instantiated -- if you create a producer for /a and then a child for
+ * /a/b, /a/b is not accessible from the first producer.
+ *
+ * Once this method returns successfully, this (parent) producer loses the ability to
+ * access the specified paths until the resulting (child) producer is shut down.
+ *
+ * @throws {@link IllegalStateException} if there is an open transaction
+ * @throws {@link IllegalArgumentException} if subtrees contains a subtree which is not
+ * accessible by this producer
+ * @throws {@link IllegalThreadStateException} if the calling thread context does not
+ * match the lifecycle rules enforced by the producer state (e.g. bound or unbound).
+ * This exception is thrown on a best effort basis and programs should not rely
+ * on it for correct operation.
+ */
+ @Override
+ @Nonnull DOMDataTreeProducer createProducer(@Nonnull Collection<DOMDataTreeIdentifier> subtrees);
+
+ /**
+ * {@inheritDoc}
+ *
+ * @throws DOMDataTreeProducerBusyException when there is an open transaction.
+ */
+ @Override
+ void close() throws DOMDataTreeProducerException;
+}
--- /dev/null
+/*
+ * Copyright (c) 2015 Cisco Systems, Inc. and others. All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+package org.opendaylight.controller.md.sal.dom.api;
+
+/**
+ * Exception indicating that the {@link DOMDataTreeProducer} has an open user
+ * transaction and cannot be closed.
+ */
+public class DOMDataTreeProducerBusyException extends DOMDataTreeProducerException {
+ private static final long serialVersionUID = 1L;
+
+ public DOMDataTreeProducerBusyException(final String message) {
+ super(message);
+ }
+
+ public DOMDataTreeProducerBusyException(final String message, final Throwable cause) {
+ super(message, cause);
+ }
+}
--- /dev/null
+/*
+ * Copyright (c) 2015 Cisco Systems, Inc. and others. All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+package org.opendaylight.controller.md.sal.dom.api;
+
+/**
+ * Base exception for all exceptions related to {@link DOMDataTreeProducer}s.
+ */
+public class DOMDataTreeProducerException extends Exception {
+ private static final long serialVersionUID = 1L;
+
+ public DOMDataTreeProducerException(final String message) {
+ super(message);
+ }
+
+ public DOMDataTreeProducerException(final String message, final Throwable cause) {
+ super(message, cause);
+ }
+}
--- /dev/null
+/*
+ * Copyright (c) 2015 Cisco Systems, Inc. and others. All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+package org.opendaylight.controller.md.sal.dom.api;
+
+import java.util.Collection;
+import javax.annotation.Nonnull;
+
+/**
+ * Base source of {@link DOMDataTreeProducer}s. This interface is usually not used directly,
+ * but rather through one of its sub-interfaces.
+ */
+public interface DOMDataTreeProducerFactory {
+ /**
+ * Create a producer, which is able to access to a set of trees.
+ *
+ * @param subtrees The collection of subtrees the resulting producer should have access to.
+ * @return A {@link DOMDataTreeProducer} instance.
+ * @throws {@link IllegalArgumentException} if subtrees is empty.
+ */
+ @Nonnull DOMDataTreeProducer createProducer(@Nonnull Collection<DOMDataTreeIdentifier> subtrees);
+}
--- /dev/null
+/*
+ * Copyright (c) 2015 Cisco Systems, Inc. and others. All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+package org.opendaylight.controller.md.sal.dom.api;
+
+import java.util.Collection;
+import javax.annotation.Nonnull;
+import org.opendaylight.yangtools.concepts.ListenerRegistration;
+
+/**
+ * A {@link DOMService} providing access to the conceptual data tree. Interactions
+ * with the data tree are split into data producers and consumers (listeners). Each
+ * of them operate on a set of subtrees, which need to be declared at instantiation time.
+ *
+ * Returned instances are not thread-safe and expected to be used by a single thread
+ * at a time. Furthermore, producers may not be accessed from consumer callbacks
+ * unless they were specified when the listener is registered.
+ *
+ * The service maintains a loop-free topology of producers and consumers. What this means
+ * is that a consumer is not allowed to access a producer, which affects any of the
+ * subtrees it is subscribed to. This restriction is in place to ensure the system does
+ * not go into a feedback loop, where it is impossible to block either a producer or
+ * a consumer without accumulating excess work in the backlog stemming from its previous
+ * activity.
+ */
+public interface DOMDataTreeService extends DOMDataTreeProducerFactory, DOMService {
+ /**
+ * Register a {@link DOMDataTreeListener} instance. Once registered, the listener
+ * will start receiving changes on the selected subtrees. If the listener cannot
+ * keep up with the rate of changes, and allowRxMerges is set to true, this service
+ * is free to merge the changes, so that a smaller number of them will be reported,
+ * possibly hiding some data transitions (like flaps).
+ *
+ * If the listener wants to write into any producer, that producer has to be mentioned
+ * in the call to this method. Those producers will be bound exclusively to the
+ * registration, so that accessing them outside of this listener's callback will trigger
+ * an error. Any producers mentioned must be idle, e.g. they may not have an open
+ * transaction at the time this method is invoked.
+ *
+ * Each listener instance can be registered at most once. Implementations of this
+ * interface have to guarantee that the listener's methods will not be invoked
+ * concurrently from multiple threads.
+ *
+ * @param listener {@link DOMDataTreeListener} that is being registered
+ * @param subtrees Conceptual subtree identifier of subtrees which should be monitored
+ * for changes. May not be null or empty.
+ * @param allowRxMerges True if the backend may perform ingress state compression.
+ * @param producers {@link DOMDataTreeProducer} instances to bind to the listener.
+ * @return A listener registration. Once closed, the listener will no longer be
+ * invoked and the producers will be unbound.
+ * @throws IllegalArgumentException if subtrees is empty or the listener is already bound
+ * @throws DOMDataTreeLoopException if the registration of the listener to the specified
+ * subtrees with specified producers would form a
+ * feedback loop
+ */
+ @Nonnull <T extends DOMDataTreeListener> ListenerRegistration<T> registerListener(@Nonnull T listener,
+ @Nonnull Collection<DOMDataTreeIdentifier> subtrees, boolean allowRxMerges, @Nonnull Collection<DOMDataTreeProducer> producers);
+}
--- /dev/null
+/*
+ * Copyright (c) 2015 Cisco Systems, Inc. and others. All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+package org.opendaylight.controller.md.sal.dom.api;
+
+import java.util.EventListener;
+import javax.annotation.Nonnull;
+
+/**
+ * A single shard of the conceptual data tree. This interface defines the basic notifications
+ * a shard can receive. Each shard implementation is expected to also implement some of the
+ * datastore-level APIs. Which interfaces are required depends on the {@link DOMDataTreeShardingService}
+ * implementation.
+ */
+public interface DOMDataTreeShard extends EventListener {
+ /**
+ * Invoked whenever a child is getting attached as a more specific prefix under this shard.
+ *
+ * @param prefix Child's prefix
+ * @param child Child shard
+ */
+ void onChildAttached(@Nonnull DOMDataTreeIdentifier prefix, @Nonnull DOMDataTreeShard child);
+
+ /**
+ * Invoked whenever a child is getting detached as a more specific prefix under this shard.
+ *
+ * @param prefix Child's prefix
+ * @param child Child shard
+ */
+ void onChildDetached(@Nonnull DOMDataTreeIdentifier prefix, @Nonnull DOMDataTreeShard child);
+}
--- /dev/null
+/*
+ * Copyright (c) 2015 Cisco Systems, Inc. and others. All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+package org.opendaylight.controller.md.sal.dom.api;
+
+import javax.annotation.Nonnull;
+
+/**
+ * Exception thrown when an attempt to attach a conflicting shard to the global
+ * table.
+ */
+public class DOMDataTreeShardingConflictException extends Exception {
+ private static final long serialVersionUID = 1L;
+
+ public DOMDataTreeShardingConflictException(final @Nonnull String message) {
+ super(message);
+ }
+
+ public DOMDataTreeShardingConflictException(final @Nonnull String message, final @Nonnull Throwable cause) {
+ super(message, cause);
+ }
+}
--- /dev/null
+/*
+ * Copyright (c) 2015 Cisco Systems, Inc. and others. All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+package org.opendaylight.controller.md.sal.dom.api;
+
+import javax.annotation.Nonnull;
+import org.opendaylight.yangtools.concepts.ListenerRegistration;
+
+/**
+ * A {@link DOMService} providing access to details on how the conceptual data tree
+ * is distributed among providers (also known as shards). Each shard is tied to a
+ * single {@link DOMDataTreeIdentifier}. Based on those data tree identifiers, the
+ * shards are organized in a tree, where there is a logical parent/child relationship.
+ *
+ * It is not allowed to attach two shards to the same data tree identifier, which means
+ * the mapping of each piece of information has an unambiguous home. When accessing
+ * the information, the shard with the longest matching data tree identifier is used,
+ * which is why this interface treats it is a prefix.
+ *
+ * Whenever a parent/child relationship is changed, the parent is notified, so it can
+ * understand that a logical child has been attached.
+ */
+public interface DOMDataTreeShardingService extends DOMService {
+ /**
+ * Register a shard as responsible for a particular subtree prefix.
+ *
+ * @param prefix Data tree identifier, may not be null.
+ * @param shard Responsible shard instance
+ * @return A registration. To remove the shard's binding, close the registration.
+ * @throws DOMDataTreeShardingConflictException if the prefix is already bound
+ */
+ @Nonnull <T extends DOMDataTreeShard> ListenerRegistration<T> registerDataTreeShard(@Nonnull DOMDataTreeIdentifier prefix, @Nonnull T shard) throws DOMDataTreeShardingConflictException;
+}
--- /dev/null
+/*
+ * Copyright (c) 2015 Cisco Systems, Inc. and others. All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+package org.opendaylight.controller.md.sal.dom.api;
+
+import static org.junit.Assert.assertNotNull;
+import com.google.common.util.concurrent.CheckedFuture;
+import java.net.URI;
+import java.util.Collections;
+import javax.annotation.Nonnull;
+import org.junit.Test;
+import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType;
+import org.opendaylight.controller.md.sal.common.api.data.TransactionCommitFailedException;
+import org.opendaylight.yangtools.yang.common.QName;
+import org.opendaylight.yangtools.yang.common.QNameModule;
+import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier;
+import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier.NodeIdentifier;
+import org.opendaylight.yangtools.yang.data.impl.schema.builder.impl.ImmutableContainerNodeBuilder;
+
+/**
+ * Abstract test suite demonstrating various access patterns on how a {@link DOMDataTreeService}
+ * can be used.
+ */
+public abstract class AbstractDOMDataTreeServiceTestSuite {
+ protected static final QNameModule TEST_MODULE = QNameModule.create(URI.create("urn:opendaylight:params:xml:ns:yang:controller:md:sal:test:store"), null);
+
+ protected static final YangInstanceIdentifier UNORDERED_CONTAINER_IID = YangInstanceIdentifier.create(
+ new NodeIdentifier(QName.create(TEST_MODULE, "lists")),
+ new NodeIdentifier(QName.create(TEST_MODULE, "unordered-container")));
+ protected static final DOMDataTreeIdentifier UNORDERED_CONTAINER_TREE = new DOMDataTreeIdentifier(LogicalDatastoreType.OPERATIONAL, UNORDERED_CONTAINER_IID);
+
+ /**
+ * Return a reference to the service used in this test. The instance
+ * needs to be reused within the same test and must be isolated between
+ * tests.
+ *
+ * @return {@link DOMDataTreeService} instance.
+ */
+ protected abstract @Nonnull DOMDataTreeService service();
+
+ /**
+ * A simple unbound producer. It write some basic things into the data store based on the
+ * test model.
+ * @throws DOMDataTreeProducerException
+ * @throws TransactionCommitFailedException
+ */
+ @Test
+ public final void testBasicProducer() throws DOMDataTreeProducerException, TransactionCommitFailedException {
+ // Create a producer. It is an AutoCloseable resource, hence the try-with pattern
+ try (final DOMDataTreeProducer prod = service().createProducer(Collections.singleton(UNORDERED_CONTAINER_TREE))) {
+ assertNotNull(prod);
+
+ final DOMDataWriteTransaction tx = prod.createTransaction(true);
+ assertNotNull(tx);
+
+ tx.put(LogicalDatastoreType.OPERATIONAL, UNORDERED_CONTAINER_IID, ImmutableContainerNodeBuilder.create().build());
+
+ final CheckedFuture<Void, TransactionCommitFailedException> f = tx.submit();
+ assertNotNull(f);
+
+ f.checkedGet();
+ }
+ }
+
+ // TODO: simple listener
+}
<groupId>org.osgi</groupId>
<artifactId>org.osgi.core</artifactId>
</dependency>
+ <dependency>
+ <groupId>junit</groupId>
+ <artifactId>junit</artifactId>
+ </dependency>
</dependencies>
<build>
<plugins>