From: Tony Tkacik Date: Fri, 6 Jun 2014 08:14:13 +0000 (+0000) Subject: Merge "BUG 624 - Make netconf TCP port optional." X-Git-Tag: release/helium~703 X-Git-Url: https://git.opendaylight.org/gerrit/gitweb?p=controller.git;a=commitdiff_plain;h=e3b0eb3bd7f61ab9f54a61d8b8e2d37685262e2c;hp=8dd063e01eda1ce8f8c3cf0b49af17d6dfff388e Merge "BUG 624 - Make netconf TCP port optional." --- diff --git a/features/base/src/main/resources/features.xml b/features/base/src/main/resources/features.xml index cc112052cc..23051f5a9a 100644 --- a/features/base/src/main/resources/features.xml +++ b/features/base/src/main/resources/features.xml @@ -1,10 +1,7 @@ - + - + http transaction base-felix-dm @@ -21,41 +18,46 @@ mvn:org.opendaylight.controller/dummy-console/1.1.0-SNAPSHOT - + mvn:org.osgi/org.osgi.compendium/${osgi.compendium.version} mvn:org.apache.felix/org.apache.felix.dependencymanager/${felix.dependencymanager.version} mvn:org.apache.felix/org.apache.felix.dependencymanager.shell/${felix.dependencymanager.shell.version} - + mvn:org.apache.aries/org.apache.aries.util/1.1.0 mvn:org.apache.aries.spifly/org.apache.aries.spifly.dynamic.bundle/${spifly.version} mvn:org.ow2.asm/asm-all/4.0 - - wrap:mvn:io.netty/netty-buffer/${netty.version} - wrap:mvn:io.netty/netty-codec/${netty.version} - wrap:mvn:io.netty/netty-transport/${netty.version} - wrap:mvn:io.netty/netty-common/${netty.version} - wrap:mvn:io.netty/netty-handler/${netty.version} - wrap:mvn:io.netty/netty-codec-http/${netty.version} - mvn:org.opendaylight.controller.thirdparty/ganymed/1.1-SNAPSHOT - - - base-gemini-web - mvn:org.opendaylight.controller.thirdparty/com.sun.jersey.jersey-servlet/${jersey.version} - mvn:com.sun.jersey/jersey-server/${jersey.version} - mvn:com.sun.jersey/jersey-core/${jersey.version} - mvn:com.sun.jersey/jersey-client/${jersey.version} - mvn:com.sun.jersey/jersey-servlet/${jersey.version} + + wrap:mvn:io.netty/netty-buffer/${netty.version} + wrap:mvn:io.netty/netty-codec/${netty.version} + wrap:mvn:io.netty/netty-transport/${netty.version} + wrap:mvn:io.netty/netty-common/${netty.version} + wrap:mvn:io.netty/netty-handler/${netty.version} + wrap:mvn:io.netty/netty-codec-http/${netty.version} + mvn:org.opendaylight.controller.thirdparty/ganymed/1.1-SNAPSHOT + + + base-gemini-web + mvn:org.opendaylight.controller.thirdparty/com.sun.jersey.jersey-servlet/${jersey.version} + mvn:com.sun.jersey/jersey-server/${jersey.version} + mvn:com.sun.jersey/jersey-core/${jersey.version} + mvn:com.sun.jersey/jersey-client/${jersey.version} + mvn:com.sun.jersey/jersey-servlet/${jersey.version} + mvn:javax.ws.rs/javax.ws.rs-api/2.0 + + http + mvn:com.eclipsesource.jaxrs/jersey-all/${jersey2.version} + mvn:com.eclipsesource.jaxrs/publisher/${jersey2.publisher.version} + mvn:javax.ws.rs/javax.ws.rs-api/${jsr311.v2.api.version} + mvn:javax.annotation/javax.annotation-api/${javax.annotation.version} + mvn:com.fasterxml.jackson.core/jackson-annotations/${jackson.version} mvn:com.fasterxml.jackson.core/jackson-core/${jackson.version} mvn:com.fasterxml.jackson.core/jackson-databind/${jackson.version} mvn:org.codehaus.jettison/jettison/${jettison.version} - mvn:javax.ws.rs/jsr311-api/${jsr311.api.version} mvn:com.fasterxml.jackson.module/jackson-module-jaxb-annotations/${jackson.version} mvn:com.fasterxml.jackson.jaxrs/jackson-jaxrs-base/${jackson.version} mvn:com.fasterxml.jackson.jaxrs/jackson-jaxrs-json-provider/${jackson.version} @@ -66,8 +68,7 @@ mvn:org.slf4j/slf4j-simple/1.7.2 mvn:org.slf4j/slf4j-api/1.7.2 - + mvn:com.google.guava/guava/${guava.version} mvn:org.javassist/javassist/${javassist.version} mvn:commons-io/commons-io/${commons.io.version} diff --git a/opendaylight/commons/opendaylight/pom.xml b/opendaylight/commons/opendaylight/pom.xml index e88e39a61e..077b452f0a 100644 --- a/opendaylight/commons/opendaylight/pom.xml +++ b/opendaylight/commons/opendaylight/pom.xml @@ -88,14 +88,18 @@ 1.7 1.7 3.17.1-GA + 1.2 1.17 1.17 + 4.0 + 2.8 1.3.3 src/main/yang-gen-config 1.1.4 2.0.1 1.1.1 + 2.0 4.8.1 3.0.1 1.0.9 @@ -107,7 +111,7 @@ 1.1-SNAPSHOT 1.9.5 0.2.5-SNAPSHOT - 4.0.17.Final + 4.0.19.Final 0.0.3-SNAPSHOT 0.4.2-SNAPSHOT 0.4.2-SNAPSHOT diff --git a/opendaylight/config/logback-config-loader/pom.xml b/opendaylight/config/logback-config-loader/pom.xml new file mode 100644 index 0000000000..03ff65f662 --- /dev/null +++ b/opendaylight/config/logback-config-loader/pom.xml @@ -0,0 +1,53 @@ + + + + 4.0.0 + + org.opendaylight.controller + config-plugin-parent + 0.2.5-SNAPSHOT + ../config-plugin-parent + + logback-config-loader + bundle + ${project.artifactId} + + 3.0.4 + + + + + ch.qos.logback + logback-classic + + + ch.qos.logback + logback-core + + + org.slf4j + slf4j-api + + + + + junit + junit + test + + + + + + + org.apache.felix + maven-bundle-plugin + + + org.opendaylight.controller.logback.config.loader.Activator + + + + + + diff --git a/opendaylight/config/logback-config-loader/src/main/java/org/opendaylight/controller/logback/config/loader/Activator.java b/opendaylight/config/logback-config-loader/src/main/java/org/opendaylight/controller/logback/config/loader/Activator.java new file mode 100644 index 0000000000..99866d5767 --- /dev/null +++ b/opendaylight/config/logback-config-loader/src/main/java/org/opendaylight/controller/logback/config/loader/Activator.java @@ -0,0 +1,50 @@ +/** + * 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.logback.config.loader; + +import java.io.File; +import java.util.List; + +import org.opendaylight.controller.logback.config.loader.impl.LogbackConfigUtil; +import org.opendaylight.controller.logback.config.loader.impl.LogbackConfigurationLoader; +import org.osgi.framework.BundleActivator; +import org.osgi.framework.BundleContext; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +/** + * default activator for loading multiple logback configuration files + */ +public class Activator implements BundleActivator { + + /** + * expected environment variable name, containing the root folder containing + * logback configurations + */ + private static final String LOGBACK_CONFIG_D = "logback.config.d"; + private static Logger LOG = LoggerFactory.getLogger(Activator.class); + + @Override + public void start(BundleContext context) { + LOG.info("Starting logback configuration loader"); + String logbackConfigRoot = System.getProperty(LOGBACK_CONFIG_D); + LOG.debug("configRoot: {}", logbackConfigRoot); + if (logbackConfigRoot != null) { + File logbackConfigRootFile = new File(logbackConfigRoot); + List sortedConfigFiles = LogbackConfigUtil.harvestSortedConfigFiles(logbackConfigRootFile); + LogbackConfigurationLoader.load(true, sortedConfigFiles.toArray()); + } + } + + @Override + public void stop(BundleContext context) { + LOG.info("Stopping logback configuration loader"); + // TODO: need reset/reload default config? + } + +} diff --git a/opendaylight/config/logback-config-loader/src/main/java/org/opendaylight/controller/logback/config/loader/impl/LogbackConfigUtil.java b/opendaylight/config/logback-config-loader/src/main/java/org/opendaylight/controller/logback/config/loader/impl/LogbackConfigUtil.java new file mode 100644 index 0000000000..ddf14d7dd3 --- /dev/null +++ b/opendaylight/config/logback-config-loader/src/main/java/org/opendaylight/controller/logback/config/loader/impl/LogbackConfigUtil.java @@ -0,0 +1,61 @@ +/** + * 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.logback.config.loader.impl; + +import java.io.File; +import java.io.FileFilter; +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; +import java.util.regex.Pattern; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +/** + * logback config utils + */ +public final class LogbackConfigUtil { + + /** logback config file pattern (*.xml) */ + protected static final String LOGBACK_CONFIG_FILE_REGEX_SEED = ".+\\.xml"; + private static final Logger LOG = LoggerFactory + .getLogger(LogbackConfigUtil.class); + + /** + * forbidden ctor + */ + private LogbackConfigUtil() { + throw new UnsupportedOperationException(); + } + + /** + * @param logConfigRoot folder containing configuration files + * @return sorted list of found files + */ + public static List harvestSortedConfigFiles(File logConfigRoot) { + final Pattern xmlFilePattern = Pattern.compile(LOGBACK_CONFIG_FILE_REGEX_SEED); + File[] configs = logConfigRoot.listFiles(new FileFilter() { + @Override + public boolean accept(File pathname) { + return pathname.isFile() + && xmlFilePattern.matcher(pathname.getName()).find(); + } + }); + + List sortedConfigFiles = new ArrayList(configs.length); + for (File cfgItem : configs) { + LOG.trace("config: {}", cfgItem.toURI()); + sortedConfigFiles.add(cfgItem); + } + Collections.sort(sortedConfigFiles); + + return sortedConfigFiles; + } + +} diff --git a/opendaylight/config/logback-config-loader/src/main/java/org/opendaylight/controller/logback/config/loader/impl/LogbackConfigurationLoader.java b/opendaylight/config/logback-config-loader/src/main/java/org/opendaylight/controller/logback/config/loader/impl/LogbackConfigurationLoader.java new file mode 100644 index 0000000000..2aa6b1a348 --- /dev/null +++ b/opendaylight/config/logback-config-loader/src/main/java/org/opendaylight/controller/logback/config/loader/impl/LogbackConfigurationLoader.java @@ -0,0 +1,109 @@ +/** + * Copyright (c) 201 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.logback.config.loader.impl; + +import java.io.File; +import java.net.URL; + +import org.slf4j.ILoggerFactory; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import ch.qos.logback.classic.LoggerContext; +import ch.qos.logback.classic.joran.JoranConfigurator; +import ch.qos.logback.core.joran.spi.JoranException; +import ch.qos.logback.core.util.StatusPrinter; + +/** + * Logback configuration loader. + * Strategy: + *
    + *
  1. reset actual configuration (probably default configuration)
  2. + *
  3. load all given logback config xml files in given order
  4. + *
+ */ +public final class LogbackConfigurationLoader { + + private static final Logger LOG = LoggerFactory + .getLogger(LogbackConfigurationLoader.class); + + /** + * forbidden ctor + */ + private LogbackConfigurationLoader() { + throw new UnsupportedOperationException(); + } + + /** + * load given logback configurations in given order, reset existing configuration before applying first one + * @param purgeBefore require reset before loading first config + * @param args + */ + public static void load(boolean purgeBefore, Object...args) { + try { + if (purgeBefore) { + resetExistingConfiguration(); + } + for (Object logbackConfig : args) { + load(logbackConfig); + } + } catch (IllegalStateException e) { + LOG.warn("loading of multiple logback configurations failed", e); + } + } + + /** + * purge existing logback configuration + */ + public static void resetExistingConfiguration() { + LOG.trace("resetting existing logback configuration"); + LoggerContext context = getLoggerContext(); + JoranConfigurator configurator = new JoranConfigurator(); + configurator.setContext(context); + context.reset(); + } + + /** + * @return logback context + */ + private static LoggerContext getLoggerContext() { + ILoggerFactory context = LoggerFactory.getILoggerFactory(); + if (context != null && context instanceof LoggerContext) { + // now SLF4J is bound to logback in the current environment + return (LoggerContext) context; + } + throw new IllegalStateException("current logger factory is not supported: " + context); + } + + /** + * @param logbackConfig + * @param reset true if previous configuration needs to get purged + */ + public static void load(Object logbackConfig) { + LOG.trace("BEFORE logback reconfig"); + try { + LoggerContext context = getLoggerContext(); + JoranConfigurator configurator = new JoranConfigurator(); + configurator.setContext(context); + if (logbackConfig instanceof String) { + configurator.doConfigure((String) logbackConfig); + } else if (logbackConfig instanceof URL) { + configurator.doConfigure((URL) logbackConfig); + } else if (logbackConfig instanceof File) { + configurator.doConfigure((File) logbackConfig); + } + + LOG.trace("applied {}", logbackConfig); + StatusPrinter.printInCaseOfErrorsOrWarnings(context); + } catch (IllegalStateException | JoranException je) { + LOG.warn("Logback configuration loading failed: {}", logbackConfig); + } + LOG.trace("AFTER logback reconfig"); + } + +} diff --git a/opendaylight/config/logback-config-loader/src/test/java/org/opendaylight/controller/logback/config/loader/test/LogbackConfigurationLoaderTest.java b/opendaylight/config/logback-config-loader/src/test/java/org/opendaylight/controller/logback/config/loader/test/LogbackConfigurationLoaderTest.java new file mode 100644 index 0000000000..2e9bf1df00 --- /dev/null +++ b/opendaylight/config/logback-config-loader/src/test/java/org/opendaylight/controller/logback/config/loader/test/LogbackConfigurationLoaderTest.java @@ -0,0 +1,87 @@ +/** + * 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.logback.config.loader.test; + +import java.io.File; +import java.util.ArrayList; +import java.util.List; + +import org.junit.Assert; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.junit.runners.JUnit4; +import org.opendaylight.controller.logback.config.loader.impl.LogbackConfigUtil; +import org.opendaylight.controller.logback.config.loader.impl.LogbackConfigurationLoader; +import org.opendaylight.controller.logback.config.loader.test.logwork.Debugger; +import org.opendaylight.controller.logback.config.loader.test.logwork.Errorer; +import org.opendaylight.controller.logback.config.loader.test.logwork.Informer; +import org.opendaylight.controller.logback.config.loader.test.logwork.Tracer; +import org.opendaylight.controller.logback.config.loader.test.logwork.Warner; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +/** + * test of logging config loader - {@link LogbackConfigurationLoader} + */ +@RunWith(JUnit4.class) +public class LogbackConfigurationLoaderTest { + + /** logback config root */ + private static final String LOGBACK_D = "/logback.d"; + private static Logger LOG = LoggerFactory + .getLogger(LogbackConfigurationLoaderTest.class); + + /** + * Test of method {@link LogbackConfigurationLoader#load(boolean, Object[])} + * + * @throws Exception + */ + @Test + public void testLoad() throws Exception { + File logConfigRoot = new File(LogbackConfigurationLoaderTest.class + .getResource(LOGBACK_D).getFile()); + List sortedConfigFiles = LogbackConfigUtil.harvestSortedConfigFiles(logConfigRoot); + LogbackConfigurationLoader.load(true, sortedConfigFiles.toArray()); + + LOG.info("LOGBACK ready -> about to use it"); + + Tracer.doSomeAction(); + Debugger.doSomeAction(); + Informer.doSomeAction(); + Warner.doSomeAction(); + Errorer.doSomeAction(); + + // check logs + String[] expectedLogs = new String[] { + "LoggingEvent -> [INFO] org.opendaylight.controller.logback.config.loader.test.LogbackConfigurationLoaderTest: LOGBACK ready -> about to use it", + "LoggingEvent -> [TRACE] org.opendaylight.controller.logback.config.loader.test.logwork.Tracer: tracing", + "LoggingEvent -> [DEBUG] org.opendaylight.controller.logback.config.loader.test.logwork.Tracer: debugging", + "LoggingEvent -> [INFO] org.opendaylight.controller.logback.config.loader.test.logwork.Tracer: infoing", + "LoggingEvent -> [WARN] org.opendaylight.controller.logback.config.loader.test.logwork.Tracer: warning", + "LoggingEvent -> [ERROR] org.opendaylight.controller.logback.config.loader.test.logwork.Tracer: erroring", + "LoggingEvent -> [DEBUG] org.opendaylight.controller.logback.config.loader.test.logwork.Debugger: debugging", + "LoggingEvent -> [INFO] org.opendaylight.controller.logback.config.loader.test.logwork.Debugger: infoing", + "LoggingEvent -> [WARN] org.opendaylight.controller.logback.config.loader.test.logwork.Debugger: warning", + "LoggingEvent -> [ERROR] org.opendaylight.controller.logback.config.loader.test.logwork.Debugger: erroring", + "LoggingEvent -> [INFO] org.opendaylight.controller.logback.config.loader.test.logwork.Informer: infoing", + "LoggingEvent -> [WARN] org.opendaylight.controller.logback.config.loader.test.logwork.Informer: warning", + "LoggingEvent -> [ERROR] org.opendaylight.controller.logback.config.loader.test.logwork.Informer: erroring", + "LoggingEvent -> [WARN] org.opendaylight.controller.logback.config.loader.test.logwork.Warner: warning", + "LoggingEvent -> [ERROR] org.opendaylight.controller.logback.config.loader.test.logwork.Warner: erroring", + "LoggingEvent -> [ERROR] org.opendaylight.controller.logback.config.loader.test.logwork.Errorer: erroring" + + }; + + List logSnapshot = new ArrayList<>(TestAppender.getLogRecord()); + for (String logLine : logSnapshot) { + LOG.info("\"{}\",", logLine); + } + + Assert.assertArrayEquals(expectedLogs, logSnapshot.toArray()); + } +} diff --git a/opendaylight/config/logback-config-loader/src/test/java/org/opendaylight/controller/logback/config/loader/test/TestAppender.java b/opendaylight/config/logback-config-loader/src/test/java/org/opendaylight/controller/logback/config/loader/test/TestAppender.java new file mode 100644 index 0000000000..b273d2777c --- /dev/null +++ b/opendaylight/config/logback-config-loader/src/test/java/org/opendaylight/controller/logback/config/loader/test/TestAppender.java @@ -0,0 +1,145 @@ +/** + * 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.logback.config.loader.test; + +import java.util.ArrayList; +import java.util.List; + +import ch.qos.logback.classic.spi.LoggingEvent; +import ch.qos.logback.core.Appender; +import ch.qos.logback.core.Context; +import ch.qos.logback.core.LogbackException; +import ch.qos.logback.core.filter.Filter; +import ch.qos.logback.core.spi.FilterReply; +import ch.qos.logback.core.status.Status; + +/** + * dummy appender for collecting log messages + * + * @param + */ +public class TestAppender implements Appender { + + private boolean started; + private Context context; + private String name; + + private static List logRecord = new ArrayList<>(); + + @Override + public void start() { + started = true; + } + + @Override + public void stop() { + started = false; + } + + @Override + public boolean isStarted() { + return started; + } + + @Override + public void setContext(Context context) { + this.context = context; + } + + @Override + public Context getContext() { + return context; + } + + @Override + public void addStatus(Status status) { + // TODO Auto-generated method stub + } + + @Override + public void addInfo(String msg) { + // TODO Auto-generated method stub + } + + @Override + public void addInfo(String msg, Throwable ex) { + // TODO Auto-generated method stub + } + + @Override + public void addWarn(String msg) { + // TODO Auto-generated method stub + } + + @Override + public void addWarn(String msg, Throwable ex) { + // TODO Auto-generated method stub + } + + @Override + public void addError(String msg) { + // TODO Auto-generated method stub + } + + @Override + public void addError(String msg, Throwable ex) { + // TODO Auto-generated method stub + } + + @Override + public void addFilter(Filter newFilter) { + // TODO Auto-generated method stub + } + + @Override + public void clearAllFilters() { + // TODO Auto-generated method stub + } + + @Override + public List> getCopyOfAttachedFiltersList() { + // TODO Auto-generated method stub + return null; + } + + @Override + public FilterReply getFilterChainDecision(E event) { + // TODO Auto-generated method stub + return null; + } + + @Override + public String getName() { + return name; + } + + @Override + public void doAppend(E event) throws LogbackException { + if (event instanceof LoggingEvent) { + LoggingEvent lEvent = (LoggingEvent) event; + logRecord.add(String.format("%s -> [%s] %s: %s", event.getClass() + .getSimpleName(), lEvent.getLevel(), + lEvent.getLoggerName(), lEvent.getMessage())); + } else { + logRecord.add(event.getClass() + " -> " + event.toString()); + } + } + + @Override + public void setName(String name) { + this.name = name; + } + + /** + * @return the logRecord + */ + public static List getLogRecord() { + return logRecord; + } + +} diff --git a/opendaylight/config/logback-config-loader/src/test/java/org/opendaylight/controller/logback/config/loader/test/logwork/Debugger.java b/opendaylight/config/logback-config-loader/src/test/java/org/opendaylight/controller/logback/config/loader/test/logwork/Debugger.java new file mode 100644 index 0000000000..a8052f71c9 --- /dev/null +++ b/opendaylight/config/logback-config-loader/src/test/java/org/opendaylight/controller/logback/config/loader/test/logwork/Debugger.java @@ -0,0 +1,31 @@ +/** + * 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.logback.config.loader.test.logwork; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +/** + * dummy logging guy + */ +public class Debugger { + + private static Logger LOG = LoggerFactory.getLogger(Debugger.class); + + /** + * all logging + */ + public static void doSomeAction() { + LOG.trace("tracing"); + LOG.debug("debugging"); + LOG.info("infoing"); + LOG.warn("warning"); + LOG.error("erroring"); + } + +} diff --git a/opendaylight/config/logback-config-loader/src/test/java/org/opendaylight/controller/logback/config/loader/test/logwork/Errorer.java b/opendaylight/config/logback-config-loader/src/test/java/org/opendaylight/controller/logback/config/loader/test/logwork/Errorer.java new file mode 100644 index 0000000000..0bcd830ad1 --- /dev/null +++ b/opendaylight/config/logback-config-loader/src/test/java/org/opendaylight/controller/logback/config/loader/test/logwork/Errorer.java @@ -0,0 +1,31 @@ +/** + * 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.logback.config.loader.test.logwork; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +/** + * dummy logging guy + */ +public class Errorer { + + private static Logger LOG = LoggerFactory.getLogger(Errorer.class); + + /** + * all logging + */ + public static void doSomeAction() { + LOG.trace("tracing"); + LOG.debug("debugging"); + LOG.info("infoing"); + LOG.warn("warning"); + LOG.error("erroring"); + } + +} diff --git a/opendaylight/config/logback-config-loader/src/test/java/org/opendaylight/controller/logback/config/loader/test/logwork/Informer.java b/opendaylight/config/logback-config-loader/src/test/java/org/opendaylight/controller/logback/config/loader/test/logwork/Informer.java new file mode 100644 index 0000000000..44f09315cf --- /dev/null +++ b/opendaylight/config/logback-config-loader/src/test/java/org/opendaylight/controller/logback/config/loader/test/logwork/Informer.java @@ -0,0 +1,31 @@ +/** + * 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.logback.config.loader.test.logwork; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +/** + * dummy logging guy + */ +public class Informer { + + private static Logger LOG = LoggerFactory.getLogger(Informer.class); + + /** + * all logging + */ + public static void doSomeAction() { + LOG.trace("tracing"); + LOG.debug("debugging"); + LOG.info("infoing"); + LOG.warn("warning"); + LOG.error("erroring"); + } + +} diff --git a/opendaylight/config/logback-config-loader/src/test/java/org/opendaylight/controller/logback/config/loader/test/logwork/Tracer.java b/opendaylight/config/logback-config-loader/src/test/java/org/opendaylight/controller/logback/config/loader/test/logwork/Tracer.java new file mode 100644 index 0000000000..70df607d8d --- /dev/null +++ b/opendaylight/config/logback-config-loader/src/test/java/org/opendaylight/controller/logback/config/loader/test/logwork/Tracer.java @@ -0,0 +1,31 @@ +/** + * 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.logback.config.loader.test.logwork; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +/** + * dummy logging guy + */ +public class Tracer { + + private static Logger LOG = LoggerFactory.getLogger(Tracer.class); + + /** + * all logging + */ + public static void doSomeAction() { + LOG.trace("tracing"); + LOG.debug("debugging"); + LOG.info("infoing"); + LOG.warn("warning"); + LOG.error("erroring"); + } + +} diff --git a/opendaylight/config/logback-config-loader/src/test/java/org/opendaylight/controller/logback/config/loader/test/logwork/Warner.java b/opendaylight/config/logback-config-loader/src/test/java/org/opendaylight/controller/logback/config/loader/test/logwork/Warner.java new file mode 100644 index 0000000000..8093180a8b --- /dev/null +++ b/opendaylight/config/logback-config-loader/src/test/java/org/opendaylight/controller/logback/config/loader/test/logwork/Warner.java @@ -0,0 +1,31 @@ +/** + * 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.logback.config.loader.test.logwork; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +/** + * dummy logging guy + */ +public class Warner { + + private static Logger LOG = LoggerFactory.getLogger(Warner.class); + + /** + * all logging + */ + public static void doSomeAction() { + LOG.trace("tracing"); + LOG.debug("debugging"); + LOG.info("infoing"); + LOG.warn("warning"); + LOG.error("erroring"); + } + +} diff --git a/opendaylight/config/logback-config-loader/src/test/resources/logback-test.xml b/opendaylight/config/logback-config-loader/src/test/resources/logback-test.xml new file mode 100755 index 0000000000..7fb760aca7 --- /dev/null +++ b/opendaylight/config/logback-config-loader/src/test/resources/logback-test.xml @@ -0,0 +1,17 @@ + + + + + + %date{"yyyy-MM-dd HH:mm:ss.SSS z"} [%thread] %-5level %logger{36} - %msg%n + + + + + + + + + + + diff --git a/opendaylight/config/logback-config-loader/src/test/resources/logback.d/logback-alt.xml b/opendaylight/config/logback-config-loader/src/test/resources/logback.d/logback-alt.xml new file mode 100755 index 0000000000..ca489d5c78 --- /dev/null +++ b/opendaylight/config/logback-config-loader/src/test/resources/logback.d/logback-alt.xml @@ -0,0 +1,19 @@ + + + + + + + %date{"yyyy-MM-dd HH:mm:ss.SSS z"} [%thread] %-5level %logger{36} - %msg%n + + + + + + + + + + + + diff --git a/opendaylight/config/logback-config-loader/src/test/resources/logback.d/logback-alt2.xml b/opendaylight/config/logback-config-loader/src/test/resources/logback.d/logback-alt2.xml new file mode 100755 index 0000000000..89f82c5046 --- /dev/null +++ b/opendaylight/config/logback-config-loader/src/test/resources/logback.d/logback-alt2.xml @@ -0,0 +1,12 @@ + + + + + + + + + + + + diff --git a/opendaylight/config/logback-config-loader/src/test/resources/logback.d/logback-alt3.xml b/opendaylight/config/logback-config-loader/src/test/resources/logback.d/logback-alt3.xml new file mode 100755 index 0000000000..a37b6f7f21 --- /dev/null +++ b/opendaylight/config/logback-config-loader/src/test/resources/logback.d/logback-alt3.xml @@ -0,0 +1,11 @@ + + + + + + + + + + + diff --git a/opendaylight/config/logback-config/src/test/java/org/opendaylight/controller/config/yang/logback/config/LogbackModuleTest.java b/opendaylight/config/logback-config/src/test/java/org/opendaylight/controller/config/yang/logback/config/LogbackModuleTest.java index d9c9dada62..75323d256e 100644 --- a/opendaylight/config/logback-config/src/test/java/org/opendaylight/controller/config/yang/logback/config/LogbackModuleTest.java +++ b/opendaylight/config/logback-config/src/test/java/org/opendaylight/controller/config/yang/logback/config/LogbackModuleTest.java @@ -7,6 +7,14 @@ */ package org.opendaylight.controller.config.yang.logback.config; +import static org.junit.Assert.assertThat; +import static org.junit.Assert.fail; +import static org.junit.matchers.JUnitMatchers.containsString; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; +import javax.management.ObjectName; import org.junit.Before; import org.junit.Ignore; import org.junit.Test; @@ -16,15 +24,6 @@ import org.opendaylight.controller.config.manager.impl.AbstractConfigTest; import org.opendaylight.controller.config.manager.impl.factoriesresolver.HardcodedModuleFactoriesResolver; import org.opendaylight.controller.config.util.ConfigTransactionJMXClient; -import javax.management.ObjectName; -import java.util.ArrayList; -import java.util.Arrays; -import java.util.List; - -import static org.junit.Assert.assertThat; -import static org.junit.Assert.fail; -import static org.junit.matchers.JUnitMatchers.containsString; - public class LogbackModuleTest extends AbstractConfigTest { private static final String INSTANCE_NAME = "singleton"; @@ -89,7 +88,7 @@ public class LogbackModuleTest extends AbstractConfigTest { assertBeanCount(1, factory.getImplementationName()); ConfigTransactionJMXClient transaction = configRegistryClient.createTransaction(); - transaction.destroyConfigBean(factory.getImplementationName(), INSTANCE_NAME); + transaction.destroyModule(factory.getImplementationName(), INSTANCE_NAME); CommitStatus status = transaction.commit(); assertBeanCount(0, factory.getImplementationName()); diff --git a/opendaylight/config/threadpool-config-impl/src/test/java/org/opendaylight/controller/config/threadpool/fixed/FixedThreadPoolConfigBeanTest.java b/opendaylight/config/threadpool-config-impl/src/test/java/org/opendaylight/controller/config/threadpool/fixed/FixedThreadPoolConfigBeanTest.java index c95661d9c9..62b295be8d 100644 --- a/opendaylight/config/threadpool-config-impl/src/test/java/org/opendaylight/controller/config/threadpool/fixed/FixedThreadPoolConfigBeanTest.java +++ b/opendaylight/config/threadpool-config-impl/src/test/java/org/opendaylight/controller/config/threadpool/fixed/FixedThreadPoolConfigBeanTest.java @@ -7,6 +7,19 @@ */ package org.opendaylight.controller.config.threadpool.fixed; +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertThat; +import static org.junit.Assert.fail; +import static org.junit.matchers.JUnitMatchers.containsString; + +import java.lang.management.ManagementFactory; +import java.lang.management.ThreadInfo; +import java.lang.management.ThreadMXBean; +import java.util.ArrayList; +import java.util.List; +import javax.management.InstanceAlreadyExistsException; +import javax.management.InstanceNotFoundException; +import javax.management.ObjectName; import org.junit.Before; import org.junit.Test; import org.opendaylight.controller.config.api.ConflictingVersionException; @@ -19,16 +32,11 @@ import org.opendaylight.controller.config.yang.threadpool.impl.NamingThreadFacto import org.opendaylight.controller.config.yang.threadpool.impl.NamingThreadFactoryModuleMXBean; import org.opendaylight.controller.config.yang.threadpool.impl.fixed.FixedThreadPoolModuleFactory; import org.opendaylight.controller.config.yang.threadpool.impl.fixed.FixedThreadPoolModuleMXBean; - -import javax.management.InstanceAlreadyExistsException; -import javax.management.InstanceNotFoundException; -import javax.management.ObjectName; - -import static org.junit.Assert.assertThat; -import static org.junit.Assert.fail; -import static org.junit.matchers.JUnitMatchers.containsString; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; public class FixedThreadPoolConfigBeanTest extends AbstractConfigTest { + private static final Logger logger = LoggerFactory.getLogger(FixedThreadPoolConfigBeanTest.class); private FixedThreadPoolModuleFactory factory; private final String nameInstance = "fixedInstance"; @@ -36,7 +44,7 @@ public class FixedThreadPoolConfigBeanTest extends AbstractConfigTest { @Before public void setUp() { factory = new FixedThreadPoolModuleFactory(); - super.initConfigTransactionManagerImpl(new HardcodedModuleFactoriesResolver(mockedContext,factory, + super.initConfigTransactionManagerImpl(new HardcodedModuleFactoriesResolver(mockedContext, factory, new NamingThreadFactoryModuleFactory())); } @@ -44,7 +52,7 @@ public class FixedThreadPoolConfigBeanTest extends AbstractConfigTest { public void testCreateBean() throws InstanceAlreadyExistsException, ValidationException, ConflictingVersionException { ConfigTransactionJMXClient transaction = configRegistryClient.createTransaction(); - createFixed(transaction, nameInstance, 2); + createFixed(transaction, nameInstance, 2, nameInstance); transaction.validateConfig(); CommitStatus status = transaction.commit(); @@ -57,7 +65,7 @@ public class FixedThreadPoolConfigBeanTest extends AbstractConfigTest { public void testReusingOldInstance() throws InstanceAlreadyExistsException, ConflictingVersionException, ValidationException { ConfigTransactionJMXClient transaction = configRegistryClient.createTransaction(); - createFixed(transaction, nameInstance, 4); + createFixed(transaction, nameInstance, 4, nameInstance); transaction.validateConfig(); transaction.commit(); @@ -75,12 +83,12 @@ public class FixedThreadPoolConfigBeanTest extends AbstractConfigTest { public void testNegative() throws ConflictingVersionException, ValidationException, InstanceAlreadyExistsException { ConfigTransactionJMXClient transaction = configRegistryClient.createTransaction(); - createFixed(transaction, nameInstance, 5); + createFixed(transaction, nameInstance, 5, nameInstance); transaction.commit(); transaction = configRegistryClient.createTransaction(); try { - createFixed(transaction, nameInstance, 0); + createFixed(transaction, nameInstance, 0, nameInstance); fail(); } catch (InstanceAlreadyExistsException e) { assertThat( @@ -89,26 +97,56 @@ public class FixedThreadPoolConfigBeanTest extends AbstractConfigTest { } } + private int countThreadsByPrefix(String prefix) { + ThreadMXBean threadMXBean = ManagementFactory.getThreadMXBean(); + int result = 0; + List names = new ArrayList<>(); + for (ThreadInfo threadInfo : threadMXBean.dumpAllThreads(false, false)) { + names.add(threadInfo.getThreadName()); + if (threadInfo.getThreadName().startsWith(prefix)) { + result++; + } + } + logger.info("Current threads {}", names); + return result; + } + @Test public void testDestroy() throws InstanceAlreadyExistsException, ValidationException, ConflictingVersionException, - InstanceNotFoundException { + InstanceNotFoundException, InterruptedException { + + String prefix = org.apache.commons.lang3.RandomStringUtils.randomAlphabetic(10); + + int numberOfThreads = 100; + int threadCount1 = countThreadsByPrefix(prefix); + assertEquals(0, threadCount1); ConfigTransactionJMXClient transaction = configRegistryClient.createTransaction(); - createFixed(transaction, nameInstance, 1); + createFixed(transaction, nameInstance, numberOfThreads, prefix); transaction.commit(); + int threadCount2 = countThreadsByPrefix(prefix); + assertEquals(numberOfThreads, threadCount2); transaction = configRegistryClient.createTransaction(); - transaction.destroyConfigBean(factory.getImplementationName(), nameInstance); + transaction.destroyModule(factory.getImplementationName(), nameInstance); CommitStatus status = transaction.commit(); assertBeanCount(0, factory.getImplementationName()); assertStatus(status, 0, 0, 1); + + for (int i = 0; i < 60; i++) { + if (countThreadsByPrefix(prefix) == 0) { + return; + } + Thread.sleep(1000); + } + assertEquals(0, countThreadsByPrefix(prefix)); } @Test public void testValidationException() throws InstanceAlreadyExistsException { ConfigTransactionJMXClient transaction = configRegistryClient.createTransaction(); - createFixed(transaction, nameInstance, -1); + createFixed(transaction, nameInstance, -1, nameInstance); try { transaction.validateConfig(); fail(); @@ -117,7 +155,7 @@ public class FixedThreadPoolConfigBeanTest extends AbstractConfigTest { } } - private ObjectName createFixed(ConfigTransactionJMXClient transaction, String name, int numberOfThreads) + private ObjectName createFixed(ConfigTransactionJMXClient transaction, String name, int numberOfThreads, String prefix) throws InstanceAlreadyExistsException { ObjectName nameCreated = transaction.createModule(factory.getImplementationName(), name); FixedThreadPoolModuleMXBean mxBean = transaction.newMXBeanProxy(nameCreated, FixedThreadPoolModuleMXBean.class); @@ -126,7 +164,7 @@ public class FixedThreadPoolConfigBeanTest extends AbstractConfigTest { ObjectName threadFactoryON = transaction.createModule(NamingThreadFactoryModuleFactory.NAME, "naming"); NamingThreadFactoryModuleMXBean namingThreadFactoryModuleMXBean = transaction.newMXBeanProxy(threadFactoryON, NamingThreadFactoryModuleMXBean.class); - namingThreadFactoryModuleMXBean.setNamePrefix("prefix"); + namingThreadFactoryModuleMXBean.setNamePrefix(prefix); mxBean.setThreadFactory(threadFactoryON); diff --git a/opendaylight/config/threadpool-config-impl/src/test/java/org/opendaylight/controller/config/threadpool/scheduled/ScheduledThreadPoolConfigBeanTest.java b/opendaylight/config/threadpool-config-impl/src/test/java/org/opendaylight/controller/config/threadpool/scheduled/ScheduledThreadPoolConfigBeanTest.java index ef06e43d2f..0fc2fd6eb3 100644 --- a/opendaylight/config/threadpool-config-impl/src/test/java/org/opendaylight/controller/config/threadpool/scheduled/ScheduledThreadPoolConfigBeanTest.java +++ b/opendaylight/config/threadpool-config-impl/src/test/java/org/opendaylight/controller/config/threadpool/scheduled/ScheduledThreadPoolConfigBeanTest.java @@ -7,6 +7,15 @@ */ package org.opendaylight.controller.config.threadpool.scheduled; +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertThat; +import static org.junit.Assert.assertTrue; +import static org.junit.Assert.fail; +import static org.junit.matchers.JUnitMatchers.containsString; + +import javax.management.InstanceAlreadyExistsException; +import javax.management.InstanceNotFoundException; +import javax.management.ObjectName; import org.junit.Before; import org.junit.Test; import org.opendaylight.controller.config.api.ConflictingVersionException; @@ -20,16 +29,6 @@ import org.opendaylight.controller.config.yang.threadpool.impl.NamingThreadFacto import org.opendaylight.controller.config.yang.threadpool.impl.scheduled.ScheduledThreadPoolModuleFactory; import org.opendaylight.controller.config.yang.threadpool.impl.scheduled.ScheduledThreadPoolModuleMXBean; -import javax.management.InstanceAlreadyExistsException; -import javax.management.InstanceNotFoundException; -import javax.management.ObjectName; - -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertThat; -import static org.junit.Assert.assertTrue; -import static org.junit.Assert.fail; -import static org.junit.matchers.JUnitMatchers.containsString; - public class ScheduledThreadPoolConfigBeanTest extends AbstractConfigTest { private ScheduledThreadPoolModuleFactory factory; @@ -103,7 +102,7 @@ public class ScheduledThreadPoolConfigBeanTest extends AbstractConfigTest { transaction.commit(); transaction = configRegistryClient.createTransaction(); - transaction.destroyConfigBean(factory.getImplementationName(), instanceName); + transaction.destroyModule(factory.getImplementationName(), instanceName); CommitStatus status = transaction.commit(); assertBeanCount(0, factory.getImplementationName()); diff --git a/opendaylight/distribution/opendaylight-karaf/src/main/resources/etc/jre.properties b/opendaylight/distribution/opendaylight-karaf/src/main/resources/etc/jre.properties new file mode 100644 index 0000000000..e91da89970 --- /dev/null +++ b/opendaylight/distribution/opendaylight-karaf/src/main/resources/etc/jre.properties @@ -0,0 +1,503 @@ +################################################################################ +# +# Licensed to the Apache Software Foundation (ASF) under one or more +# contributor license agreements. See the NOTICE file distributed with +# this work for additional information regarding copyright ownership. +# The ASF licenses this file to You under the Apache License, Version 2.0 +# (the "License"); you may not use this file except in compliance with +# the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# +################################################################################ + +# +# Java platform package export properties. +# + +# Standard package set. Note that: +# - javax.transaction* is exported with a mandatory attribute +jre-1.6= \ + javax.accessibility, \ + javax.activation;version="1.1", \ + javax.activity, \ + javax.crypto, \ + javax.crypto.interfaces, \ + javax.crypto.spec, \ + javax.imageio, \ + javax.imageio.event, \ + javax.imageio.metadata, \ + javax.imageio.plugins.bmp, \ + javax.imageio.plugins.jpeg, \ + javax.imageio.spi, \ + javax.imageio.stream, \ + javax.jws, \ + javax.jws.soap, \ + javax.lang.model, \ + javax.lang.model.element, \ + javax.lang.model.type, \ + javax.lang.model.util, \ + javax.management, \ + javax.management.loading, \ + javax.management.modelmbean, \ + javax.management.monitor, \ + javax.management.openmbean, \ + javax.management.relation, \ + javax.management.remote, \ + javax.management.remote.rmi, \ + javax.management.timer, \ + javax.naming, \ + javax.naming.directory, \ + javax.naming.event, \ + javax.naming.ldap, \ + javax.naming.spi, \ + javax.net, \ + javax.net.ssl, \ + javax.print, \ + javax.print.attribute, \ + javax.print.attribute.standard, \ + javax.print.event, \ + javax.rmi, \ + javax.rmi.CORBA, \ + javax.rmi.ssl, \ + javax.script, \ + javax.security.auth, \ + javax.security.auth.callback, \ + javax.security.auth.kerberos, \ + javax.security.auth.login, \ + javax.security.auth.spi, \ + javax.security.auth.x500, \ + javax.security.cert, \ + javax.security.sasl, \ + javax.sound.midi, \ + javax.sound.midi.spi, \ + javax.sound.sampled, \ + javax.sound.sampled.spi, \ + javax.sql, \ + javax.sql.rowset, \ + javax.sql.rowset.serial, \ + javax.sql.rowset.spi, \ + javax.swing, \ + javax.swing.border, \ + javax.swing.colorchooser, \ + javax.swing.event, \ + javax.swing.filechooser, \ + javax.swing.plaf, \ + javax.swing.plaf.basic, \ + javax.swing.plaf.metal, \ + javax.swing.plaf.multi, \ + javax.swing.plaf.synth, \ + javax.swing.table, \ + javax.swing.text, \ + javax.swing.text.html, \ + javax.swing.text.html.parser, \ + javax.swing.text.rtf, \ + javax.swing.tree, \ + javax.swing.undo, \ + javax.tools, \ + javax.transaction; javax.transaction.xa; partial=true; mandatory:=partial, \ + javax.xml, \ + javax.xml.bind;version="2.2.1", \ + javax.xml.bind.annotation;version="2.2.1", \ + javax.xml.bind.annotation.adapters;version="2.2.1", \ + javax.xml.bind.attachment;version="2.2.1", \ + javax.xml.bind.helpers;version="2.2.1", \ + javax.xml.bind.util;version="2.2.1", \ + javax.xml.crypto, \ + javax.xml.crypto.dom, \ + javax.xml.crypto.dsig, \ + javax.xml.crypto.dsig.dom, \ + javax.xml.crypto.dsig.keyinfo, \ + javax.xml.crypto.dsig.spec, \ + javax.xml.datatype, \ + javax.xml.namespace, \ + javax.xml.parsers, \ + javax.xml.soap;version="1.3", \ + javax.xml.stream;version="1.2", \ + javax.xml.stream.events;version="1.2", \ + javax.xml.stream.util;version="1.2", \ + javax.xml.transform, \ + javax.xml.transform.dom, \ + javax.xml.transform.sax, \ + javax.xml.transform.stax, \ + javax.xml.transform.stream, \ + javax.xml.validation, \ + javax.xml.ws;version="2.2", \ + javax.xml.ws.handler;version="2.2", \ + javax.xml.ws.handler.soap;version="2.2", \ + javax.xml.ws.http;version="2.2", \ + javax.xml.ws.soap;version="2.2", \ + javax.xml.ws.spi;version="2.2", \ + javax.xml.ws.wsaddressing;version="2.2", \ + javax.xml.ws.spi.http;version="2.2", \ + javax.xml.xpath, \ + org.ietf.jgss, \ + org.omg.CORBA, \ + org.omg.CORBA_2_3, \ + org.omg.CORBA_2_3.portable, \ + org.omg.CORBA.DynAnyPackage, \ + org.omg.CORBA.ORBPackage, \ + org.omg.CORBA.portable, \ + org.omg.CORBA.TypeCodePackage, \ + org.omg.CosNaming, \ + org.omg.CosNaming.NamingContextExtPackage, \ + org.omg.CosNaming.NamingContextPackage, \ + org.omg.Dynamic, \ + org.omg.DynamicAny, \ + org.omg.DynamicAny.DynAnyFactoryPackage, \ + org.omg.DynamicAny.DynAnyPackage, \ + org.omg.IOP, \ + org.omg.IOP.CodecFactoryPackage, \ + org.omg.IOP.CodecPackage, \ + org.omg.Messaging, \ + org.omg.PortableInterceptor, \ + org.omg.PortableInterceptor.ORBInitInfoPackage, \ + org.omg.PortableServer, \ + org.omg.PortableServer.CurrentPackage, \ + org.omg.PortableServer.POAManagerPackage, \ + org.omg.PortableServer.POAPackage, \ + org.omg.PortableServer.portable, \ + org.omg.PortableServer.ServantLocatorPackage, \ + org.omg.SendingContext, \ + org.omg.stub.java.rmi, \ + org.omg.stub.javax.management.remote.rmi, \ + org.w3c.dom, \ + org.w3c.dom.bootstrap, \ + org.w3c.dom.css, \ + org.w3c.dom.events, \ + org.w3c.dom.html, \ + org.w3c.dom.ls, \ + org.w3c.dom.ranges, \ + org.w3c.dom.stylesheets, \ + org.w3c.dom.traversal, \ + org.w3c.dom.views, \ + org.w3c.dom.xpath, \ + org.xml.sax, \ + org.xml.sax.ext, \ + org.xml.sax.helpers + +# Standard package set. Note that: +# - javax.transaction* is exported with a mandatory attribute +jre-1.7= \ + javax.accessibility, \ + javax.activation;version="1.1", \ + javax.activity, \ + javax.crypto, \ + javax.crypto.interfaces, \ + javax.crypto.spec, \ + javax.imageio, \ + javax.imageio.event, \ + javax.imageio.metadata, \ + javax.imageio.plugins.bmp, \ + javax.imageio.plugins.jpeg, \ + javax.imageio.spi, \ + javax.imageio.stream, \ + javax.jws, \ + javax.jws.soap, \ + javax.lang.model, \ + javax.lang.model.element, \ + javax.lang.model.type, \ + javax.lang.model.util, \ + javax.management, \ + javax.management.loading, \ + javax.management.modelmbean, \ + javax.management.monitor, \ + javax.management.openmbean, \ + javax.management.relation, \ + javax.management.remote, \ + javax.management.remote.rmi, \ + javax.management.timer, \ + javax.naming, \ + javax.naming.directory, \ + javax.naming.event, \ + javax.naming.ldap, \ + javax.naming.spi, \ + javax.net, \ + javax.net.ssl, \ + javax.print, \ + javax.print.attribute, \ + javax.print.attribute.standard, \ + javax.print.event, \ + javax.rmi, \ + javax.rmi.CORBA, \ + javax.rmi.ssl, \ + javax.script, \ + javax.security.auth, \ + javax.security.auth.callback, \ + javax.security.auth.kerberos, \ + javax.security.auth.login, \ + javax.security.auth.spi, \ + javax.security.auth.x500, \ + javax.security.cert, \ + javax.security.sasl, \ + javax.sound.midi, \ + javax.sound.midi.spi, \ + javax.sound.sampled, \ + javax.sound.sampled.spi, \ + javax.sql, \ + javax.sql.rowset, \ + javax.sql.rowset.serial, \ + javax.sql.rowset.spi, \ + javax.swing, \ + javax.swing.border, \ + javax.swing.colorchooser, \ + javax.swing.event, \ + javax.swing.filechooser, \ + javax.swing.plaf, \ + javax.swing.plaf.basic, \ + javax.swing.plaf.metal, \ + javax.swing.plaf.multi, \ + javax.swing.plaf.synth, \ + javax.swing.table, \ + javax.swing.text, \ + javax.swing.text.html, \ + javax.swing.text.html.parser, \ + javax.swing.text.rtf, \ + javax.swing.tree, \ + javax.swing.undo, \ + javax.tools, \ + javax.transaction; javax.transaction.xa; partial=true; mandatory:=partial, \ + javax.xml, \ + javax.xml.bind;version="2.2.1", \ + javax.xml.bind.annotation;version="2.2.1", \ + javax.xml.bind.annotation.adapters;version="2.2.1", \ + javax.xml.bind.attachment;version="2.2.1", \ + javax.xml.bind.helpers;version="2.2.1", \ + javax.xml.bind.util;version="2.2.1", \ + javax.xml.crypto, \ + javax.xml.crypto.dom, \ + javax.xml.crypto.dsig, \ + javax.xml.crypto.dsig.dom, \ + javax.xml.crypto.dsig.keyinfo, \ + javax.xml.crypto.dsig.spec, \ + javax.xml.datatype, \ + javax.xml.namespace, \ + javax.xml.parsers, \ + javax.xml.soap;version="1.3", \ + javax.xml.stream;version="1.2", \ + javax.xml.stream.events;version="1.2", \ + javax.xml.stream.util;version="1.2", \ + javax.xml.transform, \ + javax.xml.transform.dom, \ + javax.xml.transform.sax, \ + javax.xml.transform.stax, \ + javax.xml.transform.stream, \ + javax.xml.validation, \ + javax.xml.ws;version="2.2", \ + javax.xml.ws.handler;version="2.2", \ + javax.xml.ws.handler.soap;version="2.2", \ + javax.xml.ws.http;version="2.2", \ + javax.xml.ws.soap;version="2.2", \ + javax.xml.ws.spi;version="2.2", \ + javax.xml.ws.wsaddressing;version="2.2", \ + javax.xml.ws.spi.http;version="2.2", \ + javax.xml.xpath, \ + org.ietf.jgss, \ + org.omg.CORBA, \ + org.omg.CORBA_2_3, \ + org.omg.CORBA_2_3.portable, \ + org.omg.CORBA.DynAnyPackage, \ + org.omg.CORBA.ORBPackage, \ + org.omg.CORBA.portable, \ + org.omg.CORBA.TypeCodePackage, \ + org.omg.CosNaming, \ + org.omg.CosNaming.NamingContextExtPackage, \ + org.omg.CosNaming.NamingContextPackage, \ + org.omg.Dynamic, \ + org.omg.DynamicAny, \ + org.omg.DynamicAny.DynAnyFactoryPackage, \ + org.omg.DynamicAny.DynAnyPackage, \ + org.omg.IOP, \ + org.omg.IOP.CodecFactoryPackage, \ + org.omg.IOP.CodecPackage, \ + org.omg.Messaging, \ + org.omg.PortableInterceptor, \ + org.omg.PortableInterceptor.ORBInitInfoPackage, \ + org.omg.PortableServer, \ + org.omg.PortableServer.CurrentPackage, \ + org.omg.PortableServer.POAManagerPackage, \ + org.omg.PortableServer.POAPackage, \ + org.omg.PortableServer.portable, \ + org.omg.PortableServer.ServantLocatorPackage, \ + org.omg.SendingContext, \ + org.omg.stub.java.rmi, \ + org.omg.stub.javax.management.remote.rmi, \ + org.w3c.dom, \ + org.w3c.dom.bootstrap, \ + org.w3c.dom.css, \ + org.w3c.dom.events, \ + org.w3c.dom.html, \ + org.w3c.dom.ls, \ + org.w3c.dom.ranges, \ + org.w3c.dom.stylesheets, \ + org.w3c.dom.traversal, \ + org.w3c.dom.views, \ + org.w3c.dom.xpath, \ + org.xml.sax, \ + org.xml.sax.ext, \ + org.xml.sax.helpers + +jre-1.8= \ + javax.accessibility, \ + javax.activation;version="1.1", \ + javax.activity, \ + javax.crypto, \ + javax.crypto.interfaces, \ + javax.crypto.spec, \ + javax.imageio, \ + javax.imageio.event, \ + javax.imageio.metadata, \ + javax.imageio.plugins.bmp, \ + javax.imageio.plugins.jpeg, \ + javax.imageio.spi, \ + javax.imageio.stream, \ + javax.jws, \ + javax.jws.soap, \ + javax.lang.model, \ + javax.lang.model.element, \ + javax.lang.model.type, \ + javax.lang.model.util, \ + javax.management, \ + javax.management.loading, \ + javax.management.modelmbean, \ + javax.management.monitor, \ + javax.management.openmbean, \ + javax.management.relation, \ + javax.management.remote, \ + javax.management.remote.rmi, \ + javax.management.timer, \ + javax.naming, \ + javax.naming.directory, \ + javax.naming.event, \ + javax.naming.ldap, \ + javax.naming.spi, \ + javax.net, \ + javax.net.ssl, \ + javax.print, \ + javax.print.attribute, \ + javax.print.attribute.standard, \ + javax.print.event, \ + javax.rmi, \ + javax.rmi.CORBA, \ + javax.rmi.ssl, \ + javax.script, \ + javax.security.auth, \ + javax.security.auth.callback, \ + javax.security.auth.kerberos, \ + javax.security.auth.login, \ + javax.security.auth.spi, \ + javax.security.auth.x500, \ + javax.security.cert, \ + javax.security.sasl, \ + javax.sound.midi, \ + javax.sound.midi.spi, \ + javax.sound.sampled, \ + javax.sound.sampled.spi, \ + javax.sql, \ + javax.sql.rowset, \ + javax.sql.rowset.serial, \ + javax.sql.rowset.spi, \ + javax.swing, \ + javax.swing.border, \ + javax.swing.colorchooser, \ + javax.swing.event, \ + javax.swing.filechooser, \ + javax.swing.plaf, \ + javax.swing.plaf.basic, \ + javax.swing.plaf.metal, \ + javax.swing.plaf.multi, \ + javax.swing.plaf.synth, \ + javax.swing.table, \ + javax.swing.text, \ + javax.swing.text.html, \ + javax.swing.text.html.parser, \ + javax.swing.text.rtf, \ + javax.swing.tree, \ + javax.swing.undo, \ + javax.tools, \ + javax.transaction; javax.transaction.xa; partial=true; mandatory:=partial, \ + javax.xml, \ + javax.xml.bind;version="2.2.1", \ + javax.xml.bind.annotation;version="2.2.1", \ + javax.xml.bind.annotation.adapters;version="2.2.1", \ + javax.xml.bind.attachment;version="2.2.1", \ + javax.xml.bind.helpers;version="2.2.1", \ + javax.xml.bind.util;version="2.2.1", \ + javax.xml.crypto, \ + javax.xml.crypto.dom, \ + javax.xml.crypto.dsig, \ + javax.xml.crypto.dsig.dom, \ + javax.xml.crypto.dsig.keyinfo, \ + javax.xml.crypto.dsig.spec, \ + javax.xml.datatype, \ + javax.xml.namespace, \ + javax.xml.parsers, \ + javax.xml.soap;version="1.3", \ + javax.xml.stream;version="1.2", \ + javax.xml.stream.events;version="1.2", \ + javax.xml.stream.util;version="1.2", \ + javax.xml.transform, \ + javax.xml.transform.dom, \ + javax.xml.transform.sax, \ + javax.xml.transform.stax, \ + javax.xml.transform.stream, \ + javax.xml.validation, \ + javax.xml.ws;version="2.2", \ + javax.xml.ws.handler;version="2.2", \ + javax.xml.ws.handler.soap;version="2.2", \ + javax.xml.ws.http;version="2.2", \ + javax.xml.ws.soap;version="2.2", \ + javax.xml.ws.spi;version="2.2", \ + javax.xml.ws.wsaddressing;version="2.2", \ + javax.xml.ws.spi.http;version="2.2", \ + javax.xml.xpath, \ + org.ietf.jgss, \ + org.omg.CORBA, \ + org.omg.CORBA_2_3, \ + org.omg.CORBA_2_3.portable, \ + org.omg.CORBA.DynAnyPackage, \ + org.omg.CORBA.ORBPackage, \ + org.omg.CORBA.portable, \ + org.omg.CORBA.TypeCodePackage, \ + org.omg.CosNaming, \ + org.omg.CosNaming.NamingContextExtPackage, \ + org.omg.CosNaming.NamingContextPackage, \ + org.omg.Dynamic, \ + org.omg.DynamicAny, \ + org.omg.DynamicAny.DynAnyFactoryPackage, \ + org.omg.DynamicAny.DynAnyPackage, \ + org.omg.IOP, \ + org.omg.IOP.CodecFactoryPackage, \ + org.omg.IOP.CodecPackage, \ + org.omg.Messaging, \ + org.omg.PortableInterceptor, \ + org.omg.PortableInterceptor.ORBInitInfoPackage, \ + org.omg.PortableServer, \ + org.omg.PortableServer.CurrentPackage, \ + org.omg.PortableServer.POAManagerPackage, \ + org.omg.PortableServer.POAPackage, \ + org.omg.PortableServer.portable, \ + org.omg.PortableServer.ServantLocatorPackage, \ + org.omg.SendingContext, \ + org.omg.stub.java.rmi, \ + org.omg.stub.javax.management.remote.rmi, \ + org.w3c.dom, \ + org.w3c.dom.bootstrap, \ + org.w3c.dom.css, \ + org.w3c.dom.events, \ + org.w3c.dom.html, \ + org.w3c.dom.ls, \ + org.w3c.dom.ranges, \ + org.w3c.dom.stylesheets, \ + org.w3c.dom.traversal, \ + org.w3c.dom.views, \ + org.w3c.dom.xpath, \ + org.xml.sax, \ + org.xml.sax.ext, \ + org.xml.sax.helpers diff --git a/opendaylight/distribution/opendaylight-karaf/src/main/resources/etc/startup.properties b/opendaylight/distribution/opendaylight-karaf/src/main/resources/etc/startup.properties new file mode 100644 index 0000000000..ca8c83c380 --- /dev/null +++ b/opendaylight/distribution/opendaylight-karaf/src/main/resources/etc/startup.properties @@ -0,0 +1,53 @@ +#Bundles to be started on startup, with startlevel + +# feature: framework version: 3.0.1 +mvn\:org.ops4j.base/ops4j-base-lang/1.4.0 = 5 +mvn\:biz.aQute.bnd/bndlib/2.2.0 = 5 +mvn\:org.ops4j.pax.swissbox/pax-swissbox-bnd/1.7.0 = 5 +mvn\:org.ops4j.pax.url/pax-url-maven-commons/1.6.0 = 5 +mvn\:org.ops4j.pax.url/pax-url-aether/1.6.0 = 5 +mvn\:org.ops4j.pax.url/pax-url-wrap/1.6.0 = 5 +mvn\:javax.annotation/javax.annotation-api/1.2 = 5 +mvn\:org.ops4j.pax.logging/pax-logging-api/1.7.2 = 8 +mvn\:org.ops4j.pax.logging/pax-logging-service/1.7.2 = 8 +mvn\:org.apache.karaf.service/org.apache.karaf.service.guard/3.0.1 = 10 +mvn\:org.apache.felix/org.apache.felix.configadmin/1.6.0 = 10 +mvn\:org.apache.felix/org.apache.felix.fileinstall/3.2.8 = 11 +mvn\:org.ow2.asm/asm-all/4.1 = 12 +mvn\:org.apache.aries/org.apache.aries.util/1.1.0 = 20 +mvn\:org.apache.aries.proxy/org.apache.aries.proxy.api/1.0.0 = 20 +mvn\:org.apache.aries.proxy/org.apache.aries.proxy.impl/1.0.2 = 20 +mvn\:org.apache.aries.blueprint/org.apache.aries.blueprint.api/1.0.0 = 20 +mvn\:org.apache.aries.blueprint/org.apache.aries.blueprint.cm/1.0.3 = 20 +mvn\:org.apache.aries.blueprint/org.apache.aries.blueprint.core.compatibility/1.0.0 = 20 +mvn\:org.apache.aries.blueprint/org.apache.aries.blueprint.core/1.4.0 = 20 +mvn\:org.apache.karaf.deployer/org.apache.karaf.deployer.spring/3.0.1 = 24 +mvn\:org.apache.karaf.deployer/org.apache.karaf.deployer.blueprint/3.0.1 = 24 +mvn\:org.apache.karaf.deployer/org.apache.karaf.deployer.wrap/3.0.1 = 24 +mvn\:org.apache.karaf.region/org.apache.karaf.region.core/3.0.1 = 25 +mvn\:org.apache.karaf.features/org.apache.karaf.features.core/3.0.1 = 25 +mvn\:org.apache.karaf.deployer/org.apache.karaf.deployer.features/3.0.1 = 26 +mvn\:jline/jline/2.11 = 30 +mvn\:org.jledit/core/0.2.1 = 30 +mvn\:org.fusesource.jansi/jansi/1.11 = 30 +mvn\:org.ops4j.base/ops4j-base-util-property/1.4.0 = 30 +mvn\:org.ops4j.base/ops4j-base-util-xml/1.4.0 = 30 +mvn\:org.ops4j.base/ops4j-base-util-collections/1.4.0 = 30 +mvn\:org.ops4j.pax.url/pax-url-commons/1.6.0 = 30 +mvn\:org.ops4j.pax.swissbox/pax-swissbox-property/1.7.0 = 30 +mvn\:org.ops4j.base/ops4j-base-net/1.4.0 = 30 +mvn\:org.ops4j.base/ops4j-base-monitors/1.4.0 = 30 +mvn\:org.apache.karaf.features/org.apache.karaf.features.command/3.0.1 = 30 +mvn\:org.apache.karaf.shell/org.apache.karaf.shell.console/3.0.1 = 30 +mvn\:org.apache.karaf.jaas/org.apache.karaf.jaas.modules/3.0.1 = 30 +mvn\:org.apache.karaf.jaas/org.apache.karaf.jaas.config/3.0.1 = 30 +mvn\:org.apache.karaf.jaas/org.apache.karaf.jaas.boot/3.0.1 = 30 +mvn\:org.apache.sshd/sshd-core/0.9.0 = 30 +mvn\:org.apache.karaf.bundle/org.apache.karaf.bundle.command/3.0.1 = 30 +mvn\:org.apache.karaf.shell/org.apache.karaf.shell.table/3.0.1 = 30 +mvn\:org.apache.karaf.bundle/org.apache.karaf.bundle.core/3.0.1 = 30 +mvn\:org.apache.karaf.shell/org.apache.karaf.shell.help/3.0.1 = 30 +mvn\:org.apache.karaf.system/org.apache.karaf.system.core/3.0.1 = 30 +mvn\:org.apache.karaf.system/org.apache.karaf.system.command/3.0.1 = 30 +mvn\:org.apache.karaf.shell/org.apache.karaf.shell.commands/3.0.1 = 30 +mvn\:org.apache.aries.quiesce/org.apache.aries.quiesce.api/1.0.0 = 30 diff --git a/opendaylight/md-sal/model/model-flow-base/src/main/yang/opendaylight-match-types.yang b/opendaylight/md-sal/model/model-flow-base/src/main/yang/opendaylight-match-types.yang index b02b0dc25c..efe1ce3e3a 100644 --- a/opendaylight/md-sal/model/model-flow-base/src/main/yang/opendaylight-match-types.yang +++ b/opendaylight/md-sal/model/model-flow-base/src/main/yang/opendaylight-match-types.yang @@ -269,6 +269,12 @@ module opendaylight-match-types { } } + grouping "tcp-flag-match-fields" { + leaf tcp-flag { + type uint16; + } + } + grouping match { leaf in-port { type inv:node-connector-id; @@ -340,5 +346,9 @@ module opendaylight-match-types { container "protocol-match-fields" { uses "protocol-match-fields"; } + + container tcp-flag-match { + uses "tcp-flag-match-fields"; + } } } \ No newline at end of file diff --git a/opendaylight/md-sal/model/model-flow-base/src/main/yang/opendaylight-table-types.yang b/opendaylight/md-sal/model/model-flow-base/src/main/yang/opendaylight-table-types.yang index e74b548342..c271f8f4d0 100644 --- a/opendaylight/md-sal/model/model-flow-base/src/main/yang/opendaylight-table-types.yang +++ b/opendaylight/md-sal/model/model-flow-base/src/main/yang/opendaylight-table-types.yang @@ -188,6 +188,10 @@ module opendaylight-table-types { base match-field; description "Match for IPv6 Extension Header pseudo-field"; } + identity tcp_flag { + base match-field; + description "TCP Flag Match"; + } grouping set-field-match { list set-field-match { diff --git a/opendaylight/md-sal/sal-binding-broker/src/main/java/org/opendaylight/controller/sal/binding/codegen/impl/SingletonHolder.java b/opendaylight/md-sal/sal-binding-broker/src/main/java/org/opendaylight/controller/sal/binding/codegen/impl/SingletonHolder.java index 8276446766..1ec4aa2d30 100644 --- a/opendaylight/md-sal/sal-binding-broker/src/main/java/org/opendaylight/controller/sal/binding/codegen/impl/SingletonHolder.java +++ b/opendaylight/md-sal/sal-binding-broker/src/main/java/org/opendaylight/controller/sal/binding/codegen/impl/SingletonHolder.java @@ -11,6 +11,7 @@ import java.util.concurrent.BlockingQueue; import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; import java.util.concurrent.LinkedBlockingQueue; +import java.util.concurrent.RejectedExecutionException; import java.util.concurrent.RejectedExecutionHandler; import java.util.concurrent.ThreadFactory; import java.util.concurrent.ThreadPoolExecutor; @@ -24,6 +25,7 @@ import org.opendaylight.controller.sal.binding.spi.NotificationInvokerFactory; import org.slf4j.Logger; import org.slf4j.LoggerFactory; +import com.google.common.util.concurrent.ForwardingBlockingQueue; import com.google.common.util.concurrent.ListeningExecutorService; import com.google.common.util.concurrent.MoreExecutors; import com.google.common.util.concurrent.ThreadFactoryBuilder; @@ -62,41 +64,49 @@ public class SingletonHolder { try { queueSize = Integer.parseInt(queueValue); logger.trace("Queue size was set to {}", queueSize); - }catch(NumberFormatException e) { + } catch (NumberFormatException e) { logger.warn("Cannot parse {} as set by {}, using default {}", queueValue, NOTIFICATION_QUEUE_SIZE_PROPERTY, queueSize); } } + // Overriding the queue: // ThreadPoolExecutor would not create new threads if the queue is not full, thus adding // occurs in RejectedExecutionHandler. // This impl saturates threadpool first, then queue. When both are full caller will get blocked. - BlockingQueue queue = new LinkedBlockingQueue(queueSize) { - private static final long serialVersionUID = 1L; + final BlockingQueue delegate = new LinkedBlockingQueue<>(queueSize); + final BlockingQueue queue = new ForwardingBlockingQueue() { + @Override + protected BlockingQueue delegate() { + return delegate; + } @Override - public boolean offer(Runnable r) { - // ThreadPoolExecutor will spawn a new thread after core size is reached only if the queue.offer returns false. + public boolean offer(final Runnable r) { + // ThreadPoolExecutor will spawn a new thread after core size is reached only + // if the queue.offer returns false. return false; } }; - ThreadFactory factory = new ThreadFactoryBuilder().setDaemon(true).setNameFormat("md-sal-binding-notification-%d").build(); + final ThreadFactory factory = new ThreadFactoryBuilder() + .setDaemon(true) + .setNameFormat("md-sal-binding-notification-%d") + .build(); - ThreadPoolExecutor executor = new ThreadPoolExecutor(CORE_NOTIFICATION_THREADS, MAX_NOTIFICATION_THREADS, - NOTIFICATION_THREAD_LIFE, TimeUnit.SECONDS, queue , factory, + final ThreadPoolExecutor executor = new ThreadPoolExecutor(CORE_NOTIFICATION_THREADS, MAX_NOTIFICATION_THREADS, + NOTIFICATION_THREAD_LIFE, TimeUnit.SECONDS, queue, factory, new RejectedExecutionHandler() { - // if the max threads are met, then it will raise a rejectedExecution. We then push to the queue. - @Override - public void rejectedExecution(Runnable r, ThreadPoolExecutor executor) { - try { - executor.getQueue().put(r); - } catch (InterruptedException e) { - Thread.currentThread().interrupt();// set interrupt flag after clearing - throw new IllegalStateException(e); - } - } - }); + // if the max threads are met, then it will raise a rejectedExecution. We then push to the queue. + @Override + public void rejectedExecution(final Runnable r, final ThreadPoolExecutor executor) { + try { + executor.getQueue().put(r); + } catch (InterruptedException e) { + throw new RejectedExecutionException("Interrupted while waiting on the queue", e); + } + } + }); NOTIFICATION_EXECUTOR = MoreExecutors.listeningDecorator(executor); } diff --git a/opendaylight/md-sal/sal-binding-broker/src/main/java/org/opendaylight/controller/sal/binding/impl/AbstractNotificationListenerRegistration.java b/opendaylight/md-sal/sal-binding-broker/src/main/java/org/opendaylight/controller/sal/binding/impl/AbstractNotificationListenerRegistration.java new file mode 100644 index 0000000000..5e7c91374f --- /dev/null +++ b/opendaylight/md-sal/sal-binding-broker/src/main/java/org/opendaylight/controller/sal/binding/impl/AbstractNotificationListenerRegistration.java @@ -0,0 +1,41 @@ +/* + * Copyright (c) 2014 Cisco Systems, Inc. and others. All rights reserved. + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License v1.0 which accompanies this distribution, + * and is available at http://www.eclipse.org/legal/epl-v10.html + */ +package org.opendaylight.controller.sal.binding.impl; + +import org.opendaylight.controller.sal.binding.api.NotificationListener; +import org.opendaylight.yangtools.concepts.AbstractListenerRegistration; +import org.opendaylight.yangtools.yang.binding.Notification; + +import com.google.common.base.Preconditions; + +/** + * Abstract implementation of {@link NotificationListenerRegistration}. + * + * @param Notification type + */ +abstract class AbstractNotificationListenerRegistration extends AbstractListenerRegistration> implements NotificationListenerRegistration { + private final Class type; + + protected AbstractNotificationListenerRegistration(final Class type, final NotificationListener listener) { + super(listener); + this.type = Preconditions.checkNotNull(type); + } + + @Override + public Class getType() { + return type; + } + + @Override + @SuppressWarnings("unchecked") + public void notify(final Notification notification) { + if (!isClosed()) { + getInstance().onNotification((T)notification); + } + } +} diff --git a/opendaylight/md-sal/sal-binding-broker/src/main/java/org/opendaylight/controller/sal/binding/impl/AggregatedNotificationListenerRegistration.java b/opendaylight/md-sal/sal-binding-broker/src/main/java/org/opendaylight/controller/sal/binding/impl/AggregatedNotificationListenerRegistration.java new file mode 100644 index 0000000000..f0db891f14 --- /dev/null +++ b/opendaylight/md-sal/sal-binding-broker/src/main/java/org/opendaylight/controller/sal/binding/impl/AggregatedNotificationListenerRegistration.java @@ -0,0 +1,57 @@ +/* + * Copyright (c) 2014 Cisco Systems, Inc. and others. All rights reserved. + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License v1.0 which accompanies this distribution, + * and is available at http://www.eclipse.org/legal/epl-v10.html + */ +package org.opendaylight.controller.sal.binding.impl; + +import org.opendaylight.controller.sal.binding.api.NotificationListener; +import org.opendaylight.yangtools.yang.binding.Notification; + +import com.google.common.base.Preconditions; + +/** + * An aggregated listener registration. This is a result of registering an invoker which can handle multiple + * interfaces at the same time. In order to support correct delivery, we need to maintain per-type registrations + * which get squashed if a notification which implements multiple interfaces is encountered. + * + * We take care of that by implementing alternate {@link #hashCode()}/{@link #equals(Object)}, which resolve + * to the backing aggregator. + * + * @param Notification type + * @param Aggregator type + */ +abstract class AggregatedNotificationListenerRegistration extends AbstractNotificationListenerRegistration { + private final A aggregator; + + protected AggregatedNotificationListenerRegistration(final Class type, final NotificationListener listener, final A aggregator) { + super(type, listener); + this.aggregator = Preconditions.checkNotNull(aggregator); + } + + protected A getAggregator() { + return aggregator; + } + + @Override + public int hashCode() { + return aggregator.hashCode(); + } + + @Override + public boolean equals(final Object obj) { + if (this == obj) { + return true; + } + if (obj == null) { + return false; + } + if (!this.getClass().equals(obj.getClass())) { + return false; + } + + return aggregator.equals(((AggregatedNotificationListenerRegistration)obj).aggregator); + } +} diff --git a/opendaylight/md-sal/sal-binding-broker/src/main/java/org/opendaylight/controller/sal/binding/impl/GeneratedListenerRegistration.java b/opendaylight/md-sal/sal-binding-broker/src/main/java/org/opendaylight/controller/sal/binding/impl/GeneratedListenerRegistration.java deleted file mode 100644 index 5325ed3c3a..0000000000 --- a/opendaylight/md-sal/sal-binding-broker/src/main/java/org/opendaylight/controller/sal/binding/impl/GeneratedListenerRegistration.java +++ /dev/null @@ -1,39 +0,0 @@ -/** - * Copyright (c) 2013 Cisco Systems, Inc. and others. All rights reserved. - * - * This program and the accompanying materials are made available under the - * terms of the Eclipse Public License v1.0 which accompanies this distribution, - * and is available at http://www.eclipse.org/legal/epl-v10.html - */ -package org.opendaylight.controller.sal.binding.impl; - -import org.opendaylight.controller.sal.binding.spi.NotificationInvokerFactory.NotificationInvoker; -import org.opendaylight.yangtools.concepts.AbstractObjectRegistration; -import org.opendaylight.yangtools.concepts.ListenerRegistration; -import org.opendaylight.yangtools.yang.binding.NotificationListener; - -import com.google.common.base.Preconditions; - -class GeneratedListenerRegistration extends AbstractObjectRegistration implements ListenerRegistration { - private NotificationBrokerImpl notificationBroker; - private final NotificationInvoker invoker; - - public GeneratedListenerRegistration(final NotificationListener instance, final NotificationInvoker invoker, final NotificationBrokerImpl broker) { - super(instance); - this.invoker = Preconditions.checkNotNull(invoker); - this.notificationBroker = Preconditions.checkNotNull(broker); - } - - public NotificationInvoker getInvoker() { - // There is a race with NotificationBrokerImpl: - // the invoker can be closed here - return invoker; - } - - @Override - protected void removeRegistration() { - notificationBroker.unregisterListener(this); - notificationBroker = null; - invoker.close(); - } -} diff --git a/opendaylight/md-sal/sal-binding-broker/src/main/java/org/opendaylight/controller/sal/binding/impl/GenericNotificationRegistration.java b/opendaylight/md-sal/sal-binding-broker/src/main/java/org/opendaylight/controller/sal/binding/impl/GenericNotificationRegistration.java deleted file mode 100644 index 448adfa02e..0000000000 --- a/opendaylight/md-sal/sal-binding-broker/src/main/java/org/opendaylight/controller/sal/binding/impl/GenericNotificationRegistration.java +++ /dev/null @@ -1,36 +0,0 @@ -/** - * Copyright (c) 2013 Cisco Systems, Inc. and others. All rights reserved. - * - * This program and the accompanying materials are made available under the - * terms of the Eclipse Public License v1.0 which accompanies this distribution, - * and is available at http://www.eclipse.org/legal/epl-v10.html - */ -package org.opendaylight.controller.sal.binding.impl; - -import org.opendaylight.controller.sal.binding.api.NotificationListener; -import org.opendaylight.yangtools.concepts.AbstractObjectRegistration; -import org.opendaylight.yangtools.concepts.ListenerRegistration; -import org.opendaylight.yangtools.yang.binding.Notification; - -import com.google.common.base.Preconditions; - -class GenericNotificationRegistration extends AbstractObjectRegistration> implements ListenerRegistration> { - private final Class type; - private NotificationBrokerImpl notificationBroker; - - public GenericNotificationRegistration(final Class type, final NotificationListener instance, final NotificationBrokerImpl broker) { - super(instance); - this.type = Preconditions.checkNotNull(type); - this.notificationBroker = Preconditions.checkNotNull(broker); - } - - public Class getType() { - return type; - } - - @Override - protected void removeRegistration() { - notificationBroker.unregisterListener(this); - notificationBroker = null; - } -} diff --git a/opendaylight/md-sal/sal-binding-broker/src/main/java/org/opendaylight/controller/sal/binding/impl/ListenerMapGeneration.java b/opendaylight/md-sal/sal-binding-broker/src/main/java/org/opendaylight/controller/sal/binding/impl/ListenerMapGeneration.java new file mode 100644 index 0000000000..4d893aa7be --- /dev/null +++ b/opendaylight/md-sal/sal-binding-broker/src/main/java/org/opendaylight/controller/sal/binding/impl/ListenerMapGeneration.java @@ -0,0 +1,106 @@ +/** + * Copyright (c) 2014 Cisco Systems, Inc. and others. All rights reserved. + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License v1.0 which accompanies this distribution, + * and is available at http://www.eclipse.org/legal/epl-v10.html + */ +package org.opendaylight.controller.sal.binding.impl; + +import java.util.Arrays; +import java.util.Collection; +import java.util.HashSet; +import java.util.Set; + +import org.opendaylight.yangtools.yang.binding.Notification; + +import com.google.common.base.Predicate; +import com.google.common.cache.CacheBuilder; +import com.google.common.cache.CacheLoader; +import com.google.common.cache.LoadingCache; +import com.google.common.collect.ImmutableMultimap; +import com.google.common.collect.ImmutableSet; +import com.google.common.collect.Iterables; +import com.google.common.collect.Multimap; + +/** + * An immutable view of the current generation of listeners. + */ +final class ListenerMapGeneration { + private static final int CACHE_MAX_ENTRIES = 1000; + + /** + * Constant map of notification type to subscribed listeners. + */ + private final Multimap, NotificationListenerRegistration> typeToListeners; + + /** + * Dynamic cache of notification implementation to matching listeners. This cache loads entries based on + * the contents of the {@link #typeToListeners} map. + */ + private final LoadingCache, Iterable>> implementationToListeners = + CacheBuilder.newBuilder() + .weakKeys() + .maximumSize(CACHE_MAX_ENTRIES) + .build(new CacheLoader, Iterable>>() { + @Override + public Iterable> load(final Class key) { + final Set> regs = new HashSet<>(); + + for (final Class type : getNotificationTypes(key)) { + @SuppressWarnings("unchecked") + final Collection> l = typeToListeners.get((Class) type); + if (l != null) { + regs.addAll(l); + } + } + + return ImmutableSet.copyOf(regs); + } + }); + + ListenerMapGeneration() { + typeToListeners = ImmutableMultimap.of(); + } + + ListenerMapGeneration(final Multimap, NotificationListenerRegistration> listeners) { + this.typeToListeners = ImmutableMultimap.copyOf(listeners); + } + + /** + * Current listeners. Exposed for creating the next generation. + * + * @return Current type-to-listener map. + */ + Multimap, NotificationListenerRegistration> getListeners() { + return typeToListeners; + } + + /** + * Look up the listeners which need to see this notification delivered. + * + * @param notification Notification object + * @return Iterable of listeners, guaranteed to be nonnull. + */ + public Iterable> listenersFor(final Notification notification) { + // Safe to use, as our loader does not throw checked exceptions + return implementationToListeners.getUnchecked(notification.getClass()); + } + + public Iterable> getKnownTypes() { + return typeToListeners.keySet(); + } + + private static Iterable> getNotificationTypes(final Class cls) { + final Class[] ifaces = cls.getInterfaces(); + return Iterables.filter(Arrays.asList(ifaces), new Predicate>() { + @Override + public boolean apply(final Class input) { + if (Notification.class.equals(input)) { + return false; + } + return Notification.class.isAssignableFrom(input); + } + }); + } +} \ No newline at end of file diff --git a/opendaylight/md-sal/sal-binding-broker/src/main/java/org/opendaylight/controller/sal/binding/impl/NotificationBrokerImpl.java b/opendaylight/md-sal/sal-binding-broker/src/main/java/org/opendaylight/controller/sal/binding/impl/NotificationBrokerImpl.java index d3b68002c3..258ba51777 100644 --- a/opendaylight/md-sal/sal-binding-broker/src/main/java/org/opendaylight/controller/sal/binding/impl/NotificationBrokerImpl.java +++ b/opendaylight/md-sal/sal-binding-broker/src/main/java/org/opendaylight/controller/sal/binding/impl/NotificationBrokerImpl.java @@ -7,90 +7,82 @@ */ package org.opendaylight.controller.sal.binding.impl; -import java.util.Arrays; -import java.util.Collections; -import java.util.HashSet; import java.util.Set; import java.util.concurrent.ExecutorService; +import java.util.concurrent.atomic.AtomicReference; + +import javax.annotation.concurrent.GuardedBy; import org.opendaylight.controller.sal.binding.api.NotificationListener; import org.opendaylight.controller.sal.binding.api.NotificationProviderService; import org.opendaylight.controller.sal.binding.codegen.impl.SingletonHolder; import org.opendaylight.controller.sal.binding.spi.NotificationInvokerFactory.NotificationInvoker; +import org.opendaylight.yangtools.concepts.AbstractListenerRegistration; import org.opendaylight.yangtools.concepts.ListenerRegistration; -import org.opendaylight.yangtools.concepts.Registration; import org.opendaylight.yangtools.concepts.util.ListenerRegistry; import org.opendaylight.yangtools.yang.binding.Notification; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import com.google.common.base.Preconditions; -import com.google.common.base.Predicate; import com.google.common.collect.HashMultimap; -import com.google.common.collect.Iterables; import com.google.common.collect.Multimap; -import com.google.common.collect.Multimaps; public class NotificationBrokerImpl implements NotificationProviderService, AutoCloseable { private static final Logger LOG = LoggerFactory.getLogger(NotificationBrokerImpl.class); private final ListenerRegistry interestListeners = ListenerRegistry.create(); + private final AtomicReference listeners = new AtomicReference<>(new ListenerMapGeneration()); + private final ExecutorService executor; - private final Multimap, NotificationListener> listeners = - Multimaps.synchronizedSetMultimap(HashMultimap., NotificationListener>create()); - private ExecutorService executor; - - @Deprecated public NotificationBrokerImpl(final ExecutorService executor) { - this.setExecutor(executor); - } - - public void setExecutor(final ExecutorService executor) { this.executor = Preconditions.checkNotNull(executor); } - public Iterable> getNotificationTypes(final Notification notification) { - final Class[] ifaces = notification.getClass().getInterfaces(); - return Iterables.filter(Arrays.asList(ifaces), new Predicate>() { - @Override - public boolean apply(final Class input) { - if (Notification.class.equals(input)) { - return false; - } - return Notification.class.isAssignableFrom(input); - } - }); - } - @Override public void publish(final Notification notification) { - this.publish(notification, executor); + publish(notification, executor); } @Override public void publish(final Notification notification, final ExecutorService service) { - Iterable> listenerToNotify = Collections.emptySet(); - for (final Class type : getNotificationTypes(notification)) { - listenerToNotify = Iterables.concat(listenerToNotify, listeners.get(((Class) type))); + for (NotificationListenerRegistration r : listeners.get().listenersFor(notification)) { + service.submit(new NotifyTask(r, notification)); } + } + + @GuardedBy("this") + private Multimap, NotificationListenerRegistration> mutableListeners() { + return HashMultimap.create(listeners.get().getListeners()); + } - final Set tasks = new HashSet<>(); - for (NotificationListener l : listenerToNotify) { - tasks.add(new NotifyTask(l, notification)); + private final void addRegistrations(final NotificationListenerRegistration... registrations) { + synchronized (this) { + final Multimap, NotificationListenerRegistration> newListeners = + mutableListeners(); + for (NotificationListenerRegistration reg : registrations) { + newListeners.put(reg.getType(), reg); + } + + listeners.set(new ListenerMapGeneration(newListeners)); } - for (final NotifyTask task : tasks) { - service.submit(task); + // Notifications are dispatched out of lock... + for (NotificationListenerRegistration reg : registrations) { + announceNotificationSubscription(reg.getType()); } } - @Override - public Registration> registerNotificationListener(final Class notificationType, final NotificationListener listener) { - final GenericNotificationRegistration reg = new GenericNotificationRegistration(notificationType, listener, this); - this.listeners.put(notificationType, listener); - this.announceNotificationSubscription(notificationType); - return reg; + private synchronized void removeRegistrations(final NotificationListenerRegistration... registrations) { + final Multimap, NotificationListenerRegistration> newListeners = + mutableListeners(); + + for (NotificationListenerRegistration reg : registrations) { + newListeners.remove(reg.getType(), reg); + } + + listeners.set(new ListenerMapGeneration(newListeners)); } private void announceNotificationSubscription(final Class notification) { @@ -105,37 +97,63 @@ public class NotificationBrokerImpl implements NotificationProviderService, Auto } @Override - public Registration registerNotificationListener(final org.opendaylight.yangtools.yang.binding.NotificationListener listener) { - final NotificationInvoker invoker = SingletonHolder.INVOKER_FACTORY.invokerFor(listener); - for (final Class notifyType : invoker.getSupportedNotifications()) { - listeners.put(notifyType, invoker.getInvocationProxy()); - announceNotificationSubscription(notifyType); - } + public ListenerRegistration registerInterestListener(final NotificationInterestListener interestListener) { + final ListenerRegistration registration = this.interestListeners.register(interestListener); - return new GeneratedListenerRegistration(listener, invoker, this); + for (final Class notification : listeners.get().getKnownTypes()) { + interestListener.onNotificationSubscribtion(notification); + } + return registration; } - protected boolean unregisterListener(final GenericNotificationRegistration reg) { - return listeners.remove(reg.getType(), reg.getInstance()); + @Override + public NotificationListenerRegistration registerNotificationListener(final Class notificationType, final NotificationListener listener) { + final NotificationListenerRegistration reg = new AbstractNotificationListenerRegistration(notificationType, listener) { + @Override + protected void removeRegistration() { + removeRegistrations(this); + } + }; + + addRegistrations(reg); + return reg; } - protected void unregisterListener(final GeneratedListenerRegistration reg) { - final NotificationInvoker invoker = reg.getInvoker(); - for (final Class notifyType : invoker.getSupportedNotifications()) { - this.listeners.remove(notifyType, invoker.getInvocationProxy()); + @Override + public ListenerRegistration registerNotificationListener(final org.opendaylight.yangtools.yang.binding.NotificationListener listener) { + final NotificationInvoker invoker = SingletonHolder.INVOKER_FACTORY.invokerFor(listener); + final Set> types = invoker.getSupportedNotifications(); + final NotificationListenerRegistration[] regs = new NotificationListenerRegistration[types.size()]; + + // Populate the registrations... + int i = 0; + for (Class type : types) { + regs[i] = new AggregatedNotificationListenerRegistration(type, invoker.getInvocationProxy(), regs) { + @Override + protected void removeRegistration() { + // Nothing to do, will be cleaned up by parent (below) + } + }; + ++i; } + + // ... now put them to use ... + addRegistrations(regs); + + // ... finally return the parent registration + return new AbstractListenerRegistration(listener) { + @Override + protected void removeRegistration() { + removeRegistrations(regs); + for (ListenerRegistration reg : regs) { + reg.close(); + } + } + }; } @Override public void close() { } - @Override - public ListenerRegistration registerInterestListener(final NotificationInterestListener interestListener) { - final ListenerRegistration registration = this.interestListeners.register(interestListener); - for (final Class notification : listeners.keySet()) { - interestListener.onNotificationSubscribtion(notification); - } - return registration; - } } diff --git a/opendaylight/md-sal/sal-binding-broker/src/main/java/org/opendaylight/controller/sal/binding/impl/NotificationListenerRegistration.java b/opendaylight/md-sal/sal-binding-broker/src/main/java/org/opendaylight/controller/sal/binding/impl/NotificationListenerRegistration.java new file mode 100644 index 0000000000..3dba868c6f --- /dev/null +++ b/opendaylight/md-sal/sal-binding-broker/src/main/java/org/opendaylight/controller/sal/binding/impl/NotificationListenerRegistration.java @@ -0,0 +1,35 @@ +/* + * Copyright (c) 2014 Cisco Systems, Inc. and others. All rights reserved. + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License v1.0 which accompanies this distribution, + * and is available at http://www.eclipse.org/legal/epl-v10.html + */ +package org.opendaylight.controller.sal.binding.impl; + +import org.opendaylight.controller.sal.binding.api.NotificationListener; +import org.opendaylight.yangtools.concepts.ListenerRegistration; +import org.opendaylight.yangtools.yang.binding.Notification; + +/** + * A registration of a {@link NotificationListener}. Allows query of the type + * of the notification and dispatching the notification atomically with regard + * to unregistration. + * + * @param Type of notification + */ +interface NotificationListenerRegistration extends ListenerRegistration> { + /** + * Return the interface class of the notification type. + * + * @return Notification type. + */ + Class getType(); + + /** + * Dispatch a notification to the listener. + * + * @param notification Notification to be dispatched + */ + void notify(Notification notification); +} diff --git a/opendaylight/md-sal/sal-binding-broker/src/main/java/org/opendaylight/controller/sal/binding/impl/NotifyTask.java b/opendaylight/md-sal/sal-binding-broker/src/main/java/org/opendaylight/controller/sal/binding/impl/NotifyTask.java index 5f0de6bc16..2622a71e55 100644 --- a/opendaylight/md-sal/sal-binding-broker/src/main/java/org/opendaylight/controller/sal/binding/impl/NotifyTask.java +++ b/opendaylight/md-sal/sal-binding-broker/src/main/java/org/opendaylight/controller/sal/binding/impl/NotifyTask.java @@ -7,7 +7,6 @@ */ package org.opendaylight.controller.sal.binding.impl; -import org.opendaylight.controller.sal.binding.api.NotificationListener; import org.opendaylight.yangtools.yang.binding.Notification; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -18,37 +17,37 @@ import com.google.common.base.Preconditions; class NotifyTask implements Runnable { private static final Logger LOG = LoggerFactory.getLogger(NotifyTask.class); - private final NotificationListener listener; + private final NotificationListenerRegistration registration; private final Notification notification; - public NotifyTask(final NotificationListener listener, final Notification notification) { - this.listener = Preconditions.checkNotNull(listener); + public NotifyTask(final NotificationListenerRegistration registration, final Notification notification) { + this.registration = Preconditions.checkNotNull(registration); this.notification = Preconditions.checkNotNull(notification); } @SuppressWarnings("unchecked") - private NotificationListener getListener() { - return (NotificationListener)listener; + private NotificationListenerRegistration getRegistration() { + return (NotificationListenerRegistration)registration; } @Override public void run() { if (LOG.isDebugEnabled()) { - LOG.debug("Delivering notification {} to {}", notification, listener); + LOG.debug("Delivering notification {} to {}", notification, registration.getInstance()); } else { - LOG.trace("Delivering notification {} to {}", notification.getClass().getName(), listener); + LOG.trace("Delivering notification {} to {}", notification.getClass().getName(), registration.getInstance()); } try { - getListener().onNotification(notification); + getRegistration().notify(notification); } catch (final Exception e) { - LOG.error("Unhandled exception thrown by listener: {}", listener, e); + LOG.error("Unhandled exception thrown by listener: {}", registration.getInstance(), e); } if (LOG.isDebugEnabled()) { - LOG.debug("Notification delivered {} to {}", notification, listener); + LOG.debug("Notification delivered {} to {}", notification, registration.getInstance()); } else { - LOG.trace("Notification delivered {} to {}", notification.getClass().getName(), listener); + LOG.trace("Notification delivered {} to {}", notification.getClass().getName(), registration.getInstance()); } } @@ -56,7 +55,7 @@ class NotifyTask implements Runnable { public int hashCode() { final int prime = 31; int result = 1; - result = prime * result + ((listener== null) ? 0 : listener.hashCode()); + result = prime * result + ((registration== null) ? 0 : registration.hashCode()); result = prime * result + ((notification== null) ? 0 : notification.hashCode()); return result; } @@ -70,10 +69,10 @@ class NotifyTask implements Runnable { if (getClass() != obj.getClass()) return false; NotifyTask other = (NotifyTask) obj; - if (listener == null) { - if (other.listener != null) + if (registration == null) { + if (other.registration != null) return false; - } else if (!listener.equals(other.listener)) + } else if (!registration.equals(other.registration)) return false; if (notification == null) { if (other.notification != null) @@ -86,7 +85,7 @@ class NotifyTask implements Runnable { @Override public String toString() { return Objects.toStringHelper(this) - .add("listener", listener) + .add("listener", registration) .add("notification", notification.getClass()) .toString(); } diff --git a/opendaylight/md-sal/sal-dom-broker/src/main/java/org/opendaylight/controller/md/sal/dom/store/impl/AbstractDOMStoreTransaction.java b/opendaylight/md-sal/sal-dom-broker/src/main/java/org/opendaylight/controller/md/sal/dom/store/impl/AbstractDOMStoreTransaction.java new file mode 100644 index 0000000000..8a190c115f --- /dev/null +++ b/opendaylight/md-sal/sal-dom-broker/src/main/java/org/opendaylight/controller/md/sal/dom/store/impl/AbstractDOMStoreTransaction.java @@ -0,0 +1,51 @@ +/* + * Copyright (c) 2014 Cisco Systems, Inc. and others. All rights reserved. + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License v1.0 which accompanies this distribution, + * and is available at http://www.eclipse.org/legal/epl-v10.html + */ +package org.opendaylight.controller.md.sal.dom.store.impl; + +import org.opendaylight.controller.sal.core.spi.data.DOMStoreTransaction; + +import com.google.common.base.Objects; +import com.google.common.base.Objects.ToStringHelper; +import com.google.common.base.Preconditions; + +/** + * Abstract DOM Store Transaction + * + * Convenience super implementation of DOM Store transaction which provides + * common implementation of {@link #toString()} and {@link #getIdentifier()}. + * + * + */ +abstract class AbstractDOMStoreTransaction implements DOMStoreTransaction { + private final Object identifier; + + protected AbstractDOMStoreTransaction(final Object identifier) { + this.identifier = Preconditions.checkNotNull(identifier,"Identifier must not be null."); + } + + @Override + public final Object getIdentifier() { + return identifier; + } + + @Override + public final String toString() { + return addToStringAttributes(Objects.toStringHelper(this)).toString(); + } + + /** + * Add class-specific toString attributes. + * + * @param toStringHelper + * ToStringHelper instance + * @return ToStringHelper instance which was passed in + */ + protected ToStringHelper addToStringAttributes(final ToStringHelper toStringHelper) { + return toStringHelper.add("id", identifier); + } +} \ No newline at end of file diff --git a/opendaylight/md-sal/sal-dom-broker/src/main/java/org/opendaylight/controller/md/sal/dom/store/impl/InMemoryDOMDataStore.java b/opendaylight/md-sal/sal-dom-broker/src/main/java/org/opendaylight/controller/md/sal/dom/store/impl/InMemoryDOMDataStore.java index 87c68596ef..2495146aa6 100644 --- a/opendaylight/md-sal/sal-dom-broker/src/main/java/org/opendaylight/controller/md/sal/dom/store/impl/InMemoryDOMDataStore.java +++ b/opendaylight/md-sal/sal-dom-broker/src/main/java/org/opendaylight/controller/md/sal/dom/store/impl/InMemoryDOMDataStore.java @@ -7,7 +7,6 @@ */ package org.opendaylight.controller.md.sal.dom.store.impl; -import static com.google.common.base.Preconditions.checkNotNull; import static com.google.common.base.Preconditions.checkState; import java.util.Collections; @@ -16,6 +15,7 @@ import java.util.concurrent.atomic.AtomicLong; import org.opendaylight.controller.md.sal.common.api.data.AsyncDataBroker.DataChangeScope; import org.opendaylight.controller.md.sal.common.api.data.AsyncDataChangeListener; +import org.opendaylight.controller.md.sal.dom.store.impl.SnapshotBackedWriteTransaction.TransactionReadyPrototype; import org.opendaylight.controller.md.sal.dom.store.impl.tree.DataPreconditionFailedException; import org.opendaylight.controller.md.sal.dom.store.impl.tree.DataTree; import org.opendaylight.controller.md.sal.dom.store.impl.tree.DataTreeCandidate; @@ -27,7 +27,6 @@ import org.opendaylight.controller.sal.core.spi.data.DOMStore; import org.opendaylight.controller.sal.core.spi.data.DOMStoreReadTransaction; import org.opendaylight.controller.sal.core.spi.data.DOMStoreReadWriteTransaction; import org.opendaylight.controller.sal.core.spi.data.DOMStoreThreePhaseCommitCohort; -import org.opendaylight.controller.sal.core.spi.data.DOMStoreTransaction; import org.opendaylight.controller.sal.core.spi.data.DOMStoreTransactionChain; import org.opendaylight.controller.sal.core.spi.data.DOMStoreWriteTransaction; import org.opendaylight.yangtools.concepts.AbstractListenerRegistration; @@ -40,15 +39,22 @@ import org.opendaylight.yangtools.yang.model.api.SchemaContextListener; import org.slf4j.Logger; import org.slf4j.LoggerFactory; -import com.google.common.base.Objects; -import com.google.common.base.Objects.ToStringHelper; import com.google.common.base.Optional; import com.google.common.base.Preconditions; import com.google.common.util.concurrent.Futures; import com.google.common.util.concurrent.ListenableFuture; import com.google.common.util.concurrent.ListeningExecutorService; -public class InMemoryDOMDataStore implements DOMStore, Identifiable, SchemaContextListener { +/** + * In-memory DOM Data Store + * + * Implementation of {@link DOMStore} which uses {@link DataTree} + * and other classes such as {@link SnapshotBackedWriteTransaction}. + * {@link SnapshotBackedReadTransaction} and {@link ResolveDataChangeEventsTask} + * to implement {@link DOMStore} contract. + * + */ +public class InMemoryDOMDataStore implements DOMStore, Identifiable, SchemaContextListener, TransactionReadyPrototype { private static final Logger LOG = LoggerFactory.getLogger(InMemoryDOMDataStore.class); private final DataTree dataTree = InMemoryDataTreeFactory.getInstance().create(); private final ListenerTree listenerTree = ListenerTree.create(); @@ -83,7 +89,7 @@ public class InMemoryDOMDataStore implements DOMStore, Identifiable, Sch @Override public DOMStoreTransactionChain createTransactionChain() { - throw new UnsupportedOperationException("Not implemented yet."); + return new DOMStoreTransactionChainImpl(); } @Override @@ -130,7 +136,8 @@ public class InMemoryDOMDataStore implements DOMStore, Identifiable, Sch }; } - private synchronized DOMStoreThreePhaseCommitCohort submit(final SnapshotBackedWriteTransaction writeTx) { + @Override + public synchronized DOMStoreThreePhaseCommitCohort ready(final SnapshotBackedWriteTransaction writeTx) { LOG.debug("Tx: {} is submitted. Modifications: {}", writeTx.getIdentifier(), writeTx.getMutatedView()); return new ThreePhaseCommitImpl(writeTx); } @@ -139,162 +146,61 @@ public class InMemoryDOMDataStore implements DOMStore, Identifiable, Sch return name + "-" + txCounter.getAndIncrement(); } - private static abstract class AbstractDOMStoreTransaction implements DOMStoreTransaction { - private final Object identifier; - - protected AbstractDOMStoreTransaction(final Object identifier) { - this.identifier = identifier; - } - - @Override - public final Object getIdentifier() { - return identifier; - } - - @Override - public final String toString() { - return addToStringAttributes(Objects.toStringHelper(this)).toString(); - } - - /** - * Add class-specific toString attributes. - * - * @param toStringHelper - * ToStringHelper instance - * @return ToStringHelper instance which was passed in - */ - protected ToStringHelper addToStringAttributes(final ToStringHelper toStringHelper) { - return toStringHelper.add("id", identifier); - } - } - - private static final class SnapshotBackedReadTransaction extends AbstractDOMStoreTransaction implements - DOMStoreReadTransaction { - private DataTreeSnapshot stableSnapshot; + private class DOMStoreTransactionChainImpl implements DOMStoreTransactionChain, TransactionReadyPrototype { - public SnapshotBackedReadTransaction(final Object identifier, final DataTreeSnapshot snapshot) { - super(identifier); - this.stableSnapshot = Preconditions.checkNotNull(snapshot); - LOG.debug("ReadOnly Tx: {} allocated with snapshot {}", identifier, snapshot); - } - - @Override - public void close() { - LOG.debug("Store transaction: {} : Closed", getIdentifier()); - stableSnapshot = null; - } + private SnapshotBackedWriteTransaction previousOutstandingTx; @Override - public ListenableFuture>> read(final InstanceIdentifier path) { - checkNotNull(path, "Path must not be null."); - checkState(stableSnapshot != null, "Transaction is closed"); - return Futures.immediateFuture(stableSnapshot.readNode(path)); - } - } - - private static class SnapshotBackedWriteTransaction extends AbstractDOMStoreTransaction implements - DOMStoreWriteTransaction { - private DataTreeModification mutableTree; - private InMemoryDOMDataStore store; - private boolean ready = false; - - public SnapshotBackedWriteTransaction(final Object identifier, final DataTreeSnapshot snapshot, - final InMemoryDOMDataStore store) { - super(identifier); - mutableTree = snapshot.newModification(); - this.store = store; - LOG.debug("Write Tx: {} allocated with snapshot {}", identifier, snapshot); - } - - @Override - public void close() { - LOG.debug("Store transaction: {} : Closed", getIdentifier()); - this.mutableTree = null; - this.store = null; - } - - @Override - public void write(final InstanceIdentifier path, final NormalizedNode data) { - checkNotReady(); - try { - LOG.trace("Tx: {} Write: {}:{}", getIdentifier(), path, data); - mutableTree.write(path, data); - // FIXME: Add checked exception - } catch (Exception e) { - LOG.error("Tx: {}, failed to write {}:{} in {}", getIdentifier(), path, data, mutableTree, e); + public synchronized DOMStoreReadTransaction newReadOnlyTransaction() { + final DataTreeSnapshot snapshot; + if(previousOutstandingTx != null) { + checkState(previousOutstandingTx.isReady(), "Previous transaction in chain must be ready."); + snapshot = previousOutstandingTx.getMutatedView(); + } else { + snapshot = dataTree.takeSnapshot(); } + return new SnapshotBackedReadTransaction(nextIdentifier(), snapshot); } @Override - public void merge(final InstanceIdentifier path, final NormalizedNode data) { - checkNotReady(); - try { - LOG.trace("Tx: {} Merge: {}:{}", getIdentifier(), path, data); - mutableTree.merge(path, data); - // FIXME: Add checked exception - } catch (Exception e) { - LOG.error("Tx: {}, failed to write {}:{} in {}", getIdentifier(), path, data, mutableTree, e); + public synchronized DOMStoreReadWriteTransaction newReadWriteTransaction() { + final DataTreeSnapshot snapshot; + if(previousOutstandingTx != null) { + checkState(previousOutstandingTx.isReady(), "Previous transaction in chain must be ready."); + snapshot = previousOutstandingTx.getMutatedView(); + } else { + snapshot = dataTree.takeSnapshot().newModification(); } + SnapshotBackedReadWriteTransaction ret = new SnapshotBackedReadWriteTransaction(nextIdentifier(), snapshot,this); + return ret; } @Override - public void delete(final InstanceIdentifier path) { - checkNotReady(); - try { - LOG.trace("Tx: {} Delete: {}", getIdentifier(), path); - mutableTree.delete(path); - // FIXME: Add checked exception - } catch (Exception e) { - LOG.error("Tx: {}, failed to delete {} in {}", getIdentifier(), path, mutableTree, e); + public synchronized DOMStoreWriteTransaction newWriteOnlyTransaction() { + final DataTreeSnapshot snapshot; + if(previousOutstandingTx != null) { + checkState(previousOutstandingTx.isReady(), "Previous transaction in chain must be ready."); + snapshot = previousOutstandingTx.getMutatedView(); + } else { + snapshot = dataTree.takeSnapshot().newModification(); } - } - - protected final boolean isReady() { - return ready; - } - - protected final void checkNotReady() { - checkState(!ready, "Transaction %s is ready. No further modifications allowed.", getIdentifier()); + SnapshotBackedWriteTransaction ret =new SnapshotBackedWriteTransaction(nextIdentifier(), snapshot,this); + return ret; } @Override - public synchronized DOMStoreThreePhaseCommitCohort ready() { - checkState(!ready, "Transaction %s is already ready.", getIdentifier()); - ready = true; - - LOG.debug("Store transaction: {} : Ready", getIdentifier()); - mutableTree.ready(); - return store.submit(this); - } - - protected DataTreeModification getMutatedView() { - return mutableTree; + public DOMStoreThreePhaseCommitCohort ready(final SnapshotBackedWriteTransaction tx) { + DOMStoreThreePhaseCommitCohort storeCohort = InMemoryDOMDataStore.this.ready(tx); + // FIXME: We probably want to add Transaction Chain cohort + return storeCohort; } @Override - protected ToStringHelper addToStringAttributes(final ToStringHelper toStringHelper) { - return toStringHelper.add("ready", isReady()); - } - } - - private static class SnapshotBackedReadWriteTransaction extends SnapshotBackedWriteTransaction implements - DOMStoreReadWriteTransaction { + public void close() { + // TODO Auto-generated method stub - protected SnapshotBackedReadWriteTransaction(final Object identifier, final DataTreeSnapshot snapshot, - final InMemoryDOMDataStore store) { - super(identifier, snapshot, store); } - @Override - public ListenableFuture>> read(final InstanceIdentifier path) { - LOG.trace("Tx: {} Read: {}", getIdentifier(), path); - try { - return Futures.immediateFuture(getMutatedView().readNode(path)); - } catch (Exception e) { - LOG.error("Tx: {} Failed Read of {}", getIdentifier(), path, e); - throw e; - } - } } private class ThreePhaseCommitImpl implements DOMStoreThreePhaseCommitCohort { diff --git a/opendaylight/md-sal/sal-dom-broker/src/main/java/org/opendaylight/controller/md/sal/dom/store/impl/SnapshotBackedReadTransaction.java b/opendaylight/md-sal/sal-dom-broker/src/main/java/org/opendaylight/controller/md/sal/dom/store/impl/SnapshotBackedReadTransaction.java new file mode 100644 index 0000000000..315293fbe7 --- /dev/null +++ b/opendaylight/md-sal/sal-dom-broker/src/main/java/org/opendaylight/controller/md/sal/dom/store/impl/SnapshotBackedReadTransaction.java @@ -0,0 +1,56 @@ +/* + * Copyright (c) 2014 Cisco Systems, Inc. and others. All rights reserved. + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License v1.0 which accompanies this distribution, + * and is available at http://www.eclipse.org/legal/epl-v10.html + */ +package org.opendaylight.controller.md.sal.dom.store.impl; + +import static com.google.common.base.Preconditions.checkNotNull; +import static com.google.common.base.Preconditions.checkState; + +import org.opendaylight.controller.md.sal.dom.store.impl.tree.DataTreeSnapshot; +import org.opendaylight.controller.sal.core.spi.data.DOMStoreReadTransaction; +import org.opendaylight.yangtools.yang.data.api.InstanceIdentifier; +import org.opendaylight.yangtools.yang.data.api.schema.NormalizedNode; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import com.google.common.base.Optional; +import com.google.common.base.Preconditions; +import com.google.common.util.concurrent.Futures; +import com.google.common.util.concurrent.ListenableFuture; + +/** + * + * Implementation of read-only transaction backed by {@link DataTreeSnapshot} + * + * Implementation of read-only transaction backed by {@link DataTreeSnapshot} + * which delegates most of its calls to similar methods provided by underlying snapshot. + * + */ +final class SnapshotBackedReadTransaction extends AbstractDOMStoreTransaction implements +DOMStoreReadTransaction { + private static final Logger LOG = LoggerFactory.getLogger(SnapshotBackedReadTransaction.class); + private DataTreeSnapshot stableSnapshot; + + public SnapshotBackedReadTransaction(final Object identifier, final DataTreeSnapshot snapshot) { + super(identifier); + this.stableSnapshot = Preconditions.checkNotNull(snapshot); + LOG.debug("ReadOnly Tx: {} allocated with snapshot {}", identifier, snapshot); + } + + @Override + public void close() { + LOG.debug("Store transaction: {} : Closed", getIdentifier()); + stableSnapshot = null; + } + + @Override + public ListenableFuture>> read(final InstanceIdentifier path) { + checkNotNull(path, "Path must not be null."); + checkState(stableSnapshot != null, "Transaction is closed"); + return Futures.immediateFuture(stableSnapshot.readNode(path)); + } +} \ No newline at end of file diff --git a/opendaylight/md-sal/sal-dom-broker/src/main/java/org/opendaylight/controller/md/sal/dom/store/impl/SnapshotBackedReadWriteTransaction.java b/opendaylight/md-sal/sal-dom-broker/src/main/java/org/opendaylight/controller/md/sal/dom/store/impl/SnapshotBackedReadWriteTransaction.java new file mode 100644 index 0000000000..4abc80229f --- /dev/null +++ b/opendaylight/md-sal/sal-dom-broker/src/main/java/org/opendaylight/controller/md/sal/dom/store/impl/SnapshotBackedReadWriteTransaction.java @@ -0,0 +1,53 @@ +/* + * Copyright (c) 2014 Cisco Systems, Inc. and others. All rights reserved. + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License v1.0 which accompanies this distribution, + * and is available at http://www.eclipse.org/legal/epl-v10.html + */ +package org.opendaylight.controller.md.sal.dom.store.impl; + +import org.opendaylight.controller.md.sal.dom.store.impl.tree.DataTreeSnapshot; +import org.opendaylight.controller.sal.core.spi.data.DOMStoreReadWriteTransaction; +import org.opendaylight.yangtools.yang.data.api.InstanceIdentifier; +import org.opendaylight.yangtools.yang.data.api.schema.NormalizedNode; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import com.google.common.base.Optional; +import com.google.common.util.concurrent.Futures; +import com.google.common.util.concurrent.ListenableFuture; + +/** + * Implementation of Read-Write transaction which is backed by {@link DataTreeSnapshot} + * and executed according to {@link TransactionReadyPrototype}. + * + */ +class SnapshotBackedReadWriteTransaction extends SnapshotBackedWriteTransaction implements +DOMStoreReadWriteTransaction { + + private static final Logger LOG = LoggerFactory.getLogger(SnapshotBackedReadWriteTransaction.class); + + /** + * Creates new read-write transaction. + * + * @param identifier transaction Identifier + * @param snapshot Snapshot which will be modified. + * @param readyImpl Implementation of ready method. + */ + protected SnapshotBackedReadWriteTransaction(final Object identifier, final DataTreeSnapshot snapshot, + final TransactionReadyPrototype store) { + super(identifier, snapshot, store); + } + + @Override + public ListenableFuture>> read(final InstanceIdentifier path) { + LOG.debug("Tx: {} Read: {}", getIdentifier(), path); + try { + return Futures.immediateFuture(getMutatedView().readNode(path)); + } catch (Exception e) { + LOG.error("Tx: {} Failed Read of {}", getIdentifier(), path, e); + throw e; + } + } +} \ No newline at end of file diff --git a/opendaylight/md-sal/sal-dom-broker/src/main/java/org/opendaylight/controller/md/sal/dom/store/impl/SnapshotBackedWriteTransaction.java b/opendaylight/md-sal/sal-dom-broker/src/main/java/org/opendaylight/controller/md/sal/dom/store/impl/SnapshotBackedWriteTransaction.java new file mode 100644 index 0000000000..717fb11987 --- /dev/null +++ b/opendaylight/md-sal/sal-dom-broker/src/main/java/org/opendaylight/controller/md/sal/dom/store/impl/SnapshotBackedWriteTransaction.java @@ -0,0 +1,162 @@ +/* + * Copyright (c) 2014 Cisco Systems, Inc. and others. All rights reserved. + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License v1.0 which accompanies this distribution, + * and is available at http://www.eclipse.org/legal/epl-v10.html + */ +package org.opendaylight.controller.md.sal.dom.store.impl; + +import static com.google.common.base.Preconditions.checkState; + +import org.opendaylight.controller.md.sal.dom.store.impl.tree.DataTreeModification; +import org.opendaylight.controller.md.sal.dom.store.impl.tree.DataTreeSnapshot; +import org.opendaylight.controller.sal.core.spi.data.DOMStoreThreePhaseCommitCohort; +import org.opendaylight.controller.sal.core.spi.data.DOMStoreWriteTransaction; +import org.opendaylight.yangtools.yang.data.api.InstanceIdentifier; +import org.opendaylight.yangtools.yang.data.api.schema.NormalizedNode; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import com.google.common.base.Objects.ToStringHelper; +import com.google.common.base.Preconditions; +import com.google.common.base.Throwables; + +/** + * Implementation of Write transaction which is backed by + * {@link DataTreeSnapshot} and executed according to + * {@link TransactionReadyPrototype}. + * + */ +class SnapshotBackedWriteTransaction extends AbstractDOMStoreTransaction implements DOMStoreWriteTransaction { + + private static final Logger LOG = LoggerFactory.getLogger(SnapshotBackedWriteTransaction.class); + private DataTreeModification mutableTree; + private boolean ready = false; + private TransactionReadyPrototype readyImpl; + + /** + * Creates new write-only transaction. + * + * @param identifier + * transaction Identifier + * @param snapshot + * Snapshot which will be modified. + * @param readyImpl + * Implementation of ready method. + */ + public SnapshotBackedWriteTransaction(final Object identifier, final DataTreeSnapshot snapshot, + final TransactionReadyPrototype readyImpl) { + super(identifier); + mutableTree = snapshot.newModification(); + this.readyImpl = Preconditions.checkNotNull(readyImpl, "readyImpl must not be null."); + LOG.debug("Write Tx: {} allocated with snapshot {}", identifier, snapshot); + } + + @Override + public void close() { + LOG.debug("Store transaction: {} : Closed", getIdentifier()); + this.mutableTree = null; + this.readyImpl = null; + } + + @Override + public void write(final InstanceIdentifier path, final NormalizedNode data) { + checkNotReady(); + try { + LOG.debug("Tx: {} Write: {}:{}", getIdentifier(), path, data); + mutableTree.write(path, data); + // FIXME: Add checked exception + } catch (Exception e) { + LOG.error("Tx: {}, failed to write {}:{} in {}", getIdentifier(), path, data, mutableTree, e); + // Rethrow original ones if they are subclasses of RuntimeException + // or Error + Throwables.propagateIfPossible(e); + // FIXME: Introduce proper checked exception + throw new IllegalArgumentException("Illegal input data.", e); + } + } + + @Override + public void merge(final InstanceIdentifier path, final NormalizedNode data) { + checkNotReady(); + try { + LOG.debug("Tx: {} Merge: {}:{}", getIdentifier(), path, data); + mutableTree.merge(path, data); + // FIXME: Add checked exception + } catch (Exception e) { + LOG.error("Tx: {}, failed to write {}:{} in {}", getIdentifier(), path, data, mutableTree, e); + // Rethrow original ones if they are subclasses of RuntimeException + // or Error + Throwables.propagateIfPossible(e); + // FIXME: Introduce proper checked exception + throw new IllegalArgumentException("Illegal input data.", e); + } + } + + @Override + public void delete(final InstanceIdentifier path) { + checkNotReady(); + try { + LOG.debug("Tx: {} Delete: {}", getIdentifier(), path); + mutableTree.delete(path); + // FIXME: Add checked exception + } catch (Exception e) { + LOG.error("Tx: {}, failed to delete {} in {}", getIdentifier(), path, mutableTree, e); + // Rethrow original ones if they are subclasses of RuntimeException + // or Error + Throwables.propagateIfPossible(e); + // FIXME: Introduce proper checked exception + throw new IllegalArgumentException("Illegal path to delete.", e); + } + } + + protected final boolean isReady() { + return ready; + } + + protected final void checkNotReady() { + checkState(!ready, "Transaction %s is ready. No further modifications allowed.", getIdentifier()); + } + + @Override + public synchronized DOMStoreThreePhaseCommitCohort ready() { + checkState(!ready, "Transaction %s is already ready.", getIdentifier()); + ready = true; + LOG.debug("Store transaction: {} : Ready", getIdentifier()); + mutableTree.ready(); + return readyImpl.ready(this); + } + + protected DataTreeModification getMutatedView() { + return mutableTree; + } + + @Override + protected ToStringHelper addToStringAttributes(final ToStringHelper toStringHelper) { + return toStringHelper.add("ready", isReady()); + } + + /** + * Prototype implementation of + * {@link #ready(SnapshotBackedWriteTransaction)} + * + * This class is intended to be implemented by Transaction factories + * responsible for allocation of {@link SnapshotBackedWriteTransaction} and + * providing underlying logic for applying implementation. + * + */ + public static interface TransactionReadyPrototype { + + /** + * Returns a commit coordinator associated with supplied transactions. + * + * This call must not fail. + * + * @param tx + * Transaction on which ready was invoked. + * @return DOMStoreThreePhaseCommitCohort associated with transaction + */ + DOMStoreThreePhaseCommitCohort ready(SnapshotBackedWriteTransaction tx); + } +} \ No newline at end of file diff --git a/opendaylight/md-sal/sal-netconf-connector/src/main/java/org/opendaylight/controller/sal/connect/netconf/sal/NetconfDeviceSalFacade.java b/opendaylight/md-sal/sal-netconf-connector/src/main/java/org/opendaylight/controller/sal/connect/netconf/sal/NetconfDeviceSalFacade.java index f39c4d5792..37b87045d5 100644 --- a/opendaylight/md-sal/sal-netconf-connector/src/main/java/org/opendaylight/controller/sal/connect/netconf/sal/NetconfDeviceSalFacade.java +++ b/opendaylight/md-sal/sal-netconf-connector/src/main/java/org/opendaylight/controller/sal/connect/netconf/sal/NetconfDeviceSalFacade.java @@ -7,11 +7,11 @@ */ package org.opendaylight.controller.sal.connect.netconf.sal; +import com.google.common.collect.Lists; import com.google.common.collect.Maps; import java.util.Collections; import java.util.List; import java.util.Map; - import java.util.concurrent.ExecutorService; import org.opendaylight.controller.sal.binding.api.BindingAwareBroker; import org.opendaylight.controller.sal.connect.api.RemoteDeviceHandler; @@ -29,11 +29,9 @@ import org.osgi.framework.BundleContext; import org.slf4j.Logger; import org.slf4j.LoggerFactory; -import com.google.common.collect.Lists; - public final class NetconfDeviceSalFacade implements AutoCloseable, RemoteDeviceHandler { - private static final Logger logger= LoggerFactory.getLogger(NetconfDeviceTwoPhaseCommitTransaction.class); + private static final Logger logger= LoggerFactory.getLogger(NetconfDeviceSalFacade.class); private static final InstanceIdentifier ROOT_PATH = InstanceIdentifier.builder().toInstance(); private final RemoteDeviceId id; @@ -88,7 +86,11 @@ public final class NetconfDeviceSalFacade implements AutoCloseable, RemoteDevice } if (failedRpcs.isEmpty() == false) { - logger.warn("{}: Some rpcs from netconf device were not registered: {}", id, failedRpcs); + if (logger.isDebugEnabled()) { + logger.warn("{}: Some rpcs from netconf device were not registered: {}", id, failedRpcs); + } else { + logger.warn("{}: Some rpcs from netconf device were not registered: {}", id, failedRpcs.keySet()); + } } } diff --git a/opendaylight/md-sal/sal-rest-connector/src/main/java/org/opendaylight/controller/sal/rest/impl/JsonReader.java b/opendaylight/md-sal/sal-rest-connector/src/main/java/org/opendaylight/controller/sal/rest/impl/JsonReader.java index 593c104dfd..1f7b061e92 100644 --- a/opendaylight/md-sal/sal-rest-connector/src/main/java/org/opendaylight/controller/sal/rest/impl/JsonReader.java +++ b/opendaylight/md-sal/sal-rest-connector/src/main/java/org/opendaylight/controller/sal/rest/impl/JsonReader.java @@ -31,6 +31,12 @@ class JsonReader { JsonParser parser = new JsonParser(); JsonElement rootElement = parser.parse(new InputStreamReader(entityStream)); + if( rootElement.isJsonNull() ) + { + //no content, so return null to indicate no input + return null; + } + if (!rootElement.isJsonObject()) { throw new UnsupportedFormatException("Root element of Json has to be Object"); } diff --git a/opendaylight/md-sal/sal-rest-connector/src/main/java/org/opendaylight/controller/sal/rest/impl/XmlReader.java b/opendaylight/md-sal/sal-rest-connector/src/main/java/org/opendaylight/controller/sal/rest/impl/XmlReader.java index 5b95f0de1a..171805a179 100644 --- a/opendaylight/md-sal/sal-rest-connector/src/main/java/org/opendaylight/controller/sal/rest/impl/XmlReader.java +++ b/opendaylight/md-sal/sal-rest-connector/src/main/java/org/opendaylight/controller/sal/rest/impl/XmlReader.java @@ -9,6 +9,8 @@ package org.opendaylight.controller.sal.rest.impl; import static com.google.common.base.Preconditions.checkArgument; +import java.io.BufferedInputStream; +import java.io.IOException; import java.io.InputStream; import java.net.URI; import java.util.Stack; @@ -32,7 +34,17 @@ public class XmlReader { private final static XMLInputFactory xmlInputFactory = XMLInputFactory.newInstance(); private XMLEventReader eventReader; - public CompositeNodeWrapper read(InputStream entityStream) throws XMLStreamException, UnsupportedFormatException { + public CompositeNodeWrapper read(InputStream entityStream) throws XMLStreamException, + UnsupportedFormatException, + IOException { + //Get an XML stream which can be marked, and reset, so we can check and see if there is + //any content being provided. + entityStream = getMarkableStream(entityStream); + + if( isInputStreamEmpty( entityStream ) ) { + return null; + } + eventReader = xmlInputFactory.createXMLEventReader(entityStream); if (eventReader.hasNext()) { @@ -91,6 +103,31 @@ public class XmlReader { return root; } + /** + * If the input stream is not markable, then it wraps the input stream with a buffered stream, + * which is mark able. That way we can check if the stream is empty safely. + * @param entityStream + * @return + */ + private InputStream getMarkableStream(InputStream entityStream) { + if( !entityStream.markSupported() ) + { + entityStream = new BufferedInputStream( entityStream ); + } + return entityStream; + } + + private boolean isInputStreamEmpty(InputStream entityStream) + throws IOException { + boolean isEmpty = false; + entityStream.mark( 1 ); + if( entityStream.read() == -1 ){ + isEmpty = true; + } + entityStream.reset(); + return isEmpty; + } + private boolean isSimpleNodeEvent(final XMLEvent event) throws XMLStreamException { checkArgument(event != null, "XML Event cannot be NULL!"); if (event.isStartElement()) { diff --git a/opendaylight/md-sal/sal-rest-connector/src/main/java/org/opendaylight/controller/sal/restconf/impl/RestconfImpl.java b/opendaylight/md-sal/sal-rest-connector/src/main/java/org/opendaylight/controller/sal/restconf/impl/RestconfImpl.java index ad682bc829..c0ce90e15d 100644 --- a/opendaylight/md-sal/sal-rest-connector/src/main/java/org/opendaylight/controller/sal/restconf/impl/RestconfImpl.java +++ b/opendaylight/md-sal/sal-rest-connector/src/main/java/org/opendaylight/controller/sal/restconf/impl/RestconfImpl.java @@ -8,13 +8,6 @@ */ package org.opendaylight.controller.sal.restconf.impl; -import com.google.common.base.Objects; -import com.google.common.base.Preconditions; -import com.google.common.base.Splitter; -import com.google.common.base.Strings; -import com.google.common.collect.Iterables; -import com.google.common.collect.Lists; - import java.net.URI; import java.text.ParseException; import java.text.SimpleDateFormat; @@ -38,21 +31,11 @@ import org.opendaylight.controller.md.sal.common.api.TransactionStatus; import org.opendaylight.controller.sal.core.api.mount.MountInstance; import org.opendaylight.controller.sal.rest.api.Draft02; import org.opendaylight.controller.sal.rest.api.RestconfService; +import org.opendaylight.controller.sal.restconf.impl.RestconfError.ErrorTag; +import org.opendaylight.controller.sal.restconf.impl.RestconfError.ErrorType; import org.opendaylight.controller.sal.restconf.rpc.impl.BrokerRpcExecutor; import org.opendaylight.controller.sal.restconf.rpc.impl.MountPointRpcExecutor; import org.opendaylight.controller.sal.restconf.rpc.impl.RpcExecutor; -import org.opendaylight.controller.sal.restconf.impl.BrokerFacade; -import org.opendaylight.controller.sal.restconf.impl.CompositeNodeWrapper; -import org.opendaylight.controller.sal.restconf.impl.ControllerContext; -import org.opendaylight.controller.sal.restconf.impl.EmptyNodeWrapper; -import org.opendaylight.controller.sal.restconf.impl.IdentityValuesDTO; -import org.opendaylight.controller.sal.restconf.impl.InstanceIdWithSchemaNode; -import org.opendaylight.controller.sal.restconf.impl.NodeWrapper; -import org.opendaylight.controller.sal.restconf.impl.RestCodec; -import org.opendaylight.controller.sal.restconf.impl.SimpleNodeWrapper; -import org.opendaylight.controller.sal.restconf.impl.StructuredData; -import org.opendaylight.controller.sal.restconf.impl.RestconfError.ErrorTag; -import org.opendaylight.controller.sal.restconf.impl.RestconfError.ErrorType; import org.opendaylight.controller.sal.streams.listeners.ListenerAdapter; import org.opendaylight.controller.sal.streams.listeners.Notificator; import org.opendaylight.controller.sal.streams.websockets.WebSocketServer; @@ -84,6 +67,13 @@ import org.opendaylight.yangtools.yang.model.util.EmptyType; import org.opendaylight.yangtools.yang.parser.builder.impl.ContainerSchemaNodeBuilder; import org.opendaylight.yangtools.yang.parser.builder.impl.LeafSchemaNodeBuilder; +import com.google.common.base.Objects; +import com.google.common.base.Preconditions; +import com.google.common.base.Splitter; +import com.google.common.base.Strings; +import com.google.common.collect.Iterables; +import com.google.common.collect.Lists; + public class RestconfImpl implements RestconfService { private final static RestconfImpl INSTANCE = new RestconfImpl(); @@ -401,13 +391,36 @@ public class RestconfImpl implements RestconfService { URI rpcNamespace = rpcName.getNamespace(); if (Objects.equal(rpcNamespace.toString(), SAL_REMOTE_NAMESPACE) && Objects.equal(rpcName.getLocalName(), SAL_REMOTE_RPC_SUBSRCIBE)) { - return invokeSalRemoteRpcSubscribeRPC(payload, rpc.getRpcDefinition()); } + validateInput( rpc.getRpcDefinition().getInput(), payload ); + return callRpc(rpc, payload); } + private void validateInput(DataSchemaNode inputSchema, CompositeNode payload) { + if( inputSchema != null && payload == null ) + { + //expected a non null payload + throw new RestconfDocumentedException( "Input is required.", + ErrorType.PROTOCOL, + ErrorTag.MALFORMED_MESSAGE ); + } + else if( inputSchema == null && payload != null ) + { + //did not expect any input + throw new RestconfDocumentedException( "No input expected.", + ErrorType.PROTOCOL, + ErrorTag.MALFORMED_MESSAGE ); + } + //else + //{ + //TODO: Validate "mandatory" and "config" values here??? Or should those be + // validate in a more central location inside MD-SAL core. + //} + } + private StructuredData invokeSalRemoteRpcSubscribeRPC(final CompositeNode payload, final RpcDefinition rpc) { final CompositeNode value = this.normalizeNode(payload, rpc.getInput(), null); @@ -455,8 +468,7 @@ public class RestconfImpl implements RestconfService { throw new RestconfDocumentedException( "Content must be empty.", ErrorType.PROTOCOL, ErrorTag.INVALID_VALUE ); } - final RpcExecutor rpc = resolveIdentifierInInvokeRpc(identifier); - return callRpc(rpc, null); + return invokeRpc( identifier, (CompositeNode)null ); } private RpcExecutor resolveIdentifierInInvokeRpc(final String identifier) { @@ -586,6 +598,9 @@ public class RestconfImpl implements RestconfService { @Override public Response updateConfigurationData(final String identifier, final CompositeNode payload) { final InstanceIdWithSchemaNode iiWithData = this.controllerContext.toInstanceIdentifier(identifier); + + validateInput(iiWithData.getSchemaNode(), payload); + MountInstance mountPoint = iiWithData.getMountPoint(); final CompositeNode value = this.normalizeNode(payload, iiWithData.getSchemaNode(), mountPoint); RpcResult status = null; @@ -610,6 +625,12 @@ public class RestconfImpl implements RestconfService { @Override public Response createConfigurationData(final String identifier, final CompositeNode payload) { + if( payload == null ) { + throw new RestconfDocumentedException( "Input is required.", + ErrorType.PROTOCOL, + ErrorTag.MALFORMED_MESSAGE ); + } + URI payloadNS = this.namespace(payload); if (payloadNS == null) { throw new RestconfDocumentedException( @@ -685,6 +706,12 @@ public class RestconfImpl implements RestconfService { @Override public Response createConfigurationData(final CompositeNode payload) { + if( payload == null ) { + throw new RestconfDocumentedException( "Input is required.", + ErrorType.PROTOCOL, + ErrorTag.MALFORMED_MESSAGE ); + } + URI payloadNS = this.namespace(payload); if (payloadNS == null) { throw new RestconfDocumentedException( diff --git a/opendaylight/md-sal/sal-rest-connector/src/test/java/org/opendaylight/controller/sal/restconf/impl/cnsn/to/json/test/CnSnToJsonBasicDataTypesTest.java b/opendaylight/md-sal/sal-rest-connector/src/test/java/org/opendaylight/controller/sal/restconf/impl/cnsn/to/json/test/CnSnToJsonBasicDataTypesTest.java index 312365585e..4e32e7058c 100644 --- a/opendaylight/md-sal/sal-rest-connector/src/test/java/org/opendaylight/controller/sal/restconf/impl/cnsn/to/json/test/CnSnToJsonBasicDataTypesTest.java +++ b/opendaylight/md-sal/sal-rest-connector/src/test/java/org/opendaylight/controller/sal/restconf/impl/cnsn/to/json/test/CnSnToJsonBasicDataTypesTest.java @@ -11,49 +11,127 @@ import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertNotNull; import static org.junit.Assert.assertNull; -import static org.junit.Assert.assertTrue; +import static org.junit.Assert.fail; import java.io.IOException; import java.io.StringReader; -import java.util.ArrayList; -import java.util.Collections; -import java.util.List; - -import javax.ws.rs.WebApplicationException; +import java.util.Map; import org.junit.BeforeClass; import org.junit.Test; import org.opendaylight.controller.sal.rest.impl.StructuredDataToJsonProvider; import org.opendaylight.controller.sal.rest.impl.XmlToCompositeNodeProvider; +import org.opendaylight.controller.sal.restconf.impl.RestconfDocumentedException; +import org.opendaylight.controller.sal.restconf.impl.RestconfError.ErrorTag; import org.opendaylight.controller.sal.restconf.impl.test.TestUtils; import org.opendaylight.controller.sal.restconf.impl.test.YangAndXmlAndDataSchemaLoader; import org.opendaylight.yangtools.yang.data.api.CompositeNode; +import com.google.common.collect.Maps; import com.google.gson.stream.JsonReader; import com.google.gson.stream.JsonToken; public class CnSnToJsonBasicDataTypesTest extends YangAndXmlAndDataSchemaLoader { + static abstract class LeafVerifier { + + Object expectedValue; + JsonToken expectedToken; + + LeafVerifier( Object expectedValue, JsonToken expectedToken ) { + this.expectedValue = expectedValue; + this.expectedToken = expectedToken; + } + + abstract Object getActualValue( JsonReader reader ) throws IOException; + + void verify( JsonReader reader, String keyName ) throws IOException { + assertEquals( "Json value for key " + keyName, expectedValue, getActualValue( reader ) ); + } + + JsonToken expectedTokenType() { + return expectedToken; + } + } + + static class BooleanVerifier extends LeafVerifier { + + public BooleanVerifier( boolean expected ) { + super( expected, JsonToken.BOOLEAN ); + } + + @Override + Object getActualValue( JsonReader reader ) throws IOException { + return reader.nextBoolean(); + } + } + + static class NumberVerifier extends LeafVerifier { + + public NumberVerifier( Number expected ) { + super( expected, JsonToken.NUMBER ); + } + + @Override + Object getActualValue( JsonReader reader ) throws IOException { + if( expectedValue instanceof Double ) { + return reader.nextDouble(); + } + else if( expectedValue instanceof Long ) { + return reader.nextLong(); + } + else if( expectedValue instanceof Integer ) { + return reader.nextInt(); + } + + return null; + } + } + + static class StringVerifier extends LeafVerifier { + + StringVerifier( String expected ) { + super( expected, JsonToken.STRING ); + } + + @Override + Object getActualValue( JsonReader reader ) throws IOException { + return reader.nextString(); + } + } + + static class EmptyVerifier extends LeafVerifier { + + EmptyVerifier() { + super( null, null ); + } + + @Override + Object getActualValue( JsonReader reader ) throws IOException { + reader.beginArray(); + reader.nextNull(); + reader.endArray(); + return null; + } + + } + @BeforeClass public static void initialize() { dataLoad("/cnsn-to-json/simple-data-types"); } @Test - public void simpleYangDataTest() { + public void simpleYangDataTest() throws Exception { CompositeNode compositeNode = TestUtils.readInputToCnSn("/cnsn-to-json/simple-data-types/xml/data.xml", XmlToCompositeNodeProvider.INSTANCE); - String jsonOutput = null; - TestUtils.normalizeCompositeNode(compositeNode, modules, "simple-data-types:cont"); - try { - jsonOutput = TestUtils.writeCompNodeWithSchemaContextToOutput(compositeNode, modules, dataSchemaNode, + String jsonOutput = TestUtils.writeCompNodeWithSchemaContextToOutput(compositeNode, modules, dataSchemaNode, StructuredDataToJsonProvider.INSTANCE); - } catch (WebApplicationException | IOException e) { - } + assertNotNull(jsonOutput); verifyJsonOutput(jsonOutput); @@ -88,167 +166,84 @@ public class CnSnToJsonBasicDataTypesTest extends YangAndXmlAndDataSchemaLoader private void jsonReadContElements(JsonReader jReader) throws IOException { jReader.beginObject(); - List loadedLfs = new ArrayList<>(); - boolean enumChecked = false; - boolean bitsChecked = false; - boolean lfdecimal6Checked = false; - boolean lfdecimal4Checked = false; - boolean lfdecimal3Checked = false; - boolean lfdecimal2Checked = false; - boolean lfdecimal1Checked = false; - boolean lfbool1Checked = false; - boolean lfbool2Checked = false; - boolean lfstrChecked = false; - boolean lfbinaryChecked = false; - boolean lfemptyChecked = false; - boolean lfstr1Checked = false; - boolean lfidentityrefChecked = false; + + Map expectedMap = Maps.newHashMap(); + expectedMap.put( "lfnint8Min", new NumberVerifier( Integer.valueOf( -128 ) ) ); + expectedMap.put( "lfnint8Max", new NumberVerifier( Integer.valueOf( 127 ) ) ); + expectedMap.put( "lfnint16Min", new NumberVerifier( Integer.valueOf( -32768 ) ) ); + expectedMap.put( "lfnint16Max", new NumberVerifier( Integer.valueOf( 32767 ) ) ); + expectedMap.put( "lfnint32Min", new NumberVerifier( Integer.valueOf( -2147483648 ) ) ); + expectedMap.put( "lfnint32Max", new NumberVerifier( Long.valueOf( 2147483647 ) ) ); + expectedMap.put( "lfnint64Min", new NumberVerifier( Long.valueOf( -9223372036854775808L ) ) ); + expectedMap.put( "lfnint64Max", new NumberVerifier( Long.valueOf( 9223372036854775807L ) ) ); + expectedMap.put( "lfnuint8Max", new NumberVerifier( Integer.valueOf( 255 ) ) ); + expectedMap.put( "lfnuint16Max", new NumberVerifier( Integer.valueOf( 65535 ) ) ); + expectedMap.put( "lfnuint32Max", new NumberVerifier( Long.valueOf( 4294967295L ) ) ); + expectedMap.put( "lfstr", new StringVerifier( "lfstr" ) ); + expectedMap.put( "lfstr1", new StringVerifier( "" ) ); + expectedMap.put( "lfbool1", new BooleanVerifier( true ) ); + expectedMap.put( "lfbool2", new BooleanVerifier( false ) ); + expectedMap.put( "lfbool3", new BooleanVerifier( false ) ); + expectedMap.put( "lfdecimal1", new NumberVerifier( new Double( 43.32 ) ) ); + expectedMap.put( "lfdecimal2", new NumberVerifier( new Double( -0.43 ) ) ); + expectedMap.put( "lfdecimal3", new NumberVerifier( new Double( 43 ) ) ); + expectedMap.put( "lfdecimal4", new NumberVerifier( new Double( 43E3 ) ) ); + expectedMap.put( "lfdecimal6", new NumberVerifier( new Double( 33.12345 ) ) ); + expectedMap.put( "lfenum", new StringVerifier( "enum3" ) ); + expectedMap.put( "lfbits", new StringVerifier( "bit3 bit2" ) ); + expectedMap.put( "lfbinary", new StringVerifier( "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz" ) ); + expectedMap.put( "lfunion1", new StringVerifier( "324" ) ); + expectedMap.put( "lfunion2", new StringVerifier( "33.3" ) ); + expectedMap.put( "lfunion3", new StringVerifier( "55" ) ); + expectedMap.put( "lfunion4", new StringVerifier( "true" ) ); + expectedMap.put( "lfunion5", new StringVerifier( "true" ) ); + expectedMap.put( "lfunion6", new StringVerifier( "10" ) ); + expectedMap.put( "lfunion7", new StringVerifier( "" ) ); + expectedMap.put( "lfunion8", new StringVerifier( "" ) ); + expectedMap.put( "lfunion9", new StringVerifier( "" ) ); + expectedMap.put( "lfunion10", new StringVerifier( "bt1" ) ); + expectedMap.put( "lfunion11", new StringVerifier( "33" ) ); + expectedMap.put( "lfunion12", new StringVerifier( "false" ) ); + expectedMap.put( "lfunion13", new StringVerifier( "b1" ) ); + expectedMap.put( "lfunion14", new StringVerifier( "zero" ) ); + expectedMap.put( "lfempty", new EmptyVerifier() ); + expectedMap.put( "identityref1", new StringVerifier( "simple-data-types:iden" ) ); while (jReader.hasNext()) { String keyName = jReader.nextName(); - JsonToken peek = null; - try { - peek = jReader.peek(); - } catch (IOException e) { - assertTrue("Key " + keyName + " has incorrect value for specifed type", false); - } + JsonToken peek = jReader.peek(); - if (keyName.startsWith("lfnint") || keyName.startsWith("lfnuint")) { - assertEquals("Key " + keyName + " has incorrect type", JsonToken.NUMBER, peek); - try { - jReader.nextLong(); - } catch (NumberFormatException e) { - assertTrue("Key " + keyName + " has incorrect value - " + e.getMessage(), false); - } - loadedLfs.add(keyName.substring(3)); - } else if (keyName.equals("identityref1")) { - assertEquals("Key " + keyName + " has incorrect type", JsonToken.STRING, peek); - assertEquals("simple-data-types:iden", jReader.nextString()); - lfidentityrefChecked = true; - } else if (keyName.equals("lfstr")) { - assertEquals("Key " + keyName + " has incorrect type", JsonToken.STRING, peek); - assertEquals("lfstr", jReader.nextString()); - lfstrChecked = true; - } else if (keyName.equals("lfstr1")) { - assertEquals("Key " + keyName + " has incorrect type", JsonToken.STRING, peek); - assertEquals("", jReader.nextString()); - lfstr1Checked = true; - } else if (keyName.equals("lfbool1")) { - assertEquals("Key " + keyName + " has incorrect type", JsonToken.BOOLEAN, peek); - assertEquals(true, jReader.nextBoolean()); - lfbool1Checked = true; - } else if (keyName.equals("lfbool2")) { - assertEquals("Key " + keyName + " has incorrect type", JsonToken.BOOLEAN, peek); - assertEquals(false, jReader.nextBoolean()); - lfbool2Checked = true; - } else if (keyName.equals("lfbool3")) { - assertEquals("Key " + keyName + " has incorrect type", JsonToken.BOOLEAN, peek); - assertEquals(false, jReader.nextBoolean()); - } else if (keyName.equals("lfdecimal1")) { - assertEquals("Key " + keyName + " has incorrect type", JsonToken.NUMBER, peek); - assertEquals(new Double(43.32), (Double) jReader.nextDouble()); - lfdecimal1Checked = true; - } else if (keyName.equals("lfdecimal2")) { - assertEquals("Key " + keyName + " has incorrect type", JsonToken.NUMBER, peek); - assertEquals(new Double(-0.43), (Double) jReader.nextDouble()); - lfdecimal2Checked = true; - } else if (keyName.equals("lfdecimal3")) { - assertEquals("Key " + keyName + " has incorrect type", JsonToken.NUMBER, peek); - assertEquals(new Double(43), (Double) jReader.nextDouble()); - lfdecimal3Checked = true; - } else if (keyName.equals("lfdecimal4")) { - assertEquals("Key " + keyName + " has incorrect type", JsonToken.NUMBER, peek); - assertEquals(new Double(43E3), (Double) jReader.nextDouble()); - lfdecimal4Checked = true; - } else if (keyName.equals("lfdecimal6")) { - assertEquals("Key " + keyName + " has incorrect type", JsonToken.NUMBER, peek); - assertEquals(new Double(33.12345), (Double) jReader.nextDouble()); - lfdecimal6Checked = true; - } else if (keyName.equals("lfenum")) { - assertEquals("enum3", jReader.nextString()); - enumChecked = true; - } else if (keyName.equals("lfbits")) { - assertEquals("bit3 bit2", jReader.nextString()); - bitsChecked = true; - } else if (keyName.equals("lfbinary")) { - assertEquals("ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz", jReader.nextString()); - lfbinaryChecked = true; - } else if (keyName.equals("lfempty")) { - jReader.beginArray(); - jReader.nextNull(); - jReader.endArray(); - lfemptyChecked = true; - } else if (keyName.startsWith("lfunion")) { - checkLfUnion(jReader, keyName, peek); - } else { - assertTrue("Key " + keyName + " doesn't exists in yang file.", false); + LeafVerifier verifier = expectedMap.remove( keyName ); + assertNotNull( "Found unexpected leaf: " + keyName , verifier ); + + JsonToken expToken = verifier.expectedTokenType(); + if( expToken != null ) { + assertEquals( "Json token type for key " + keyName, expToken, peek ); } + verifier.verify( jReader, keyName );; + } + + if( !expectedMap.isEmpty() ) { + fail( "Missing leaf nodes in Json output: " +expectedMap.keySet() ); } - Collections.sort(loadedLfs); - String expectedLfsStr = "[int16Max, int16Min, int32Max, int32Min, int64Max, int64Min, int8Max, int8Min, uint16Max, uint32Max, uint8Max]"; - String actualLfsStr = loadedLfs.toString(); - assertEquals("Some leaves are missing", expectedLfsStr, actualLfsStr); - assertTrue("Enum wasn't checked", enumChecked); - assertTrue("Bits wasn't checked", bitsChecked); - assertTrue("Decimal1 wasn't checked", lfdecimal1Checked); - assertTrue("Decimal2 wasn't checked", lfdecimal2Checked); - assertTrue("Decimal3 wasn't checked", lfdecimal3Checked); - assertTrue("Decimal4 wasn't checked", lfdecimal4Checked); - assertTrue("Decimal5 wasn't checked", lfdecimal6Checked); - assertTrue("lfbool1 wasn't checked", lfbool1Checked); - assertTrue("lfbool2 wasn't checked", lfbool2Checked); - assertTrue("lfstr wasn't checked", lfstrChecked); - assertTrue("lfstr1 wasn't checked", lfstr1Checked); - assertTrue("lfbinary wasn't checked", lfbinaryChecked); - assertTrue("lfempty wasn't checked", lfemptyChecked); - assertTrue("lfidentityref wasn't checked", lfidentityrefChecked); + jReader.endObject(); } - private void checkLfUnion(JsonReader jReader, String keyName, JsonToken peek) throws IOException { - if (keyName.equals("lfunion1")) { - assertEquals("Key " + keyName + " has incorrect type", JsonToken.STRING, peek); - assertEquals("324", jReader.nextString()); - } else if (keyName.equals("lfunion2")) { - assertEquals("Key " + keyName + " has incorrect type", JsonToken.STRING, peek); - assertEquals("33.3", jReader.nextString()); - } else if (keyName.equals("lfunion3")) { - assertEquals("Key " + keyName + " has incorrect type", JsonToken.STRING, peek); - assertEquals("55", jReader.nextString()); - } else if (keyName.equals("lfunion4")) { - assertEquals("Key " + keyName + " has incorrect type", JsonToken.STRING, peek); - assertEquals("true", jReader.nextString()); - } else if (keyName.equals("lfunion5")) { - assertEquals("Key " + keyName + " has incorrect type", JsonToken.STRING, peek); - assertEquals("true", jReader.nextString()); - } else if (keyName.equals("lfunion6")) { - assertEquals("Key " + keyName + " has incorrect type", JsonToken.STRING, peek); - assertEquals("false", jReader.nextString()); - } else if (keyName.equals("lfunion7")) { - assertEquals("Key " + keyName + " has incorrect type", JsonToken.STRING, peek); - assertEquals("", jReader.nextString()); - } else if (keyName.equals("lfunion8")) { - assertEquals("Key " + keyName + " has incorrect type", JsonToken.STRING, peek); - assertEquals("", jReader.nextString()); - } else if (keyName.equals("lfunion9")) { - assertEquals("Key " + keyName + " has incorrect type", JsonToken.STRING, peek); - assertEquals("", jReader.nextString()); - } else if (keyName.equals("lfunion10")) { - assertEquals("Key " + keyName + " has incorrect type", JsonToken.STRING, peek); - assertEquals("bt1", jReader.nextString()); - } else if (keyName.equals("lfunion11")) { - assertEquals("Key " + keyName + " has incorrect type", JsonToken.STRING, peek); - assertEquals("33", jReader.nextString()); - } else if (keyName.equals("lfunion12")) { - assertEquals("Key " + keyName + " has incorrect type", JsonToken.STRING, peek); - assertEquals("false", jReader.nextString()); - } else if (keyName.equals("lfunion13")) { - assertEquals("Key " + keyName + " has incorrect type", JsonToken.STRING, peek); - assertEquals("44", jReader.nextString()); - } else if (keyName.equals("lfunion14")) { - assertEquals("Key " + keyName + " has incorrect type", JsonToken.STRING, peek); - assertEquals("21", jReader.nextString()); + @Test + public void testBadData() throws Exception { + + try { + CompositeNode compositeNode = TestUtils.readInputToCnSn( + "/cnsn-to-json/simple-data-types/xml/bad-data.xml", + XmlToCompositeNodeProvider.INSTANCE); + + TestUtils.normalizeCompositeNode(compositeNode, modules, "simple-data-types:cont"); + fail( "Expected RestconfDocumentedException" ); + } + catch( RestconfDocumentedException e ) { + assertEquals( "getErrorTag", ErrorTag.INVALID_VALUE, e.getErrors().get( 0 ).getErrorTag() ); } } } diff --git a/opendaylight/md-sal/sal-rest-connector/src/test/java/org/opendaylight/controller/sal/restconf/impl/cnsn/to/xml/test/CnSnToXmlTest.java b/opendaylight/md-sal/sal-rest-connector/src/test/java/org/opendaylight/controller/sal/restconf/impl/cnsn/to/xml/test/CnSnToXmlTest.java index fc54795fcc..155ee9d590 100644 --- a/opendaylight/md-sal/sal-rest-connector/src/test/java/org/opendaylight/controller/sal/restconf/impl/cnsn/to/xml/test/CnSnToXmlTest.java +++ b/opendaylight/md-sal/sal-rest-connector/src/test/java/org/opendaylight/controller/sal/restconf/impl/cnsn/to/xml/test/CnSnToXmlTest.java @@ -11,12 +11,16 @@ import static org.junit.Assert.assertNotNull; import static org.junit.Assert.assertTrue; import java.io.IOException; +import java.util.List; import javax.ws.rs.WebApplicationException; import javax.xml.transform.TransformerFactoryConfigurationError; import org.junit.BeforeClass; import org.junit.Test; + +import static org.mockito.Mockito.*; + import org.opendaylight.controller.sal.rest.impl.StructuredDataToXmlProvider; import org.opendaylight.controller.sal.restconf.impl.test.TestUtils; import org.opendaylight.controller.sal.restconf.impl.test.YangAndXmlAndDataSchemaLoader; @@ -26,6 +30,29 @@ import org.opendaylight.yangtools.yang.data.api.MutableCompositeNode; import org.opendaylight.yangtools.yang.data.api.MutableSimpleNode; import org.opendaylight.yangtools.yang.data.impl.NodeFactory; import org.opendaylight.yangtools.yang.data.impl.codec.TypeDefinitionAwareCodec; +import org.opendaylight.yangtools.yang.model.api.SchemaPath; +import org.opendaylight.yangtools.yang.model.api.TypeDefinition; +import org.opendaylight.yangtools.yang.model.api.type.BitsTypeDefinition; +import org.opendaylight.yangtools.yang.model.api.type.EnumTypeDefinition; +import org.opendaylight.yangtools.yang.model.api.type.EnumTypeDefinition.EnumPair; +import org.opendaylight.yangtools.yang.model.util.BinaryType; +import org.opendaylight.yangtools.yang.model.util.BitsType; +import org.opendaylight.yangtools.yang.model.util.BooleanType; +import org.opendaylight.yangtools.yang.model.util.EmptyType; +import org.opendaylight.yangtools.yang.model.util.EnumerationType; +import org.opendaylight.yangtools.yang.model.util.Int16; +import org.opendaylight.yangtools.yang.model.util.Int32; +import org.opendaylight.yangtools.yang.model.util.Int64; +import org.opendaylight.yangtools.yang.model.util.Int8; +import org.opendaylight.yangtools.yang.model.util.StringType; +import org.opendaylight.yangtools.yang.model.util.Uint16; +import org.opendaylight.yangtools.yang.model.util.Uint32; +import org.opendaylight.yangtools.yang.model.util.Uint64; +import org.opendaylight.yangtools.yang.model.util.Uint8; +import org.opendaylight.yangtools.yang.model.util.UnionType; + +import com.google.common.base.Optional; +import com.google.common.collect.Lists; /** * @@ -65,7 +92,7 @@ public class CnSnToXmlTest extends YangAndXmlAndDataSchemaLoader { @Test public void snAsYangStringToXmlTest() { serializeToXml( - prepareCnStructForYangData(TypeDefinitionAwareCodec.STRING_DEFAULT_CODEC.deserialize("lfStr value"), + prepareCnStructForYangData(TypeDefinitionAwareCodec.from(StringType.getInstance()).deserialize("lfStr value"), "lfStr"), "lfStr value"); } @@ -73,7 +100,7 @@ public class CnSnToXmlTest extends YangAndXmlAndDataSchemaLoader { public void snAsYangInt8ToXmlTest() { String elName = "lfInt8"; serializeToXml( - prepareCnStructForYangData(TypeDefinitionAwareCodec.INT8_DEFAULT_CODEC.deserialize("14"), elName), "<" + prepareCnStructForYangData(TypeDefinitionAwareCodec.from(Int8.getInstance()).deserialize("14"), elName), "<" + elName + ">14"); } @@ -81,7 +108,7 @@ public class CnSnToXmlTest extends YangAndXmlAndDataSchemaLoader { public void snAsYangInt16ToXmlTest() { String elName = "lfInt16"; serializeToXml( - prepareCnStructForYangData(TypeDefinitionAwareCodec.INT16_DEFAULT_CODEC.deserialize("3000"), elName), + prepareCnStructForYangData(TypeDefinitionAwareCodec.from(Int16.getInstance()).deserialize("3000"), elName), "<" + elName + ">3000"); } @@ -89,7 +116,7 @@ public class CnSnToXmlTest extends YangAndXmlAndDataSchemaLoader { public void snAsYangInt32ToXmlTest() { String elName = "lfInt32"; serializeToXml( - prepareCnStructForYangData(TypeDefinitionAwareCodec.INT32_DEFAULT_CODEC.deserialize("201234"), elName), + prepareCnStructForYangData(TypeDefinitionAwareCodec.from(Int32.getInstance()).deserialize("201234"), elName), "<" + elName + ">201234"); } @@ -97,7 +124,7 @@ public class CnSnToXmlTest extends YangAndXmlAndDataSchemaLoader { public void snAsYangInt64ToXmlTest() { String elName = "lfInt64"; serializeToXml( - prepareCnStructForYangData(TypeDefinitionAwareCodec.INT64_DEFAULT_CODEC.deserialize("5123456789"), + prepareCnStructForYangData(TypeDefinitionAwareCodec.from(Int64.getInstance()).deserialize("5123456789"), elName), "<" + elName + ">5123456789"); } @@ -105,7 +132,7 @@ public class CnSnToXmlTest extends YangAndXmlAndDataSchemaLoader { public void snAsYangUint8ToXmlTest() { String elName = "lfUint8"; serializeToXml( - prepareCnStructForYangData(TypeDefinitionAwareCodec.UINT8_DEFAULT_CODEC.deserialize("200"), elName), + prepareCnStructForYangData(TypeDefinitionAwareCodec.from(Uint8.getInstance()).deserialize("200"), elName), "<" + elName + ">200"); } @@ -113,7 +140,7 @@ public class CnSnToXmlTest extends YangAndXmlAndDataSchemaLoader { public void snAsYangUint16ToXmlTest() { String elName = "lfUint16"; serializeToXml( - prepareCnStructForYangData(TypeDefinitionAwareCodec.UINT16_DEFAULT_CODEC.deserialize("4000"), elName), + prepareCnStructForYangData(TypeDefinitionAwareCodec.from(Uint16.getInstance()).deserialize("4000"), elName), "<" + elName + ">4000"); } @@ -121,7 +148,7 @@ public class CnSnToXmlTest extends YangAndXmlAndDataSchemaLoader { public void snAsYangUint32ToXmlTest() { String elName = "lfUint32"; serializeToXml( - prepareCnStructForYangData(TypeDefinitionAwareCodec.UINT32_DEFAULT_CODEC.deserialize("4123456789"), + prepareCnStructForYangData(TypeDefinitionAwareCodec.from(Uint32.getInstance()).deserialize("4123456789"), elName), "<" + elName + ">4123456789"); } @@ -129,7 +156,7 @@ public class CnSnToXmlTest extends YangAndXmlAndDataSchemaLoader { public void snAsYangUint64ToXmlTest() { String elName = "lfUint64"; serializeToXml( - prepareCnStructForYangData(TypeDefinitionAwareCodec.UINT64_DEFAULT_CODEC.deserialize("5123456789"), + prepareCnStructForYangData(TypeDefinitionAwareCodec.from(Uint64.getInstance()).deserialize("5123456789"), elName), "<" + elName + ">5123456789"); } @@ -138,25 +165,40 @@ public class CnSnToXmlTest extends YangAndXmlAndDataSchemaLoader { String elName = "lfBinary"; serializeToXml( prepareCnStructForYangData( - TypeDefinitionAwareCodec.BINARY_DEFAULT_CODEC - .deserialize("ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz01234567"), + TypeDefinitionAwareCodec.from(BinaryType.getInstance()) + .deserialize("ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz01234567"), elName), "<" + elName + ">ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz01234567"); + + elName + ">"); } @Test public void snAsYangBitsToXmlTest() { + BitsTypeDefinition.Bit mockBit1 = mock( BitsTypeDefinition.Bit.class ); + when( mockBit1.getName() ).thenReturn( "one" ); + BitsTypeDefinition.Bit mockBit2 = mock( BitsTypeDefinition.Bit.class ); + when( mockBit2.getName() ).thenReturn( "two" ); + List bitList = Lists.newArrayList( mockBit1, mockBit2 ); + String elName = "lfBits"; serializeToXml( - prepareCnStructForYangData(TypeDefinitionAwareCodec.BITS_DEFAULT_CODEC.deserialize("one two"), elName), + prepareCnStructForYangData(TypeDefinitionAwareCodec.from( + BitsType.create( mock( SchemaPath.class ), bitList ) ) + .deserialize("one two"), elName), "<" + elName + ">one two", "<" + elName + ">two one"); } @Test public void snAsYangEnumerationToXmlTest() { + EnumTypeDefinition.EnumPair mockEnum = mock( EnumTypeDefinition.EnumPair.class ); + when( mockEnum.getName() ).thenReturn( "enum2" ); + List enumList = Lists.newArrayList( mockEnum ); + String elName = "lfEnumeration"; serializeToXml( - prepareCnStructForYangData(TypeDefinitionAwareCodec.ENUMERATION_DEFAULT_CODEC.deserialize("enum2"), + prepareCnStructForYangData(TypeDefinitionAwareCodec.from( + EnumerationType.create( mock( SchemaPath.class ), enumList, + Optional.absent() ) ) + .deserialize("enum2"), elName), "<" + elName + ">enum2"); } @@ -164,7 +206,7 @@ public class CnSnToXmlTest extends YangAndXmlAndDataSchemaLoader { public void snAsYangEmptyToXmlTest() { String elName = "lfEmpty"; serializeToXml( - prepareCnStructForYangData(TypeDefinitionAwareCodec.EMPTY_DEFAULT_CODEC.deserialize(null), elName), "<" + prepareCnStructForYangData(TypeDefinitionAwareCodec.from(EmptyType.getInstance()).deserialize(null), elName), "<" + elName + "/>"); } @@ -172,33 +214,46 @@ public class CnSnToXmlTest extends YangAndXmlAndDataSchemaLoader { public void snAsYangBooleanToXmlTest() { String elName = "lfBoolean"; serializeToXml( - prepareCnStructForYangData(TypeDefinitionAwareCodec.BOOLEAN_DEFAULT_CODEC.deserialize("str"), elName), + prepareCnStructForYangData(TypeDefinitionAwareCodec.from(BooleanType.getInstance()).deserialize("str"), elName), "<" + elName + ">false"); serializeToXml( - prepareCnStructForYangData(TypeDefinitionAwareCodec.BOOLEAN_DEFAULT_CODEC.deserialize("true"), elName), + prepareCnStructForYangData(TypeDefinitionAwareCodec.from(BooleanType.getInstance()).deserialize("true"), elName), "<" + elName + ">true"); } @Test public void snAsYangUnionToXmlTest() { + + BitsTypeDefinition.Bit mockBit1 = mock( BitsTypeDefinition.Bit.class ); + when( mockBit1.getName() ).thenReturn( "first" ); + BitsTypeDefinition.Bit mockBit2 = mock( BitsTypeDefinition.Bit.class ); + when( mockBit1.getName() ).thenReturn( "second" ); + List bitList = Lists.newArrayList( mockBit1, mockBit2 ); + + List> types = Lists.>newArrayList( + Int8.getInstance(), + BitsType.create( mock( SchemaPath.class ) , bitList ), + BooleanType.getInstance() ); + UnionType unionType = UnionType.create( types ); + String elName = "lfUnion"; String int8 = "15"; serializeToXml( - prepareCnStructForYangData(TypeDefinitionAwareCodec.UNION_DEFAULT_CODEC.deserialize(int8), elName), "<" + prepareCnStructForYangData(TypeDefinitionAwareCodec.from(unionType).deserialize(int8), elName), "<" + elName + ">15"); String bits = "first second"; serializeToXml( - prepareCnStructForYangData(TypeDefinitionAwareCodec.UNION_DEFAULT_CODEC.deserialize(bits), elName), "<" + prepareCnStructForYangData(TypeDefinitionAwareCodec.from(unionType).deserialize(bits), elName), "<" + elName + ">first second"); String bool = "str"; serializeToXml( - prepareCnStructForYangData(TypeDefinitionAwareCodec.UNION_DEFAULT_CODEC.deserialize(bool), elName), "<" + prepareCnStructForYangData(TypeDefinitionAwareCodec.from(unionType).deserialize(bool), elName), "<" + elName + ">str"); } - private void serializeToXml(final CompositeNode compositeNode, final String... xmlRepresentation) + private void serializeToXml(CompositeNode compositeNode, String... xmlRepresentation) throws TransformerFactoryConfigurationError { String xmlString = ""; try { @@ -220,7 +275,7 @@ public class CnSnToXmlTest extends YangAndXmlAndDataSchemaLoader { } - private CompositeNode prepareIdentityrefData(final String prefix, final boolean valueAsQName) { + private CompositeNode prepareIdentityrefData(String prefix, boolean valueAsQName) { MutableCompositeNode cont = NodeFactory.createMutableCompositeNode( TestUtils.buildQName("cont", "basic:module", "2013-12-2"), null, null, ModifyAction.CREATE, null); MutableCompositeNode cont1 = NodeFactory.createMutableCompositeNode( diff --git a/opendaylight/md-sal/sal-rest-connector/src/test/java/org/opendaylight/controller/sal/restconf/impl/json/to/cnsn/test/JsonToCnSnTest.java b/opendaylight/md-sal/sal-rest-connector/src/test/java/org/opendaylight/controller/sal/restconf/impl/json/to/cnsn/test/JsonToCnSnTest.java index 3c70cca0f8..47e329cc3e 100644 --- a/opendaylight/md-sal/sal-rest-connector/src/test/java/org/opendaylight/controller/sal/restconf/impl/json/to/cnsn/test/JsonToCnSnTest.java +++ b/opendaylight/md-sal/sal-rest-connector/src/test/java/org/opendaylight/controller/sal/restconf/impl/json/to/cnsn/test/JsonToCnSnTest.java @@ -9,8 +9,11 @@ package org.opendaylight.controller.sal.restconf.impl.json.to.cnsn.test; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertNotNull; +import static org.junit.Assert.assertNull; import static org.junit.Assert.assertTrue; +import java.io.ByteArrayInputStream; +import java.io.InputStream; import java.util.HashSet; import java.util.List; import java.util.Set; @@ -176,6 +179,14 @@ public class JsonToCnSnTest { } + @Test + public void testJsonBlankInput() throws Exception{ + InputStream inputStream = new ByteArrayInputStream( "".getBytes() ); + CompositeNode compositeNode = + JsonToCompositeNodeProvider.INSTANCE.readFrom(null, null, null, null, null, inputStream); + assertNull( compositeNode ); + } + /** * Tests whether namespace stay unchanged if concrete values are * present in composite or simple node and if the method for update is diff --git a/opendaylight/md-sal/sal-rest-connector/src/test/java/org/opendaylight/controller/sal/restconf/impl/test/CodecsExceptionsCatchingTest.java b/opendaylight/md-sal/sal-rest-connector/src/test/java/org/opendaylight/controller/sal/restconf/impl/test/CodecsExceptionsCatchingTest.java index 51687e2a12..307abebdd7 100644 --- a/opendaylight/md-sal/sal-rest-connector/src/test/java/org/opendaylight/controller/sal/restconf/impl/test/CodecsExceptionsCatchingTest.java +++ b/opendaylight/md-sal/sal-rest-connector/src/test/java/org/opendaylight/controller/sal/restconf/impl/test/CodecsExceptionsCatchingTest.java @@ -56,6 +56,6 @@ public class CodecsExceptionsCatchingTest extends JerseyTest { Response response = target("/config/number:cont").request(MediaType.APPLICATION_XML).put( Entity.entity("3f", MediaType.APPLICATION_XML)); String exceptionMessage = response.readEntity(String.class); - assertTrue(exceptionMessage.contains("Incorrect lexical representation of Integer value: 3f")); + assertTrue(exceptionMessage.contains("invalid-value")); } } \ No newline at end of file diff --git a/opendaylight/md-sal/sal-rest-connector/src/test/java/org/opendaylight/controller/sal/restconf/impl/test/InvokeRpcMethodTest.java b/opendaylight/md-sal/sal-rest-connector/src/test/java/org/opendaylight/controller/sal/restconf/impl/test/InvokeRpcMethodTest.java index c0c86c3f25..910ca8e20a 100644 --- a/opendaylight/md-sal/sal-rest-connector/src/test/java/org/opendaylight/controller/sal/restconf/impl/test/InvokeRpcMethodTest.java +++ b/opendaylight/md-sal/sal-rest-connector/src/test/java/org/opendaylight/controller/sal/restconf/impl/test/InvokeRpcMethodTest.java @@ -308,7 +308,7 @@ public class InvokeRpcMethodTest { ListenableFuture> mockListener = mock( ListenableFuture.class ); when( mockListener.get() ).thenReturn( rpcResult ); - QName cancelToastQName = QName.create( "cancelToast" ); + QName cancelToastQName = QName.create( "namespace", "2014-05-28", "cancelToast" ); RpcDefinition mockRpc = mock( RpcDefinition.class ); when( mockRpc.getQName() ).thenReturn( cancelToastQName ); diff --git a/opendaylight/md-sal/sal-rest-connector/src/test/java/org/opendaylight/controller/sal/restconf/impl/test/RestPostOperationTest.java b/opendaylight/md-sal/sal-rest-connector/src/test/java/org/opendaylight/controller/sal/restconf/impl/test/RestPostOperationTest.java index ce460fe474..cfbc9fdb76 100644 --- a/opendaylight/md-sal/sal-rest-connector/src/test/java/org/opendaylight/controller/sal/restconf/impl/test/RestPostOperationTest.java +++ b/opendaylight/md-sal/sal-rest-connector/src/test/java/org/opendaylight/controller/sal/restconf/impl/test/RestPostOperationTest.java @@ -149,6 +149,8 @@ public class RestPostOperationTest extends JerseyTest { mockCommitConfigurationDataPostMethod(TransactionStatus.FAILED); assertEquals(500, post(uri, MediaType.APPLICATION_XML, xmlDataInterfaceAbsolutePath)); + + assertEquals( 400, post(uri, MediaType.APPLICATION_JSON, "" )); } @Test @@ -172,6 +174,8 @@ public class RestPostOperationTest extends JerseyTest { assertEquals(204, post(uri, Draft02.MediaTypes.DATA + XML, xmlData4)); uri = "/config/ietf-interfaces:interfaces/interface/0/yang-ext:mount/test-module:cont"; assertEquals(204, post(uri, Draft02.MediaTypes.DATA + XML, xmlData3)); + + assertEquals( 400, post(uri, MediaType.APPLICATION_JSON, "" )); } private void mockInvokeRpc(CompositeNode result, boolean sucessful) { diff --git a/opendaylight/md-sal/sal-rest-connector/src/test/java/org/opendaylight/controller/sal/restconf/impl/test/RestPutOperationTest.java b/opendaylight/md-sal/sal-rest-connector/src/test/java/org/opendaylight/controller/sal/restconf/impl/test/RestPutOperationTest.java index 3af2945526..77b39b7352 100644 --- a/opendaylight/md-sal/sal-rest-connector/src/test/java/org/opendaylight/controller/sal/restconf/impl/test/RestPutOperationTest.java +++ b/opendaylight/md-sal/sal-rest-connector/src/test/java/org/opendaylight/controller/sal/restconf/impl/test/RestPutOperationTest.java @@ -22,6 +22,7 @@ import java.util.concurrent.Future; import javax.ws.rs.client.Entity; import javax.ws.rs.core.Application; import javax.ws.rs.core.MediaType; +import javax.ws.rs.core.Response; import org.glassfish.jersey.server.ResourceConfig; import org.glassfish.jersey.test.JerseyTest; @@ -31,6 +32,7 @@ import org.opendaylight.controller.md.sal.common.api.TransactionStatus; import org.opendaylight.controller.sal.core.api.mount.MountInstance; import org.opendaylight.controller.sal.core.api.mount.MountService; import org.opendaylight.controller.sal.rest.impl.JsonToCompositeNodeProvider; +import org.opendaylight.controller.sal.rest.impl.RestconfDocumentedExceptionMapper; import org.opendaylight.controller.sal.rest.impl.StructuredDataToJsonProvider; import org.opendaylight.controller.sal.rest.impl.StructuredDataToXmlProvider; import org.opendaylight.controller.sal.rest.impl.XmlToCompositeNodeProvider; @@ -86,6 +88,7 @@ public class RestPutOperationTest extends JerseyTest { resourceConfig = resourceConfig.registerInstances(restconfImpl, StructuredDataToXmlProvider.INSTANCE, StructuredDataToJsonProvider.INSTANCE, XmlToCompositeNodeProvider.INSTANCE, JsonToCompositeNodeProvider.INSTANCE); + resourceConfig.registerClasses( RestconfDocumentedExceptionMapper.class ); return resourceConfig; } @@ -100,6 +103,15 @@ public class RestPutOperationTest extends JerseyTest { mockCommitConfigurationDataPutMethod(TransactionStatus.FAILED); assertEquals(500, put(uri, MediaType.APPLICATION_XML, xmlData)); + + assertEquals( 400, put(uri, MediaType.APPLICATION_JSON, "" )); + } + + @Test + public void putConfigStatusCodesEmptyBody() throws UnsupportedEncodingException { + String uri = "/config/ietf-interfaces:interfaces/interface/eth0"; + Response resp = target(uri).request( MediaType.APPLICATION_JSON).put(Entity.entity( "", MediaType.APPLICATION_JSON)); + assertEquals( 400, put(uri, MediaType.APPLICATION_JSON, "" )); } @Test diff --git a/opendaylight/md-sal/sal-rest-connector/src/test/java/org/opendaylight/controller/sal/restconf/impl/xml/to/cnsn/test/XmlToCnSnTest.java b/opendaylight/md-sal/sal-rest-connector/src/test/java/org/opendaylight/controller/sal/restconf/impl/xml/to/cnsn/test/XmlToCnSnTest.java index 5008d28bbf..5cda4a7f52 100644 --- a/opendaylight/md-sal/sal-rest-connector/src/test/java/org/opendaylight/controller/sal/restconf/impl/xml/to/cnsn/test/XmlToCnSnTest.java +++ b/opendaylight/md-sal/sal-rest-connector/src/test/java/org/opendaylight/controller/sal/restconf/impl/xml/to/cnsn/test/XmlToCnSnTest.java @@ -9,8 +9,12 @@ package org.opendaylight.controller.sal.restconf.impl.xml.to.cnsn.test; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertNotNull; +import static org.junit.Assert.assertNull; import static org.junit.Assert.assertTrue; +import java.io.ByteArrayInputStream; +import java.io.InputStream; + import org.junit.BeforeClass; import org.junit.Test; import org.opendaylight.controller.sal.rest.impl.XmlToCompositeNodeProvider; @@ -52,4 +56,27 @@ public class XmlToCnSnTest extends YangAndXmlAndDataSchemaLoader { assertEquals("121", lf2.getValue()); } + @Test + public void testXmlBlankInput() throws Exception{ + InputStream inputStream = new ByteArrayInputStream( "".getBytes() ); + CompositeNode compositeNode = + XmlToCompositeNodeProvider.INSTANCE.readFrom(null, null, null, null, null, inputStream); + + assertNull( compositeNode ); + } + + @Test + public void testXmlBlankInputUnmarkableStream() throws Exception{ + InputStream inputStream = new ByteArrayInputStream( "".getBytes() ){ + @Override + public boolean markSupported() { + return false; + } + }; + CompositeNode compositeNode = + XmlToCompositeNodeProvider.INSTANCE.readFrom(null, null, null, null, null, inputStream); + + assertNull( compositeNode ); + } + } diff --git a/opendaylight/md-sal/sal-rest-connector/src/test/resources/cnsn-to-json/simple-data-types/xml/bad-data.xml b/opendaylight/md-sal/sal-rest-connector/src/test/resources/cnsn-to-json/simple-data-types/xml/bad-data.xml new file mode 100644 index 0000000000..110c3237de --- /dev/null +++ b/opendaylight/md-sal/sal-rest-connector/src/test/resources/cnsn-to-json/simple-data-types/xml/bad-data.xml @@ -0,0 +1,3 @@ + + invalid + \ No newline at end of file diff --git a/opendaylight/md-sal/sal-rest-connector/src/test/resources/cnsn-to-json/simple-data-types/xml/data.xml b/opendaylight/md-sal/sal-rest-connector/src/test/resources/cnsn-to-json/simple-data-types/xml/data.xml index 56872a337d..f73ce1b65c 100644 --- a/opendaylight/md-sal/sal-rest-connector/src/test/resources/cnsn-to-json/simple-data-types/xml/data.xml +++ b/opendaylight/md-sal/sal-rest-connector/src/test/resources/cnsn-to-json/simple-data-types/xml/data.xml @@ -29,15 +29,14 @@ 55 true true - false + 10 bt1 33 false - 44 - 21 - + b1 + zero x:iden \ No newline at end of file diff --git a/opendaylight/md-sal/statistics-manager/src/main/java/org/opendaylight/controller/md/statistics/manager/NodeStatisticsHandler.java b/opendaylight/md-sal/statistics-manager/src/main/java/org/opendaylight/controller/md/statistics/manager/NodeStatisticsHandler.java index dbcbab982a..7d9cc7ecbd 100644 --- a/opendaylight/md-sal/statistics-manager/src/main/java/org/opendaylight/controller/md/statistics/manager/NodeStatisticsHandler.java +++ b/opendaylight/md-sal/statistics-manager/src/main/java/org/opendaylight/controller/md/statistics/manager/NodeStatisticsHandler.java @@ -313,6 +313,9 @@ public final class NodeStatisticsHandler implements AutoCloseable, FlowCapableCo meterStats.close(); queueStats.close(); + //Clean up queued statistics request from scheduler queue + srScheduler.removeRequestsFromSchedulerQueue(this.getNodeRef()); + logger.debug("Statistics handler for {} shut down", targetNodeKey.getId()); } diff --git a/opendaylight/md-sal/statistics-manager/src/main/java/org/opendaylight/controller/md/statistics/manager/StatisticsRequestScheduler.java b/opendaylight/md-sal/statistics-manager/src/main/java/org/opendaylight/controller/md/statistics/manager/StatisticsRequestScheduler.java index 9ebfd6fd62..bea43ef68a 100644 --- a/opendaylight/md-sal/statistics-manager/src/main/java/org/opendaylight/controller/md/statistics/manager/StatisticsRequestScheduler.java +++ b/opendaylight/md-sal/statistics-manager/src/main/java/org/opendaylight/controller/md/statistics/manager/StatisticsRequestScheduler.java @@ -18,6 +18,7 @@ import java.util.concurrent.TimeUnit; import org.opendaylight.controller.md.sal.common.api.TransactionStatus; import org.opendaylight.controller.sal.binding.api.data.DataModificationTransaction; import org.opendaylight.controller.sal.binding.api.data.DataModificationTransaction.DataTransactionListener; +import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.NodeRef; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -62,6 +63,19 @@ public class StatisticsRequestScheduler implements DataTransactionListener { requestQueue.put(statsRequest, null); } + public void removeRequestsFromSchedulerQueue(NodeRef node){ + AbstractStatsTracker stats = null; + synchronized(requestQueue){ + Iterator> nodesItr = requestQueue.entrySet().iterator(); + while(nodesItr.hasNext()){ + stats = nodesItr.next().getKey(); + if(stats.getNodeRef().equals(node)){ + nodesItr.remove(); + } + } + } + + } public AbstractStatsTracker getNextRequestFromSchedulerQueue(){ //Remove first element AbstractStatsTracker stats = null; @@ -79,10 +93,7 @@ public class StatisticsRequestScheduler implements DataTransactionListener { private void requestStatistics(){ AbstractStatsTracker stats = this.getNextRequestFromSchedulerQueue(); - if(stats != null) { - stats.request(); - stats.increaseRequestCounter(); - } + sendStatsRequest(stats); } @Override public void onStatusUpdated(DataModificationTransaction transaction, TransactionStatus status) { @@ -106,12 +117,19 @@ public class StatisticsRequestScheduler implements DataTransactionListener { break; } } + sendStatsRequest(stats); + } + + private void sendStatsRequest(AbstractStatsTracker stats){ if(stats != null){ - stats.request(); - stats.increaseRequestCounter(); + try{ + stats.request(); + stats.increaseRequestCounter(); + }catch(Exception e){ + srsLogger.warn("Statistics request was not sent successfully. Reason : {}",e.getMessage()); + } } } - public void start(){ timer.schedule(task, 0, REQUEST_MONITOR_INTERVAL); } diff --git a/opendaylight/netconf/config-netconf-connector/src/test/java/org/opendaylight/controller/netconf/confignetconfconnector/operations/editconfig/ReplaceEditConfigStrategyTest.java b/opendaylight/netconf/config-netconf-connector/src/test/java/org/opendaylight/controller/netconf/confignetconfconnector/operations/editconfig/ReplaceEditConfigStrategyTest.java index 78a2043e20..22a3f10547 100644 --- a/opendaylight/netconf/config-netconf-connector/src/test/java/org/opendaylight/controller/netconf/confignetconfconnector/operations/editconfig/ReplaceEditConfigStrategyTest.java +++ b/opendaylight/netconf/config-netconf-connector/src/test/java/org/opendaylight/controller/netconf/confignetconfconnector/operations/editconfig/ReplaceEditConfigStrategyTest.java @@ -8,7 +8,17 @@ package org.opendaylight.controller.netconf.confignetconfconnector.operations.editconfig; +import static org.mockito.Matchers.any; +import static org.mockito.Matchers.anyString; +import static org.mockito.Mockito.doNothing; +import static org.mockito.Mockito.doReturn; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.verify; + import com.google.common.collect.Sets; +import java.util.Map; +import javax.management.Attribute; +import javax.management.ObjectName; import org.junit.Before; import org.junit.Test; import org.mockito.Mock; @@ -16,17 +26,6 @@ import org.mockito.MockitoAnnotations; import org.opendaylight.controller.config.util.ConfigTransactionClient; import org.opendaylight.controller.netconf.confignetconfconnector.mapping.attributes.fromxml.AttributeConfigElement; -import javax.management.Attribute; -import javax.management.ObjectName; -import java.util.Map; - -import static org.mockito.Matchers.any; -import static org.mockito.Matchers.anyString; -import static org.mockito.Mockito.doNothing; -import static org.mockito.Mockito.doReturn; -import static org.mockito.Mockito.mock; -import static org.mockito.Mockito.verify; - public class ReplaceEditConfigStrategyTest { @Mock @@ -35,7 +34,7 @@ public class ReplaceEditConfigStrategyTest { @Before public void setUp() throws Exception { MockitoAnnotations.initMocks(this); - doNothing().when(ta).destroyConfigBean(anyString(), anyString()); + doNothing().when(ta).destroyModule(anyString(), anyString()); doReturn(mockON()).when(ta).lookupConfigBean(anyString(), anyString()); doNothing().when(ta).setAttribute(any(ObjectName.class), anyString(), any(Attribute.class)); } diff --git a/opendaylight/sal/api/src/main/java/org/opendaylight/controller/sal/packet/TCP.java b/opendaylight/sal/api/src/main/java/org/opendaylight/controller/sal/packet/TCP.java index 4b2badd92d..8253ac46d3 100644 --- a/opendaylight/sal/api/src/main/java/org/opendaylight/controller/sal/packet/TCP.java +++ b/opendaylight/sal/api/src/main/java/org/opendaylight/controller/sal/packet/TCP.java @@ -230,4 +230,12 @@ public class TCP extends Packet { return (BitBufferHelper.getShort(fieldValues.get(DESTPORT))); } + /** + * Get the stored checksum value of the TCP header + * @return short - the checksum + */ + public short getChecksum() { + return (BitBufferHelper.getShort(fieldValues.get(CHECKSUM))); + } + } diff --git a/opendaylight/sal/api/src/test/java/org/opendaylight/controller/sal/packet/TCPTest.java b/opendaylight/sal/api/src/test/java/org/opendaylight/controller/sal/packet/TCPTest.java index 48679c33f2..3e18aedfdb 100644 --- a/opendaylight/sal/api/src/test/java/org/opendaylight/controller/sal/packet/TCPTest.java +++ b/opendaylight/sal/api/src/test/java/org/opendaylight/controller/sal/packet/TCPTest.java @@ -104,4 +104,13 @@ public class TCPTest { Assert.assertTrue(urgentPointer[1] == 10); } + + @Test + public void testGetChecksum() { + TCP tcp = new TCP(); + byte[] udpChecksum = { 0, -56 }; + tcp.hdrFieldsMap.put("Checksum", udpChecksum); + short checksum = tcp.getChecksum(); + Assert.assertTrue(checksum == 200); + } }