From: Ed Warnicke Date: Mon, 16 Dec 2013 15:52:41 +0000 (+0000) Subject: Merge "Fixed netconf monitoring." X-Git-Tag: jenkins-controller-bulk-release-prepare-only-2-1~187 X-Git-Url: https://git.opendaylight.org/gerrit/gitweb?p=controller.git;a=commitdiff_plain;h=d1ab4c3ea79bcd74e02aa9334bc660cb7fc6d037;hp=58e0b181f70b2e8bf1c8097bb804f6d1f28b00b8 Merge "Fixed netconf monitoring." --- diff --git a/opendaylight/commons/controller-maven-plugin/pom.xml b/opendaylight/commons/controller-maven-plugin/pom.xml deleted file mode 100644 index 1ab4e7067b..0000000000 --- a/opendaylight/commons/controller-maven-plugin/pom.xml +++ /dev/null @@ -1,83 +0,0 @@ - - 4.0.0 - - - org.opendaylight.controller - commons.opendaylight - 1.4.1-SNAPSHOT - ../../commons/opendaylight - - - controller-maven-plugin - 0.1.0-SNAPSHOT - maven-plugin - - controller-maven-plugin - Maven Plugin for controlling the launch of the controller. - http://maven.apache.org - - - UTF-8 - - - - - - org.apache.maven - maven-plugin-api - 2.0 - - - - org.apache.maven.plugin-tools - maven-plugin-annotations - 3.2 - provided - - - - com.sun - tools - system - 7 - ${java.home}/../lib/tools.jar - - - junit - junit - 4.8.1 - test - - - - - - - - org.apache.maven.plugins - maven-plugin-plugin - 3.2 - - controller-maven-plugin - true - - - - mojo-descriptor - - descriptor - - - - help-goal - - helpmojo - - - - - - - - diff --git a/opendaylight/commons/controller-maven-plugin/src/main/java/org/opendaylight/controller/maven/plugin/AbstractControllerMojo.java b/opendaylight/commons/controller-maven-plugin/src/main/java/org/opendaylight/controller/maven/plugin/AbstractControllerMojo.java deleted file mode 100644 index 39ca71c62c..0000000000 --- a/opendaylight/commons/controller-maven-plugin/src/main/java/org/opendaylight/controller/maven/plugin/AbstractControllerMojo.java +++ /dev/null @@ -1,228 +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.maven.plugin; - -import java.io.File; -import java.io.IOException; -import java.net.HttpURLConnection; -import java.net.MalformedURLException; -import java.net.URL; -import java.util.ArrayList; -import java.util.Enumeration; -import java.util.List; -import java.util.Map; -import java.util.Properties; - -import org.apache.maven.plugin.AbstractMojo; -import org.apache.maven.plugin.MojoExecutionException; -import org.apache.maven.plugin.MojoFailureException; -import org.apache.maven.plugins.annotations.Parameter; - -import org.opendaylight.controller.maven.plugin.util.JavaProcess; -import org.opendaylight.controller.maven.plugin.util.ProcessMonitor; - -/** - * Base controller mojo which handles common operations - */ -public abstract class AbstractControllerMojo extends AbstractMojo { - public static final String OS_NAME = System.getProperty("os.name"); - public static final boolean WIN = OS_NAME.toUpperCase().contains("WINDOWS"); - public static final String JAVA_HOME = "JAVA_HOME"; - public static final boolean skip = Boolean.getBoolean("controller.startup.skip"); - public static final String MAIN_CLASS = "org.eclipse.equinox.launcher.Main"; - public static final String CTRL_PROP = "opendaylight.controller"; - - /** - * The home directory where controller is installed - */ - @Parameter( required = false ) - protected File controllerHome; - - /** - * The address on which controller is listening - */ - @Parameter( defaultValue = "localhost") - protected String controllerHost; - - /** - * The admin web port - */ - @Parameter( defaultValue = "8080") - protected int controllerWebPort; - - /** - * The openflow port - */ - @Parameter( defaultValue = "6633") - protected int controllerOFPort; - - /** - * Additional environment variables passed when starting the controller - * process. - */ - @Parameter(required = false) - protected Properties controllerShellVariables; - - /** - * The script name to invoke - */ - @Parameter(required = false) - protected String controllerStartScriptName; - - /** - * The username - */ - @Parameter(required = false) - protected String controllerUsername; - - /** - * The password - */ - @Parameter(required = false) - protected String controllerPassword; - - /** - * pidFile location - */ - @Parameter(required = false) - protected File pidFile; - - protected final ProcessMonitor procMon = ProcessMonitor.load(); - - public abstract void start() throws MojoExecutionException, MojoFailureException; - - public void execute() throws MojoExecutionException, MojoFailureException { - if (skip) return; - validateArgs(); - start(); - } - - protected URL getWebUrl() { - try { - return new URL("http", controllerHost, controllerWebPort, "/"); - } catch (MalformedURLException e) { - throw new IllegalArgumentException( - "controller host:port is Malformed: " + controllerHost + " " + controllerWebPort, e); - } - - } - - protected void validateArgs() throws IllegalArgumentException { - // System property and environment variable override the default setting - String odlHome = System.getProperty("controllerHome"); - if (odlHome != null) { - controllerHome = new File(odlHome); - } - if (controllerHome == null) { - getLog().error("controllerHome cannot be determined from controllerHome " - + "property or ONE_HOME env variable"); - throw new IllegalArgumentException("controllerHome cannot be determined."); - } - if (!controllerHome.exists()) { - throw new IllegalArgumentException( - "controllerHome does not exist: " + controllerHome); - } - if (controllerUsername == null) { - controllerUsername = System.getProperty("controllerUsername"); - } - if (controllerPassword == null) { - controllerPassword= System.getProperty("controllerPassword"); - } - URL u = getWebUrl(); - getLog().info("Controller Home : " + controllerHome); - getLog().info("Controller Url : " + u); - getLog().info("Controller credentials: " + controllerUsername - + "/" + controllerPassword); - } - - protected Process invokeScript(List args, String log) - throws MojoFailureException, MojoExecutionException - { - ProcessBuilder pb = new ProcessBuilder(); - List cmd = new ArrayList(); - cmd.add(getScript()); - if (args != null) { - for (String s : args) { - // on windows args containing equals symbols need to be quoted - if (WIN && s.contains("=") && !s.startsWith("\"")) { - cmd.add("\"" + s + "\""); - } else { - cmd.add(s); - } - } - } - pb.command(cmd); - pb.directory(controllerHome); - pb.redirectErrorStream(true); - pb.inheritIO(); - Map env = pb.environment(); - if (controllerShellVariables != null) { - for (Enumeration e = controllerShellVariables.propertyNames(); e.hasMoreElements();) { - String n = (String) e.nextElement(); - env.put(n, controllerShellVariables.getProperty(n)); - } - } - String jh = env.get(JAVA_HOME); - if (jh == null) env.put(JAVA_HOME, System.getProperty("java.home")); - try { - getLog().info("Invoking process " + pb.command()); - return pb.start(); - } catch (IOException e) { - throw new MojoExecutionException(e.getMessage()); - } - } - - private String getScript() throws MojoFailureException { - File script = null; - if (controllerStartScriptName != null && !"".equals(controllerStartScriptName) ) { - script = new File(controllerStartScriptName); - if (!script.exists()) { - // try relative path - script = new File(controllerHome, controllerStartScriptName); - } - if (script.exists()) return script.getAbsolutePath(); - throw new MojoFailureException("Script not found: " + controllerStartScriptName); - } - // try default - script = new File(controllerHome, "run." + (WIN ? "bat" : "sh") ); - if (script.exists()) return script.getAbsolutePath(); - throw new MojoFailureException("Cannot find a default script to launch."); - } - - protected boolean canConnect() { - try { - URL url = getWebUrl(); - HttpURLConnection con; - con = (HttpURLConnection) url.openConnection(); - return (con.getResponseCode() > 0); - } catch (IOException e) { - return false; - } - } - - public void killControllers() { - getLog().info("Checking environment for stray processes."); - List jvms = procMon.getProcesses(MAIN_CLASS, CTRL_PROP); - for (JavaProcess j : jvms) { - getLog().info("Killing running process: " + j); - ProcessMonitor.kill(j.getPid()); - } - // cleanup pid files - getLog().info("Checking left over pid file: " + pidFile); - if (pidFile != null && pidFile.exists()) { - getLog().info("Cleaning up pid file : " + pidFile); - pidFile.delete(); - } - } - - public boolean isControllerRunning() { - return !procMon.getProcesses(MAIN_CLASS, CTRL_PROP).isEmpty(); - } - -} diff --git a/opendaylight/commons/controller-maven-plugin/src/main/java/org/opendaylight/controller/maven/plugin/StartControllerMojo.java b/opendaylight/commons/controller-maven-plugin/src/main/java/org/opendaylight/controller/maven/plugin/StartControllerMojo.java deleted file mode 100644 index 0a3bee42f4..0000000000 --- a/opendaylight/commons/controller-maven-plugin/src/main/java/org/opendaylight/controller/maven/plugin/StartControllerMojo.java +++ /dev/null @@ -1,94 +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.maven.plugin; - -import java.net.MalformedURLException; -import java.util.ArrayList; -import java.util.List; - -import org.apache.maven.plugin.MojoExecutionException; -import org.apache.maven.plugin.MojoFailureException; -import org.apache.maven.plugins.annotations.LifecyclePhase; -import org.apache.maven.plugins.annotations.Mojo; -import org.apache.maven.plugins.annotations.Parameter; - - -/** - * Starts the controller - */ -@Mojo( name = "run", defaultPhase = LifecyclePhase.PRE_INTEGRATION_TEST ) -public class StartControllerMojo extends AbstractControllerMojo { - public static final String REDIRECT_LOG = "controller.out"; - - /** - * The timeout value for starting the controller. Defaults to 60 secs - */ - @Parameter(defaultValue = "60") - public int timeoutSecs = 60; - - /** - * The startArgs for starting the controller - */ - @Parameter(required = false) - protected List startArgs = new ArrayList(); - - /** - * The time to wait after successfully connecting to the controller and - * before returning from execution. - */ - @Parameter(required = false) - protected int warmupTimeSecs = 10; - - - @Override - public void start() throws MojoExecutionException, MojoFailureException { - killControllers(); - // if we can still connect to a controller, bail out - if (canConnect()) { - getLog().error("A controller is already running. Shutdown and retry."); - throw new MojoFailureException("Controller is already running."); - } - startArgs.add("-D" + CTRL_PROP); - Process process = invokeScript(startArgs, REDIRECT_LOG); - getLog().info("Controller starting... (waiting for open ports)"); - try { - waitForListening(process); - getLog().info("Controller port open. Waiting for warmup: " - + warmupTimeSecs); - Thread.sleep(warmupTimeSecs*1000); - } catch (Exception e) { - throw new MojoExecutionException(e.getMessage()); - } - getLog().info("Controller started successfully."); - } - - protected boolean waitForListening(Process process) - throws MalformedURLException, InterruptedException, MojoExecutionException - { - long timeElapsedMillis = 0L; - long sleepTimeMillis = 2000L; // 2 secs - long timeoutMillis = timeoutSecs * 1000; - - while (timeElapsedMillis < timeoutMillis) { - long timeRemaining = timeoutMillis - timeElapsedMillis; - sleepTimeMillis *= 2; - long toSleep = (sleepTimeMillis > timeRemaining) - ? timeRemaining : sleepTimeMillis; - Thread.sleep(toSleep); - timeElapsedMillis += toSleep; - if (canConnect()) { - return true; - } - if (!isControllerRunning()) { - throw new MojoExecutionException("Process seems to have exited prematurely."); - } - } - return false; - } -} diff --git a/opendaylight/commons/controller-maven-plugin/src/main/java/org/opendaylight/controller/maven/plugin/StopControllerMojo.java b/opendaylight/commons/controller-maven-plugin/src/main/java/org/opendaylight/controller/maven/plugin/StopControllerMojo.java deleted file mode 100644 index 579778d150..0000000000 --- a/opendaylight/commons/controller-maven-plugin/src/main/java/org/opendaylight/controller/maven/plugin/StopControllerMojo.java +++ /dev/null @@ -1,54 +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.maven.plugin; - -import java.util.ArrayList; -import java.util.List; - -import org.apache.maven.plugin.MojoExecutionException; -import org.apache.maven.plugin.MojoFailureException; -import org.apache.maven.plugins.annotations.LifecyclePhase; -import org.apache.maven.plugins.annotations.Mojo; - -/** - * Stop controller - */ -@Mojo( name = "stop", defaultPhase = LifecyclePhase.POST_INTEGRATION_TEST ) -public class StopControllerMojo extends AbstractControllerMojo { - private static final boolean SKIP_STOP = Boolean.getBoolean("skipControllerStop"); - - @Override - public void start() throws MojoExecutionException, MojoFailureException { - if (SKIP_STOP) { - getLog().info("Controller STOP is skipped per configuration " + - "(-DskipControllerStop=true)."); - return; - } - if (canConnect()) { - List args = new ArrayList(); - args.add("-stop"); - Process proc = invokeScript(args, null); - try { - int status = proc.waitFor(); - if (status == 0) { - getLog().info("Controller stopped."); - } else { - getLog().error("Error stopping controller. See stdout log for details."); - } - } catch (InterruptedException ie) { - throw new MojoExecutionException("Error stopping controller : " + ie.getMessage()); - } - } else { - getLog().info("Controller not running."); - } - // cleanup for any hung processes - killControllers(); - } - -} diff --git a/opendaylight/commons/controller-maven-plugin/src/main/java/org/opendaylight/controller/maven/plugin/util/JavaProcess.java b/opendaylight/commons/controller-maven-plugin/src/main/java/org/opendaylight/controller/maven/plugin/util/JavaProcess.java deleted file mode 100644 index 95da34ffad..0000000000 --- a/opendaylight/commons/controller-maven-plugin/src/main/java/org/opendaylight/controller/maven/plugin/util/JavaProcess.java +++ /dev/null @@ -1,57 +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.maven.plugin.util; - -import java.util.Properties; - -public class JavaProcess { - private final int pid; - private final String mainClass; - private final Properties systemProperties = new Properties(); - - public JavaProcess(int id, String cls) { - this.pid = id; - this.mainClass = cls; - } - - public void setSystemProperties(String line) { - if (line == null || line.length() == 0) return; - String[] tokens = line.split("\\s"); - for (String t : tokens) setSystemProperty(t); - } - - public void setSystemProperty(String line) { - if (line.startsWith("-D")) { - int x = line.indexOf('='); - if (x > -1) { - systemProperties.put(line.substring(2, x), line.substring(x+1)); - } else { - systemProperties.put(line.substring(2), ""); - } - } - } - - public int getPid() { - return pid; - } - - public String getMainClass() { - return mainClass; - } - - public Properties getSystemProperties() { - return systemProperties; - } - - @Override - public String toString() { - return "pid:" + pid + " class:" + mainClass + - " system-properties:" + systemProperties.toString(); - } -} diff --git a/opendaylight/commons/controller-maven-plugin/src/main/java/org/opendaylight/controller/maven/plugin/util/JpsProcessMonitor.java b/opendaylight/commons/controller-maven-plugin/src/main/java/org/opendaylight/controller/maven/plugin/util/JpsProcessMonitor.java deleted file mode 100644 index 8474266df2..0000000000 --- a/opendaylight/commons/controller-maven-plugin/src/main/java/org/opendaylight/controller/maven/plugin/util/JpsProcessMonitor.java +++ /dev/null @@ -1,79 +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.maven.plugin.util; - -import java.io.BufferedReader; -import java.io.File; -import java.io.InputStreamReader; -import java.util.ArrayList; -import java.util.List; - -/** - * Uses JPS tool to monitor java local processes - */ -public class JpsProcessMonitor extends ProcessMonitor { - private final String jpsTool; - - public JpsProcessMonitor() { - String jh = System.getProperty("java.home"); - File jps = new File(jh + SEP + "bin" + SEP + "jps"); - if (!jps.exists()) { - // try one dir above - jps = new File(jh + SEP + ".." + SEP + "bin" + SEP + "jps"); - if (!jps.exists()) { - throw new IllegalStateException("jps tool cannot be located."); - } - } - jpsTool = jps.getAbsolutePath(); - } - - @Override - public List getProcesses() { - if (jpsTool == null) return super.getProcesses(); - List jvms = new ArrayList(); - try { - ProcessBuilder pb = new ProcessBuilder(); - pb.command(new String[] { jpsTool, "-mlvV"} ); - pb.redirectErrorStream(true); - Process process = pb.start(); - BufferedReader br = new BufferedReader( - new InputStreamReader(process.getInputStream())); - String line = null; - while ( (line = br.readLine()) != null) { - JavaProcess j = parseLine(line); - if (j != null) jvms.add(j); - } - } catch (Exception e) { - e.printStackTrace(); - } - return jvms; - } - - public static JavaProcess parseLine(String line) { - String[] tokens = line.split("\\s"); - if (tokens.length < 2) { - System.out.println("Unable to parse line: " + line); - return null; - } - int idx = 0; - int pid = Integer.parseInt(tokens[idx++]); - String mainClass = ""; - if (!tokens[idx].startsWith("-")) { - mainClass = tokens[idx++]; - } - JavaProcess proc = new JavaProcess(pid, mainClass); - for (int i=idx; i -1; - - - - public void log(String msg) { - System.out.println("" + msg); - } - - public List getProcesses() { - return Collections.emptyList(); - } - - public List getProcesses(String mainClass, String systemPropertyKey) { - List result = new ArrayList(); - for (JavaProcess info : getProcesses()) { - if (info.getMainClass().equals(mainClass)) { - if (info.getSystemProperties().containsKey(systemPropertyKey)) { - result.add(info); - } - } - } - return result; - } - - public int kill(String mainClass) { - for (JavaProcess info : getProcesses()) { - if (info.getMainClass().equals(mainClass)) { - log("Killing process matching class: " + mainClass); - return kill(info.getPid()); - } - } - return -1; - } - - public static int kill(int pid) { - String cmd = WIN ? "TASKKILL /F /PID " + pid : "kill -SIGTERM " + pid; - try { - Process p = Runtime.getRuntime().exec(cmd); - p.waitFor(); - return p.exitValue(); - } catch (Exception e) { - e.printStackTrace(); - return -1; - } - } - - public static ProcessMonitor load() { - // load the providers dynamically to allow error handling - ProcessMonitor pm = load("org.opendaylight.controller.maven.plugin.util.VMProcessMonitor"); - if (pm == null) { - pm = load("org.opendaylight.controller.maven.plugin.util.JpsProcessMonitor"); - } - return (pm == null ? new ProcessMonitor() : pm); - } - - private static ProcessMonitor load(String clz) { - try { - Class c = Class.forName(clz); - return (ProcessMonitor) c.newInstance(); - } catch (Exception e) { - e.printStackTrace(); - return null; - } - } - - // simple driver for basic manual testing - public static void main(String[] args) throws Exception { - ProcessMonitor pm = ProcessMonitor.load(); - System.out.println("==== " + pm); - for (JavaProcess info : pm.getProcesses()) { - System.out.println(info.toString()); - } - pm.kill("Foo"); - System.out.println("==== controller processses "); - for (JavaProcess info : pm.getProcesses( - "org.eclipse.equinox.launcher.Main", "opendaylight.controller")) - { - System.out.println(info.toString()); - pm.kill(info.getPid()); - } - } - -} diff --git a/opendaylight/commons/controller-maven-plugin/src/main/java/org/opendaylight/controller/maven/plugin/util/VMProcessMonitor.java b/opendaylight/commons/controller-maven-plugin/src/main/java/org/opendaylight/controller/maven/plugin/util/VMProcessMonitor.java deleted file mode 100644 index fdf232a63c..0000000000 --- a/opendaylight/commons/controller-maven-plugin/src/main/java/org/opendaylight/controller/maven/plugin/util/VMProcessMonitor.java +++ /dev/null @@ -1,59 +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.maven.plugin.util; - -import java.util.ArrayList; -import java.util.List; -import java.util.Set; - -import sun.jvmstat.monitor.HostIdentifier; -import sun.jvmstat.monitor.MonitoredHost; -import sun.jvmstat.monitor.MonitoredVm; -import sun.jvmstat.monitor.MonitoredVmUtil; -import sun.jvmstat.monitor.VmIdentifier; - -public class VMProcessMonitor extends ProcessMonitor { - - @Override - public List getProcesses() { - Set activeVmPids = null; - List result = new ArrayList(); - MonitoredHost monitoredHost = null; - MonitoredVm mvm = null; - try { - monitoredHost = MonitoredHost.getMonitoredHost( - new HostIdentifier((String) null)); - activeVmPids = monitoredHost.activeVms(); - } catch (Exception e) { - throw new IllegalStateException("Error accessing VM", e); - } - for (Integer vmPid : activeVmPids) { - try { - mvm = monitoredHost.getMonitoredVm( - new VmIdentifier(vmPid.toString())); - JavaProcess proc = new JavaProcess(vmPid, - MonitoredVmUtil.mainClass(mvm, true)); - proc.setSystemProperties(MonitoredVmUtil.jvmArgs(mvm)); - proc.setSystemProperties(MonitoredVmUtil.jvmFlags(mvm)); - result.add(proc); - } catch(Exception e2) { - log("Error connecting to pid: " + vmPid + " reason:" - + e2.getMessage()); - e2.printStackTrace(); - } finally { - if (mvm != null) { - mvm.detach(); - } - } - } - return result; - } - - -} diff --git a/opendaylight/commons/integrationtest/pom.xml b/opendaylight/commons/integrationtest/pom.xml index 5e101ebd28..fe5aa473a6 100644 --- a/opendaylight/commons/integrationtest/pom.xml +++ b/opendaylight/commons/integrationtest/pom.xml @@ -59,11 +59,6 @@ junit - - org.ops4j.pax.exam - pax-exam-container-native - test - org.ops4j.pax.exam pax-exam-junit4 diff --git a/opendaylight/commons/opendaylight/pom.xml b/opendaylight/commons/opendaylight/pom.xml index 07c89166f9..5183165752 100644 --- a/opendaylight/commons/opendaylight/pom.xml +++ b/opendaylight/commons/opendaylight/pom.xml @@ -70,8 +70,6 @@ 0.5.3.201107060350 1.3.1 2.3.7 - 2.5 - 1.3.1 4.8.1 0.3.0-SNAPSHOT 0.5.9-SNAPSHOT @@ -996,7 +994,7 @@ true ${project.basedir} **\/*.java,**\/*.xml,**\/*.ini,**\/*.sh,**\/*.bat - **\/target\/,**\/bin\/ + **\/target\/,**\/bin\/,**\/target-ide\/ diff --git a/opendaylight/config/config-api/src/main/java/org/opendaylight/controller/config/api/ConfigRegistry.java b/opendaylight/config/config-api/src/main/java/org/opendaylight/controller/config/api/ConfigRegistry.java index 56b96e97bb..d81c48a602 100644 --- a/opendaylight/config/config-api/src/main/java/org/opendaylight/controller/config/api/ConfigRegistry.java +++ b/opendaylight/config/config-api/src/main/java/org/opendaylight/controller/config/api/ConfigRegistry.java @@ -62,8 +62,13 @@ public interface ConfigRegistry extends LookupRegistry, ServiceReferenceReadable */ boolean isHealthy(); + /** + * @return module factory names available in the system + */ Set getAvailableModuleNames(); + + /** * Find all runtime beans * diff --git a/opendaylight/config/config-api/src/main/java/org/opendaylight/controller/config/api/LookupRegistry.java b/opendaylight/config/config-api/src/main/java/org/opendaylight/controller/config/api/LookupRegistry.java index 8975471353..772617e97d 100644 --- a/opendaylight/config/config-api/src/main/java/org/opendaylight/controller/config/api/LookupRegistry.java +++ b/opendaylight/config/config-api/src/main/java/org/opendaylight/controller/config/api/LookupRegistry.java @@ -65,4 +65,9 @@ public interface LookupRegistry { */ void checkConfigBeanExists(ObjectName objectName) throws InstanceNotFoundException; + /** + * @return qnames of all ModuleFactory instances in the system + */ + Set getAvailableModuleFactoryQNames(); + } diff --git a/opendaylight/config/config-manager/src/main/java/org/opendaylight/controller/config/manager/impl/ConfigRegistryImpl.java b/opendaylight/config/config-manager/src/main/java/org/opendaylight/controller/config/manager/impl/ConfigRegistryImpl.java index 18326d91f2..e3311c747f 100644 --- a/opendaylight/config/config-manager/src/main/java/org/opendaylight/controller/config/manager/impl/ConfigRegistryImpl.java +++ b/opendaylight/config/config-manager/src/main/java/org/opendaylight/controller/config/manager/impl/ConfigRegistryImpl.java @@ -25,6 +25,7 @@ import org.opendaylight.controller.config.manager.impl.jmx.TransactionJMXRegistr import org.opendaylight.controller.config.manager.impl.osgi.BeanToOsgiServiceManager; import org.opendaylight.controller.config.manager.impl.osgi.BeanToOsgiServiceManager.OsgiRegistration; import org.opendaylight.controller.config.manager.impl.util.LookupBeansUtil; +import org.opendaylight.controller.config.manager.impl.util.ModuleQNameUtil; import org.opendaylight.controller.config.spi.Module; import org.opendaylight.controller.config.spi.ModuleFactory; import org.osgi.framework.BundleContext; @@ -61,9 +62,6 @@ public class ConfigRegistryImpl implements AutoCloseable, ConfigRegistryImplMXBe private final ModuleFactoriesResolver resolver; private final MBeanServer configMBeanServer; - @GuardedBy("this") - private final BundleContext bundleContext; - @GuardedBy("this") private long version = 0; @GuardedBy("this") @@ -101,6 +99,7 @@ public class ConfigRegistryImpl implements AutoCloseable, ConfigRegistryImplMXBe // internal jmx server shared by all transactions private final MBeanServer transactionsMBeanServer; + // Used for finding new factory instances for default module functionality @GuardedBy("this") private List lastListOfFactories = Collections.emptyList(); @@ -109,18 +108,17 @@ public class ConfigRegistryImpl implements AutoCloseable, ConfigRegistryImplMXBe // constructor public ConfigRegistryImpl(ModuleFactoriesResolver resolver, - BundleContext bundleContext, MBeanServer configMBeanServer) { - this(resolver, bundleContext, configMBeanServer, + MBeanServer configMBeanServer) { + this(resolver, configMBeanServer, new BaseJMXRegistrator(configMBeanServer)); } // constructor public ConfigRegistryImpl(ModuleFactoriesResolver resolver, - BundleContext bundleContext, MBeanServer configMBeanServer, + MBeanServer configMBeanServer, BaseJMXRegistrator baseJMXRegistrator) { this.resolver = resolver; this.beanToOsgiServiceManager = new BeanToOsgiServiceManager(); - this.bundleContext = bundleContext; this.configMBeanServer = configMBeanServer; this.baseJMXRegistrator = baseJMXRegistrator; this.registryMBeanServer = MBeanServerFactory @@ -156,10 +154,10 @@ public class ConfigRegistryImpl implements AutoCloseable, ConfigRegistryImplMXBe } }; - ConfigTransactionLookupRegistry txLookupRegistry = new ConfigTransactionLookupRegistry(new TransactionIdentifier( - transactionName), factory); Map> allCurrentFactories = Collections.unmodifiableMap( resolver.getAllFactories()); + ConfigTransactionLookupRegistry txLookupRegistry = new ConfigTransactionLookupRegistry(new TransactionIdentifier( + transactionName), factory, allCurrentFactories); ServiceReferenceWritableRegistry writableRegistry = ServiceReferenceRegistryImpl.createSRWritableRegistry( readableSRRegistry, txLookupRegistry, allCurrentFactories); @@ -550,6 +548,12 @@ public class ConfigRegistryImpl implements AutoCloseable, ConfigRegistryImplMXBe public synchronized String getServiceInterfaceName(String namespace, String localName) { return readableSRRegistry.getServiceInterfaceName(namespace, localName); } + + @Override + public Set getAvailableModuleFactoryQNames() { + return ModuleQNameUtil.getQNames(resolver.getAllFactories()); + } + } /** @@ -607,6 +611,8 @@ class ConfigHolder { Collections.sort(result); return result; } + + } /** diff --git a/opendaylight/config/config-manager/src/main/java/org/opendaylight/controller/config/manager/impl/ConfigTransactionControllerImpl.java b/opendaylight/config/config-manager/src/main/java/org/opendaylight/controller/config/manager/impl/ConfigTransactionControllerImpl.java index 36485b1abf..17ce078154 100644 --- a/opendaylight/config/config-manager/src/main/java/org/opendaylight/controller/config/manager/impl/ConfigTransactionControllerImpl.java +++ b/opendaylight/config/config-manager/src/main/java/org/opendaylight/controller/config/manager/impl/ConfigTransactionControllerImpl.java @@ -33,13 +33,13 @@ import javax.management.InstanceAlreadyExistsException; import javax.management.InstanceNotFoundException; import javax.management.MBeanServer; import javax.management.ObjectName; +import java.util.ArrayList; +import java.util.Collection; import java.util.HashSet; import java.util.List; import java.util.Map; import java.util.Map.Entry; import java.util.Set; -import java.util.ArrayList; -import java.util.Collection; import java.util.concurrent.atomic.AtomicBoolean; import static java.lang.String.format; @@ -576,4 +576,9 @@ class ConfigTransactionControllerImpl implements return txLookupRegistry.getTransactionIdentifier(); } + @Override + public Set getAvailableModuleFactoryQNames() { + return txLookupRegistry.getAvailableModuleFactoryQNames(); + } + } diff --git a/opendaylight/config/config-manager/src/main/java/org/opendaylight/controller/config/manager/impl/ConfigTransactionLookupRegistry.java b/opendaylight/config/config-manager/src/main/java/org/opendaylight/controller/config/manager/impl/ConfigTransactionLookupRegistry.java index 5d1f0b3976..12db6c8f89 100644 --- a/opendaylight/config/config-manager/src/main/java/org/opendaylight/controller/config/manager/impl/ConfigTransactionLookupRegistry.java +++ b/opendaylight/config/config-manager/src/main/java/org/opendaylight/controller/config/manager/impl/ConfigTransactionLookupRegistry.java @@ -12,11 +12,16 @@ import org.opendaylight.controller.config.api.jmx.ObjectNameUtil; import org.opendaylight.controller.config.manager.impl.jmx.TransactionJMXRegistrator; import org.opendaylight.controller.config.manager.impl.jmx.TransactionModuleJMXRegistrator; import org.opendaylight.controller.config.manager.impl.util.LookupBeansUtil; +import org.opendaylight.controller.config.manager.impl.util.ModuleQNameUtil; +import org.opendaylight.controller.config.spi.ModuleFactory; +import org.osgi.framework.BundleContext; import javax.management.InstanceAlreadyExistsException; import javax.management.InstanceNotFoundException; import javax.management.ObjectName; import java.io.Closeable; +import java.util.Map; +import java.util.Map.Entry; import java.util.Set; /** @@ -27,12 +32,14 @@ class ConfigTransactionLookupRegistry implements LookupRegistry, Closeable { private final TransactionJMXRegistrator transactionJMXRegistrator; private final TransactionIdentifier transactionIdentifier; private final TransactionModuleJMXRegistrator txModuleJMXRegistrator; + private final Map> allCurrentFactories; ConfigTransactionLookupRegistry(TransactionIdentifier transactionIdentifier, - TransactionJMXRegistratorFactory factory) { + TransactionJMXRegistratorFactory factory, Map> allCurrentFactories) { this.transactionIdentifier = transactionIdentifier; this.transactionJMXRegistrator = factory.create(); this.txModuleJMXRegistrator = transactionJMXRegistrator.createTransactionModuleJMXRegistrator(); + this.allCurrentFactories = allCurrentFactories; } private void checkTransactionName(ObjectName objectName) { @@ -104,6 +111,12 @@ class ConfigTransactionLookupRegistry implements LookupRegistry, Closeable { public void registerMBean(ConfigTransactionControllerInternal transactionController, ObjectName controllerObjectName) throws InstanceAlreadyExistsException { transactionJMXRegistrator.registerMBean(transactionController, controllerObjectName); } + + @Override + public Set getAvailableModuleFactoryQNames() { + return ModuleQNameUtil.getQNames(allCurrentFactories); + } + } interface TransactionJMXRegistratorFactory { diff --git a/opendaylight/config/config-manager/src/main/java/org/opendaylight/controller/config/manager/impl/ServiceReferenceRegistryImpl.java b/opendaylight/config/config-manager/src/main/java/org/opendaylight/controller/config/manager/impl/ServiceReferenceRegistryImpl.java index 2fd1ca6c2c..7fedcdf71c 100644 --- a/opendaylight/config/config-manager/src/main/java/org/opendaylight/controller/config/manager/impl/ServiceReferenceRegistryImpl.java +++ b/opendaylight/config/config-manager/src/main/java/org/opendaylight/controller/config/manager/impl/ServiceReferenceRegistryImpl.java @@ -75,6 +75,11 @@ public class ServiceReferenceRegistryImpl implements ServiceReferenceReadableReg public void checkConfigBeanExists(ObjectName objectName) throws InstanceNotFoundException { throw new InstanceNotFoundException("Cannot find " + objectName); } + + @Override + public Set getAvailableModuleFactoryQNames() { + throw new UnsupportedOperationException(); + } }; return new ServiceReferenceRegistryImpl(Collections.emptyMap(), lookupRegistry, Collections.>emptyMap()); diff --git a/opendaylight/config/config-manager/src/main/java/org/opendaylight/controller/config/manager/impl/factoriesresolver/HierarchicalConfigMBeanFactoriesHolder.java b/opendaylight/config/config-manager/src/main/java/org/opendaylight/controller/config/manager/impl/factoriesresolver/HierarchicalConfigMBeanFactoriesHolder.java index f82a7295aa..16f7cf024a 100644 --- a/opendaylight/config/config-manager/src/main/java/org/opendaylight/controller/config/manager/impl/factoriesresolver/HierarchicalConfigMBeanFactoriesHolder.java +++ b/opendaylight/config/config-manager/src/main/java/org/opendaylight/controller/config/manager/impl/factoriesresolver/HierarchicalConfigMBeanFactoriesHolder.java @@ -13,6 +13,7 @@ import org.osgi.framework.BundleContext; import org.slf4j.Logger; import org.slf4j.LoggerFactory; +import java.util.Map.Entry; import java.util.Set; import java.util.List; import java.util.Map; @@ -76,4 +77,7 @@ public class HierarchicalConfigMBeanFactoriesHolder { return moduleFactories; } + public Map> getModuleNamesToConfigBeanFactories() { + return moduleNamesToConfigBeanFactories; + } } diff --git a/opendaylight/config/config-manager/src/main/java/org/opendaylight/controller/config/manager/impl/osgi/ConfigManagerActivator.java b/opendaylight/config/config-manager/src/main/java/org/opendaylight/controller/config/manager/impl/osgi/ConfigManagerActivator.java index ab81143170..1ee6cca7e2 100644 --- a/opendaylight/config/config-manager/src/main/java/org/opendaylight/controller/config/manager/impl/osgi/ConfigManagerActivator.java +++ b/opendaylight/config/config-manager/src/main/java/org/opendaylight/controller/config/manager/impl/osgi/ConfigManagerActivator.java @@ -36,8 +36,7 @@ public class ConfigManagerActivator implements BundleActivator { new BundleContextBackedModuleFactoriesResolver(context); MBeanServer configMBeanServer = ManagementFactory.getPlatformMBeanServer(); configRegistry = new ConfigRegistryImpl( - bundleContextBackedModuleFactoriesResolver, context, - configMBeanServer); + bundleContextBackedModuleFactoriesResolver, configMBeanServer); // register config registry to OSGi configRegistryServiceRegistration = context.registerService(ConfigRegistryImpl.class, configRegistry, null); diff --git a/opendaylight/config/config-manager/src/main/java/org/opendaylight/controller/config/manager/impl/util/ModuleQNameUtil.java b/opendaylight/config/config-manager/src/main/java/org/opendaylight/controller/config/manager/impl/util/ModuleQNameUtil.java new file mode 100644 index 0000000000..e84337756e --- /dev/null +++ b/opendaylight/config/config-manager/src/main/java/org/opendaylight/controller/config/manager/impl/util/ModuleQNameUtil.java @@ -0,0 +1,42 @@ +/* + * Copyright (c) 2013 Cisco Systems, Inc. and others. All rights reserved. + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License v1.0 which accompanies this distribution, + * and is available at http://www.eclipse.org/legal/epl-v10.html + */ +package org.opendaylight.controller.config.manager.impl.util; + +import org.opendaylight.controller.config.spi.ModuleFactory; +import org.opendaylight.yangtools.yang.binding.annotations.ModuleQName; +import org.osgi.framework.BundleContext; + +import java.util.HashSet; +import java.util.Map; +import java.util.Map.Entry; +import java.util.Set; + +public class ModuleQNameUtil { + + public static Set getQNames(Map> resolved) { + Set result = new HashSet<>(); + for (Entry entry : resolved.values()) { + Class inspected = entry.getKey().getClass(); + if (inspected.isInterface()) { + throw new IllegalArgumentException("Unexpected interface " + inspected); + } + ModuleQName annotation = null; + while(annotation == null && inspected != null) { + annotation = inspected.getAnnotation(ModuleQName.class); + inspected = inspected.getSuperclass(); + } + if (annotation != null) { + // FIXME + String qName = "(" + annotation.namespace() + "?revision=" + annotation.revision() + ")" + annotation.name(); + result.add(qName); + } + } + return result; + } + +} diff --git a/opendaylight/config/config-manager/src/test/java/org/opendaylight/controller/config/manager/ConfigRegistryImplTest.java b/opendaylight/config/config-manager/src/test/java/org/opendaylight/controller/config/manager/ConfigRegistryImplTest.java index ccb67d371e..e6b07bab64 100644 --- a/opendaylight/config/config-manager/src/test/java/org/opendaylight/controller/config/manager/ConfigRegistryImplTest.java +++ b/opendaylight/config/config-manager/src/test/java/org/opendaylight/controller/config/manager/ConfigRegistryImplTest.java @@ -40,7 +40,7 @@ public class ConfigRegistryImplTest extends factory, factory); configRegistry = new ConfigRegistryImpl(resolver, - context, ManagementFactory.getPlatformMBeanServer()); + ManagementFactory.getPlatformMBeanServer()); configRegistry.beginConfig(); fail(); diff --git a/opendaylight/config/config-manager/src/test/java/org/opendaylight/controller/config/manager/impl/AbstractConfigTest.java b/opendaylight/config/config-manager/src/test/java/org/opendaylight/controller/config/manager/impl/AbstractConfigTest.java index 5ed56bd2bf..a7e3fa6c6f 100644 --- a/opendaylight/config/config-manager/src/test/java/org/opendaylight/controller/config/manager/impl/AbstractConfigTest.java +++ b/opendaylight/config/config-manager/src/test/java/org/opendaylight/controller/config/manager/impl/AbstractConfigTest.java @@ -70,7 +70,7 @@ public abstract class AbstractConfigTest extends internalJmxRegistrator = new InternalJMXRegistrator(platformMBeanServer); baseJmxRegistrator = new BaseJMXRegistrator(internalJmxRegistrator); - configRegistry = new ConfigRegistryImpl(resolver, mockedContext, + configRegistry = new ConfigRegistryImpl(resolver, platformMBeanServer, baseJmxRegistrator); try { configRegistryJMXRegistrator.registerToJMX(configRegistry); diff --git a/opendaylight/config/config-manager/src/test/java/org/opendaylight/controller/config/manager/impl/ConfigRegistryImplLookupTest.java b/opendaylight/config/config-manager/src/test/java/org/opendaylight/controller/config/manager/impl/ConfigRegistryImplLookupTest.java index 6dddc62f67..a522356a27 100644 --- a/opendaylight/config/config-manager/src/test/java/org/opendaylight/controller/config/manager/impl/ConfigRegistryImplLookupTest.java +++ b/opendaylight/config/config-manager/src/test/java/org/opendaylight/controller/config/manager/impl/ConfigRegistryImplLookupTest.java @@ -66,7 +66,7 @@ public class ConfigRegistryImplLookupTest extends @Before public void setUp() throws Exception { - configRegistryImpl = new ConfigRegistryImpl(null, null, + configRegistryImpl = new ConfigRegistryImpl(null, ManagementFactory.getPlatformMBeanServer()); Field field = configRegistryImpl.getClass().getDeclaredField( "baseJMXRegistrator"); diff --git a/opendaylight/config/config-manager/src/test/java/org/opendaylight/controller/config/manager/impl/ConfigTransactionControllerImplTest.java b/opendaylight/config/config-manager/src/test/java/org/opendaylight/controller/config/manager/impl/ConfigTransactionControllerImplTest.java index 43c75ef1e7..50f5742149 100644 --- a/opendaylight/config/config-manager/src/test/java/org/opendaylight/controller/config/manager/impl/ConfigTransactionControllerImplTest.java +++ b/opendaylight/config/config-manager/src/test/java/org/opendaylight/controller/config/manager/impl/ConfigTransactionControllerImplTest.java @@ -68,7 +68,7 @@ public class ConfigTransactionControllerImplTest extends public TransactionJMXRegistrator create() { return baseJMXRegistrator.createTransactionJMXRegistrator(transactionName123); } - }); + }, currentlyRegisteredFactories); ServiceReferenceWritableRegistry writableRegistry = ServiceReferenceRegistryImpl.createSRWritableRegistry( ServiceReferenceRegistryImpl.createInitialSRLookupRegistry(), txLookupRegistry, currentlyRegisteredFactories); diff --git a/opendaylight/config/config-manager/src/test/java/org/opendaylight/controller/config/manager/testingservices/threadpool/AbstractTestingFixedThreadPoolModuleFactory.java b/opendaylight/config/config-manager/src/test/java/org/opendaylight/controller/config/manager/testingservices/threadpool/AbstractTestingFixedThreadPoolModuleFactory.java new file mode 100644 index 0000000000..0286400d7b --- /dev/null +++ b/opendaylight/config/config-manager/src/test/java/org/opendaylight/controller/config/manager/testingservices/threadpool/AbstractTestingFixedThreadPoolModuleFactory.java @@ -0,0 +1,14 @@ +/* + * Copyright (c) 2013 Cisco Systems, Inc. and others. All rights reserved. + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License v1.0 which accompanies this distribution, + * and is available at http://www.eclipse.org/legal/epl-v10.html + */ +package org.opendaylight.controller.config.manager.testingservices.threadpool; + +import org.opendaylight.yangtools.yang.binding.annotations.ModuleQName; + +@ModuleQName(namespace = "namespace", revision = "revision", name = "name") +public abstract class AbstractTestingFixedThreadPoolModuleFactory { +} diff --git a/opendaylight/config/config-manager/src/test/java/org/opendaylight/controller/config/manager/testingservices/threadpool/TestingFixedThreadPoolModuleFactory.java b/opendaylight/config/config-manager/src/test/java/org/opendaylight/controller/config/manager/testingservices/threadpool/TestingFixedThreadPoolModuleFactory.java index b749ea7511..bec2868557 100644 --- a/opendaylight/config/config-manager/src/test/java/org/opendaylight/controller/config/manager/testingservices/threadpool/TestingFixedThreadPoolModuleFactory.java +++ b/opendaylight/config/config-manager/src/test/java/org/opendaylight/controller/config/manager/testingservices/threadpool/TestingFixedThreadPoolModuleFactory.java @@ -23,7 +23,7 @@ import java.util.Collections; import java.util.HashSet; import java.util.Set; -public class TestingFixedThreadPoolModuleFactory implements ModuleFactory { +public class TestingFixedThreadPoolModuleFactory extends AbstractTestingFixedThreadPoolModuleFactory implements ModuleFactory { public static final String NAME = "fixed"; private static Set> ifc = Collections.unmodifiableSet(Sets.newHashSet( diff --git a/opendaylight/config/config-manager/src/test/java/org/opendaylight/controller/config/manager/testingservices/threadpool/test/SimpleConfigurationTest.java b/opendaylight/config/config-manager/src/test/java/org/opendaylight/controller/config/manager/testingservices/threadpool/test/SimpleConfigurationTest.java index 13bb84040a..441de36db0 100644 --- a/opendaylight/config/config-manager/src/test/java/org/opendaylight/controller/config/manager/testingservices/threadpool/test/SimpleConfigurationTest.java +++ b/opendaylight/config/config-manager/src/test/java/org/opendaylight/controller/config/manager/testingservices/threadpool/test/SimpleConfigurationTest.java @@ -7,6 +7,7 @@ */ package org.opendaylight.controller.config.manager.testingservices.threadpool.test; +import com.google.common.collect.Sets; import org.junit.After; import org.junit.Before; import org.junit.Test; @@ -34,6 +35,7 @@ import java.util.Arrays; import java.util.Collections; import java.util.List; import java.util.Map; +import java.util.Set; import java.util.concurrent.ThreadPoolExecutor; import static org.junit.Assert.assertEquals; @@ -384,4 +386,11 @@ public class SimpleConfigurationTest extends AbstractConfigTest { } + @Test + public void testQNames() { + Set availableModuleFactoryQNames = configRegistryClient.getAvailableModuleFactoryQNames(); + String expected = "(namespace?revision=revision)name"; + assertEquals(Sets.newHashSet(expected), availableModuleFactoryQNames); + } + } diff --git a/opendaylight/config/config-persister-directory-adapter/src/main/java/org/opendaylight/controller/config/persist/storage/directory/DirectoryPersister.java b/opendaylight/config/config-persister-directory-adapter/src/main/java/org/opendaylight/controller/config/persist/storage/directory/DirectoryPersister.java index 39595edb0b..a123eb981e 100644 --- a/opendaylight/config/config-persister-directory-adapter/src/main/java/org/opendaylight/controller/config/persist/storage/directory/DirectoryPersister.java +++ b/opendaylight/config/config-persister-directory-adapter/src/main/java/org/opendaylight/controller/config/persist/storage/directory/DirectoryPersister.java @@ -139,7 +139,7 @@ class MyLineProcessor implements com.google.common.io.LineProcessor { } private void checkFileConsistency(){ - checkState(inCapabilities, "File {} is missing delimiters in this order: {}", fileNameForReporting, + checkState(inCapabilities, "File %s is missing delimiters in this order: %s", fileNameForReporting, Arrays.asList(DirectoryPersister.MODULES_START, DirectoryPersister.SERVICES_START, DirectoryPersister.CAPABILITIES_START)); diff --git a/opendaylight/config/config-persister-directory-xml-adapter/pom.xml b/opendaylight/config/config-persister-directory-xml-adapter/pom.xml new file mode 100644 index 0000000000..b2ea632834 --- /dev/null +++ b/opendaylight/config/config-persister-directory-xml-adapter/pom.xml @@ -0,0 +1,115 @@ + + + 4.0.0 + + config-subsystem + org.opendaylight.controller + 0.2.3-SNAPSHOT + .. + + config-persister-directory-xml-adapter + ${project.artifactId} + bundle + + + + + ${project.groupId} + config-persister-api + + + org.apache.commons + commons-lang3 + + + com.google.guava + guava + + + org.opendaylight.controller + config-persister-file-xml-adapter + ${config.version} + + + + org.eclipse.persistence + org.eclipse.persistence.moxy + + + org.eclipse.persistence + org.eclipse.persistence.core + + + + org.slf4j + slf4j-api + + + commons-io + commons-io + + + + + org.opendaylight.bgpcep + mockito-configuration + test + + + + + + + + + org.codehaus.groovy.maven + gmaven-plugin + + + generate-sources + + execute + + + + System.setProperty("osgiversion", "${project.version}".replace('-', '.')) + + + + + + + org.apache.felix + maven-bundle-plugin + + + ${project.groupId}.config-persister-impl;bundle-version=${osgiversion} + + org.opendaylight.controller.config.persister.storage.adapter + + + com.google.common.base, + com.google.common.io, + org.apache.commons.io, + org.opendaylight.controller.config.persist.api, + org.slf4j, + com.google.common.collect, + javax.xml.bind, + javax.xml.bind.annotation, + javax.xml.transform, + javax.xml.transform.stream, + org.eclipse.persistence.jaxb, + org.apache.commons.lang3 + + + org.opendaylight.controller.config.persist.storage.file.xml.model, + + + + + + + + diff --git a/opendaylight/config/config-persister-directory-xml-adapter/src/main/java/org/opendaylight/controller/config/persist/storage/directory/xml/XmlDirectoryPersister.java b/opendaylight/config/config-persister-directory-xml-adapter/src/main/java/org/opendaylight/controller/config/persist/storage/directory/xml/XmlDirectoryPersister.java new file mode 100644 index 0000000000..f6f6de9fd5 --- /dev/null +++ b/opendaylight/config/config-persister-directory-xml-adapter/src/main/java/org/opendaylight/controller/config/persist/storage/directory/xml/XmlDirectoryPersister.java @@ -0,0 +1,108 @@ +/* + * Copyright (c) 2013 Cisco Systems, Inc. and others. All rights reserved. + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License v1.0 which accompanies this distribution, + * and is available at http://www.eclipse.org/legal/epl-v10.html + */ +package org.opendaylight.controller.config.persist.storage.directory.xml; + +import org.opendaylight.controller.config.persist.api.ConfigSnapshotHolder; +import org.opendaylight.controller.config.persist.api.Persister; +import org.opendaylight.controller.config.persist.storage.file.xml.model.ConfigSnapshot; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import javax.xml.bind.JAXBContext; +import javax.xml.bind.JAXBException; +import javax.xml.bind.Unmarshaller; +import java.io.File; +import java.io.IOException; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Collections; +import java.util.List; +import java.util.SortedSet; + +import static com.google.common.base.Preconditions.checkArgument; + +public class XmlDirectoryPersister implements Persister { + private static final Logger logger = LoggerFactory.getLogger(XmlDirectoryPersister.class); + + private final File storage; + + public XmlDirectoryPersister(File storage) { + checkArgument(storage.exists() && storage.isDirectory(), "Storage directory does not exist: " + storage); + this.storage = storage; + } + + @Override + public void persistConfig(ConfigSnapshotHolder holder) throws IOException { + throw new UnsupportedOperationException("This adapter is read only. Please set readonly=true on " + getClass()); + } + + @Override + public List loadLastConfigs() throws IOException { + File[] filesArray = storage.listFiles(); + if (filesArray == null || filesArray.length == 0) { + return Collections.emptyList(); + } + List sortedFiles = new ArrayList<>(Arrays.asList(filesArray)); + Collections.sort(sortedFiles); + // combine all found files + logger.debug("Reading files in following order: {}", sortedFiles); + + List result = new ArrayList<>(); + for (File file : sortedFiles) { + logger.trace("Adding file '{}' to combined result", file); + ConfigSnapshotHolder h = fromXmlSnapshot(file); + result.add(h); + } + return result; + } + + private ConfigSnapshotHolder fromXmlSnapshot(File file) { + try { + JAXBContext jaxbContext = JAXBContext.newInstance(ConfigSnapshot.class); + Unmarshaller um = jaxbContext.createUnmarshaller(); + + return asHolder((ConfigSnapshot) um.unmarshal(file)); + } catch (JAXBException e) { + logger.warn("Unable to restore configuration snapshot from {}", file, e); + throw new IllegalStateException("Unable to restore configuration snapshot from " + file, e); + } + } + + private ConfigSnapshotHolder asHolder(final ConfigSnapshot unmarshalled) { + return new ConfigSnapshotHolder() { + @Override + public String getConfigSnapshot() { + return unmarshalled.getConfigSnapshot(); + } + + @Override + public SortedSet getCapabilities() { + return unmarshalled.getCapabilities(); + } + + @Override + public String toString() { + return unmarshalled.toString(); + } + }; + } + + + @Override + public void close() { + + } + + @Override + public String toString() { + final StringBuffer sb = new StringBuffer("XmlDirectoryPersister{"); + sb.append("storage=").append(storage); + sb.append('}'); + return sb.toString(); + } +} \ No newline at end of file diff --git a/opendaylight/config/config-persister-directory-xml-adapter/src/main/java/org/opendaylight/controller/config/persist/storage/directory/xml/XmlDirectoryStorageAdapter.java b/opendaylight/config/config-persister-directory-xml-adapter/src/main/java/org/opendaylight/controller/config/persist/storage/directory/xml/XmlDirectoryStorageAdapter.java new file mode 100644 index 0000000000..ab6fb1577c --- /dev/null +++ b/opendaylight/config/config-persister-directory-xml-adapter/src/main/java/org/opendaylight/controller/config/persist/storage/directory/xml/XmlDirectoryStorageAdapter.java @@ -0,0 +1,39 @@ +/* + * Copyright (c) 2013 Cisco Systems, Inc. and others. All rights reserved. + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License v1.0 which accompanies this distribution, + * and is available at http://www.eclipse.org/legal/epl-v10.html + */ + +package org.opendaylight.controller.config.persist.storage.directory.xml; + +import com.google.common.base.Preconditions; +import org.opendaylight.controller.config.persist.api.Persister; +import org.opendaylight.controller.config.persist.api.PropertiesProvider; +import org.opendaylight.controller.config.persist.api.StorageAdapter; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import java.io.File; + +/** + * StorageAdapter that retrieves initial configuration from a directory. If multiple files are present, snapshot and + * required capabilities will be merged together. Writing to this persister is not supported. + */ +public class XmlDirectoryStorageAdapter implements StorageAdapter { + private static final Logger logger = LoggerFactory.getLogger(XmlDirectoryStorageAdapter.class); + + public static final String DIRECTORY_STORAGE_PROP = "directoryStorage"; + + + @Override + public Persister instantiate(PropertiesProvider propertiesProvider) { + String fileStorageProperty = propertiesProvider.getProperty(DIRECTORY_STORAGE_PROP); + Preconditions.checkNotNull(fileStorageProperty, "Unable to find " + propertiesProvider.getFullKeyForReporting(DIRECTORY_STORAGE_PROP)); + File storage = new File(fileStorageProperty); + logger.debug("Using {}", storage); + return new XmlDirectoryPersister(storage); + } + +} diff --git a/opendaylight/config/config-persister-directory-xml-adapter/src/test/java/org/opendaylight/controller/config/persist/storage/directory/xml/DirectoryStorageAdapterTest.java b/opendaylight/config/config-persister-directory-xml-adapter/src/test/java/org/opendaylight/controller/config/persist/storage/directory/xml/DirectoryStorageAdapterTest.java new file mode 100644 index 0000000000..73061f81de --- /dev/null +++ b/opendaylight/config/config-persister-directory-xml-adapter/src/test/java/org/opendaylight/controller/config/persist/storage/directory/xml/DirectoryStorageAdapterTest.java @@ -0,0 +1,88 @@ +/* + * Copyright (c) 2013 Cisco Systems, Inc. and others. All rights reserved. + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License v1.0 which accompanies this distribution, + * and is available at http://www.eclipse.org/legal/epl-v10.html + */ + +package org.opendaylight.controller.config.persist.storage.directory.xml; + +import org.junit.Test; +import org.opendaylight.controller.config.persist.api.ConfigSnapshotHolder; + +import java.io.File; +import java.util.Collections; +import java.util.List; +import java.util.SortedSet; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertTrue; +import static org.junit.Assert.fail; + +public class DirectoryStorageAdapterTest { + XmlDirectoryPersister tested; + + @Test + public void testEmptyDirectory() throws Exception { + File folder = new File("target/emptyFolder"); + folder.mkdir(); + tested = new XmlDirectoryPersister((folder)); + assertEquals(Collections.emptyList(), tested.loadLastConfigs()); + + try { + tested.persistConfig(new ConfigSnapshotHolder() { + @Override + public String getConfigSnapshot() { + throw new RuntimeException(); + } + + @Override + public SortedSet getCapabilities() { + throw new RuntimeException(); + } + }); + fail(); + } catch (UnsupportedOperationException e) { + + } + } + + private File getFolder(String folderName) { + File result = new File(("src/test/resources/" + + folderName).replace("/", File.separator)); + assertTrue(result + " is not a directory", result.isDirectory()); + return result; + } + + @Test + public void testOneFile() throws Exception { + File folder = getFolder("oneFile"); + tested = new XmlDirectoryPersister((folder)); + List results = tested.loadLastConfigs(); + assertEquals(1, results.size()); + ConfigSnapshotHolder result = results.get(0); + assertResult(result, "1", "cap1&rev", "cap2", "capa a"); + } + + private void assertResult(ConfigSnapshotHolder result, String s, String... caps) { + assertEquals(s, result.getConfigSnapshot().replaceAll("\\s", "")); + int i = 0; + for (String capFromSnapshot : result.getCapabilities()) { + assertEquals(capFromSnapshot, caps[i++]); + } + } + + @Test + public void testTwoFiles() throws Exception { + File folder = getFolder("twoFiles"); + tested = new XmlDirectoryPersister((folder)); + List results = tested.loadLastConfigs(); + assertEquals(2, results.size()); + + assertResult(results.get(0), "1", "cap1-a", "cap2-a", "capa a-a"); + assertResult(results.get(1), "2", "cap1-b", "cap2-b", "capa a-b"); + + } + +} diff --git a/opendaylight/config/config-persister-directory-xml-adapter/src/test/resources/oneFile/controller.config.xml b/opendaylight/config/config-persister-directory-xml-adapter/src/test/resources/oneFile/controller.config.xml new file mode 100644 index 0000000000..aa8b14c9c4 --- /dev/null +++ b/opendaylight/config/config-persister-directory-xml-adapter/src/test/resources/oneFile/controller.config.xml @@ -0,0 +1,10 @@ + + + cap1&rev + cap2 + capa a + + + 1 + + \ No newline at end of file diff --git a/opendaylight/config/config-persister-directory-xml-adapter/src/test/resources/twoFiles/controller.config1.xml b/opendaylight/config/config-persister-directory-xml-adapter/src/test/resources/twoFiles/controller.config1.xml new file mode 100644 index 0000000000..28f112e4fa --- /dev/null +++ b/opendaylight/config/config-persister-directory-xml-adapter/src/test/resources/twoFiles/controller.config1.xml @@ -0,0 +1,10 @@ + + + cap1-a + cap2-a + capa a-a + + + 1 + + \ No newline at end of file diff --git a/opendaylight/config/config-persister-directory-xml-adapter/src/test/resources/twoFiles/controller.config2.xml b/opendaylight/config/config-persister-directory-xml-adapter/src/test/resources/twoFiles/controller.config2.xml new file mode 100644 index 0000000000..8fed29d182 --- /dev/null +++ b/opendaylight/config/config-persister-directory-xml-adapter/src/test/resources/twoFiles/controller.config2.xml @@ -0,0 +1,10 @@ + + + cap1-b + cap2-b + capa a-b + + + 2 + + \ No newline at end of file diff --git a/opendaylight/config/config-persister-file-xml-adapter/pom.xml b/opendaylight/config/config-persister-file-xml-adapter/pom.xml new file mode 100644 index 0000000000..abbec382b7 --- /dev/null +++ b/opendaylight/config/config-persister-file-xml-adapter/pom.xml @@ -0,0 +1,87 @@ + + + 4.0.0 + + config-subsystem + org.opendaylight.controller + 0.2.3-SNAPSHOT + .. + + config-persister-file-xml-adapter + ${project.artifactId} + bundle + + + + + ${project.groupId} + config-persister-api + + + org.apache.commons + commons-lang3 + + + com.google.guava + guava + + + org.slf4j + slf4j-api + + + + org.eclipse.persistence + org.eclipse.persistence.moxy + + + org.eclipse.persistence + org.eclipse.persistence.core + + + + + org.opendaylight.bgpcep + mockito-configuration + test + + + + + + + + org.codehaus.groovy.maven + gmaven-plugin + + + generate-sources + + execute + + + + System.setProperty("osgiversion", "${project.version}".replace('-', '.')) + + + + + + + org.apache.felix + maven-bundle-plugin + + + ${project.groupId}.config-persister-impl;bundle-version=${osgiversion} + + org.opendaylight.controller.config.persister.storage.adapter + + + + + + + + diff --git a/opendaylight/config/config-persister-file-xml-adapter/src/main/java/org/opendaylight/controller/config/persist/storage/file/xml/XmlFileStorageAdapter.java b/opendaylight/config/config-persister-file-xml-adapter/src/main/java/org/opendaylight/controller/config/persist/storage/file/xml/XmlFileStorageAdapter.java new file mode 100644 index 0000000000..e75c62b81d --- /dev/null +++ b/opendaylight/config/config-persister-file-xml-adapter/src/main/java/org/opendaylight/controller/config/persist/storage/file/xml/XmlFileStorageAdapter.java @@ -0,0 +1,149 @@ +/* + * Copyright (c) 2013 Cisco Systems, Inc. and others. All rights reserved. + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License v1.0 which accompanies this distribution, + * and is available at http://www.eclipse.org/legal/epl-v10.html + */ + +package org.opendaylight.controller.config.persist.storage.file.xml; + +import com.google.common.annotations.VisibleForTesting; +import com.google.common.base.Optional; +import com.google.common.base.Preconditions; +import com.google.common.collect.Lists; +import org.opendaylight.controller.config.persist.api.ConfigSnapshotHolder; +import org.opendaylight.controller.config.persist.api.Persister; +import org.opendaylight.controller.config.persist.api.PropertiesProvider; +import org.opendaylight.controller.config.persist.api.StorageAdapter; +import org.opendaylight.controller.config.persist.storage.file.xml.model.Config; +import org.opendaylight.controller.config.persist.storage.file.xml.model.ConfigSnapshot; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import java.io.File; +import java.io.IOException; +import java.util.Collections; +import java.util.List; +import java.util.SortedSet; + +/** + * StorageAdapter that stores configuration in an xml file. + */ +public class XmlFileStorageAdapter implements StorageAdapter, Persister { + private static final Logger logger = LoggerFactory.getLogger(XmlFileStorageAdapter.class); + + public static final String FILE_STORAGE_PROP = "fileStorage"; + public static final String NUMBER_OF_BACKUPS = "numberOfBackups"; + + private static Integer numberOfStoredBackups; + private File storage; + + @Override + public Persister instantiate(PropertiesProvider propertiesProvider) { + File storage = extractStorageFileFromProperties(propertiesProvider); + logger.debug("Using file {}", storage.getAbsolutePath()); + // Create file if it does not exist + File parentFile = storage.getAbsoluteFile().getParentFile(); + if (parentFile.exists() == false) { + logger.debug("Creating parent folders {}", parentFile); + parentFile.mkdirs(); + } + if (storage.exists() == false) { + logger.debug("Storage file does not exist, creating empty file"); + try { + boolean result = storage.createNewFile(); + if (result == false) + throw new RuntimeException("Unable to create storage file " + storage); + } catch (IOException e) { + throw new RuntimeException("Unable to create storage file " + storage, e); + } + } + if (numberOfStoredBackups == 0) { + throw new RuntimeException(NUMBER_OF_BACKUPS + + " property should be either set to positive value, or ommited. Can not be set to 0."); + } + setFileStorage(storage); + return this; + } + + @VisibleForTesting + public void setFileStorage(File storage) { + this.storage = storage; + } + + @VisibleForTesting + public void setNumberOfBackups(Integer numberOfBackups) { + numberOfStoredBackups = numberOfBackups; + } + + private static File extractStorageFileFromProperties(PropertiesProvider propertiesProvider) { + String fileStorageProperty = propertiesProvider.getProperty(FILE_STORAGE_PROP); + Preconditions.checkNotNull(fileStorageProperty, "Unable to find " + propertiesProvider.getFullKeyForReporting(FILE_STORAGE_PROP)); + File result = new File(fileStorageProperty); + String numberOfBackupsAsString = propertiesProvider.getProperty(NUMBER_OF_BACKUPS); + if (numberOfBackupsAsString != null) { + numberOfStoredBackups = Integer.valueOf(numberOfBackupsAsString); + } else { + numberOfStoredBackups = Integer.MAX_VALUE; + } + logger.trace("Property {} set to {}", NUMBER_OF_BACKUPS, numberOfStoredBackups); + return result; + } + + @Override + public void persistConfig(ConfigSnapshotHolder holder) throws IOException { + Preconditions.checkNotNull(storage, "Storage file is null"); + + Config cfg = Config.fromXml(storage); + cfg.addConfigSnapshot(ConfigSnapshot.fromConfigSnapshot(holder), numberOfStoredBackups); + cfg.toXml(storage); + } + + @Override + public List loadLastConfigs() throws IOException { + Preconditions.checkNotNull(storage, "Storage file is null"); + + if (!storage.exists()) { + return Collections.emptyList(); + } + + Optional lastSnapshot = Config.fromXml(storage).getLastSnapshot(); + + if (lastSnapshot.isPresent()) + return Lists.newArrayList(toConfigSnapshot(lastSnapshot.get())); + else + return Collections.emptyList(); + } + + + public ConfigSnapshotHolder toConfigSnapshot(final ConfigSnapshot configSnapshot) { + return new ConfigSnapshotHolder() { + @Override + public String getConfigSnapshot() { + return configSnapshot.getConfigSnapshot(); + } + + @Override + public SortedSet getCapabilities() { + return configSnapshot.getCapabilities(); + } + + @Override + public String toString() { + return configSnapshot.toString(); + } + }; + } + + @Override + public void close() { + + } + + @Override + public String toString() { + return "XmlFileStorageAdapter [storage=" + storage + "]"; + } + +} diff --git a/opendaylight/config/config-persister-file-xml-adapter/src/main/java/org/opendaylight/controller/config/persist/storage/file/xml/model/CapabilityHandler.java b/opendaylight/config/config-persister-file-xml-adapter/src/main/java/org/opendaylight/controller/config/persist/storage/file/xml/model/CapabilityHandler.java new file mode 100644 index 0000000000..d384df6989 --- /dev/null +++ b/opendaylight/config/config-persister-file-xml-adapter/src/main/java/org/opendaylight/controller/config/persist/storage/file/xml/model/CapabilityHandler.java @@ -0,0 +1,47 @@ +/* + * Copyright (c) 2013 Cisco Systems, Inc. and others. All rights reserved. + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License v1.0 which accompanies this distribution, + * and is available at http://www.eclipse.org/legal/epl-v10.html + */ +package org.opendaylight.controller.config.persist.storage.file.xml.model; + +import javax.xml.bind.ValidationEventHandler; +import javax.xml.bind.annotation.DomHandler; +import javax.xml.transform.Source; +import javax.xml.transform.stream.StreamResult; +import javax.xml.transform.stream.StreamSource; +import java.io.StringReader; +import java.io.StringWriter; + +class CapabilityHandler implements DomHandler { + + private static final String START_TAG = ""; + private static final String END_TAG = ""; + + private StringWriter xmlWriter = new StringWriter(); + + public StreamResult createUnmarshaller(ValidationEventHandler errorHandler) { + xmlWriter.getBuffer().setLength(0); + return new StreamResult(xmlWriter); + } + + public String getElement(StreamResult rt) { + String xml = rt.getWriter().toString(); + int beginIndex = xml.indexOf(START_TAG) + START_TAG.length(); + int endIndex = xml.indexOf(END_TAG); + return xml.substring(beginIndex, endIndex); + } + + public Source marshal(String n, ValidationEventHandler errorHandler) { + try { + String xml = START_TAG + n.trim() + END_TAG; + StringReader xmlReader = new StringReader(xml); + return new StreamSource(xmlReader); + } catch(Exception e) { + throw new RuntimeException(e); + } + } + +} diff --git a/opendaylight/config/config-persister-file-xml-adapter/src/main/java/org/opendaylight/controller/config/persist/storage/file/xml/model/Config.java b/opendaylight/config/config-persister-file-xml-adapter/src/main/java/org/opendaylight/controller/config/persist/storage/file/xml/model/Config.java new file mode 100644 index 0000000000..fb84651ca1 --- /dev/null +++ b/opendaylight/config/config-persister-file-xml-adapter/src/main/java/org/opendaylight/controller/config/persist/storage/file/xml/model/Config.java @@ -0,0 +1,109 @@ +/* + * Copyright (c) 2013 Cisco Systems, Inc. and others. All rights reserved. + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License v1.0 which accompanies this distribution, + * and is available at http://www.eclipse.org/legal/epl-v10.html + */ +package org.opendaylight.controller.config.persist.storage.file.xml.model; + +import com.google.common.base.Charsets; +import com.google.common.base.Optional; +import com.google.common.collect.Iterables; +import com.google.common.collect.Lists; +import com.google.common.io.Files; +import org.apache.commons.lang3.StringUtils; + +import javax.xml.bind.JAXBContext; +import javax.xml.bind.JAXBException; +import javax.xml.bind.Marshaller; +import javax.xml.bind.Unmarshaller; +import javax.xml.bind.annotation.XmlElement; +import javax.xml.bind.annotation.XmlElementWrapper; +import javax.xml.bind.annotation.XmlRootElement; +import java.io.File; +import java.io.IOException; +import java.util.List; + +@XmlRootElement(name = "persisted-snapshots") +public final class Config { + + private List snapshots; + + Config(List snapshots) { + this.snapshots = snapshots; + } + + public Config() { + this.snapshots = Lists.newArrayList(); + } + + @XmlElement(name = "snapshot") + @XmlElementWrapper(name = "snapshots") + public List getSnapshots() { + return snapshots; + } + + public void setSnapshots(List snapshots) { + this.snapshots = snapshots; + } + + public void toXml(File to) { + try { + + // TODO Moxy has to be used instead of default jaxb impl due to a bug + // default implementation has a bug that prevents from serializing xml in a string + JAXBContext jaxbContext = org.eclipse.persistence.jaxb.JAXBContextFactory.createContext(new Class[]{Config.class}, null); + + Marshaller marshaller = jaxbContext.createMarshaller(); + + marshaller.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, Boolean.TRUE); + + marshaller.marshal(this, to); + } catch (JAXBException e) { + throw new PersistException("Unable to persist configuration", e); + } + } + + public static Config fromXml(File from) { + if(isEmpty(from)) + return new Config(); + + try { + JAXBContext jaxbContext = JAXBContext.newInstance(Config.class); + Unmarshaller um = jaxbContext.createUnmarshaller(); + + return (Config) um.unmarshal(from); + } catch (JAXBException e) { + throw new PersistException("Unable to restore configuration", e); + } + } + + private static boolean isEmpty(File from) { + return from.length() == 0 || isBlank(from); + } + + private static boolean isBlank(File from) { + try { + return StringUtils.isBlank(Files.toString(from, Charsets.UTF_8)); + } catch (IOException e) { + throw new IllegalStateException("Unexpected error reading file" + from, e); + } + } + + public Optional getLastSnapshot() { + ConfigSnapshot last = Iterables.getLast(snapshots, null); + return last == null ? Optional.absent() : Optional.of(last); + } + + public void addConfigSnapshot(ConfigSnapshot snap, int numberOfStoredBackups) { + if(shouldReplaceLast(numberOfStoredBackups) && snapshots.isEmpty() == false) { + snapshots.remove(0); + } + snapshots.add(snap); + } + + private boolean shouldReplaceLast(int numberOfStoredBackups) { + return numberOfStoredBackups == snapshots.size(); + } +} diff --git a/opendaylight/config/config-persister-file-xml-adapter/src/main/java/org/opendaylight/controller/config/persist/storage/file/xml/model/ConfigSnapshot.java b/opendaylight/config/config-persister-file-xml-adapter/src/main/java/org/opendaylight/controller/config/persist/storage/file/xml/model/ConfigSnapshot.java new file mode 100644 index 0000000000..41976000ba --- /dev/null +++ b/opendaylight/config/config-persister-file-xml-adapter/src/main/java/org/opendaylight/controller/config/persist/storage/file/xml/model/ConfigSnapshot.java @@ -0,0 +1,63 @@ +/* + * Copyright (c) 2013 Cisco Systems, Inc. and others. All rights reserved. + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License v1.0 which accompanies this distribution, + * and is available at http://www.eclipse.org/legal/epl-v10.html + */ +package org.opendaylight.controller.config.persist.storage.file.xml.model; + +import org.opendaylight.controller.config.persist.api.ConfigSnapshotHolder; + +import javax.xml.bind.annotation.XmlAnyElement; +import javax.xml.bind.annotation.XmlElement; +import javax.xml.bind.annotation.XmlElementWrapper; +import javax.xml.bind.annotation.XmlRootElement; +import java.util.SortedSet; + +@XmlRootElement(name = "snapshot") +public class ConfigSnapshot { + + private String configSnapshot; + private SortedSet capabilities; + + ConfigSnapshot(String configXml, SortedSet capabilities) { + this.configSnapshot = configXml; + this.capabilities = capabilities; + } + + public ConfigSnapshot() { + } + + public static ConfigSnapshot fromConfigSnapshot(ConfigSnapshotHolder cfg) { + return new ConfigSnapshot(cfg.getConfigSnapshot(), cfg.getCapabilities()); + } + + @XmlAnyElement(SnapshotHandler.class) + public String getConfigSnapshot() { + return configSnapshot; + } + + public void setConfigSnapshot(String configSnapshot) { + this.configSnapshot = configSnapshot; + } + + @XmlElement(name = "capability") + @XmlElementWrapper(name = "required-capabilities") + public SortedSet getCapabilities() { + return capabilities; + } + + public void setCapabilities(SortedSet capabilities) { + this.capabilities = capabilities; + } + + @Override + public String toString() { + final StringBuffer sb = new StringBuffer("ConfigSnapshot{"); + sb.append("configSnapshot='").append(configSnapshot).append('\''); + sb.append(", capabilities=").append(capabilities); + sb.append('}'); + return sb.toString(); + } +} diff --git a/opendaylight/config/config-persister-file-xml-adapter/src/main/java/org/opendaylight/controller/config/persist/storage/file/xml/model/PersistException.java b/opendaylight/config/config-persister-file-xml-adapter/src/main/java/org/opendaylight/controller/config/persist/storage/file/xml/model/PersistException.java new file mode 100644 index 0000000000..29d623274c --- /dev/null +++ b/opendaylight/config/config-persister-file-xml-adapter/src/main/java/org/opendaylight/controller/config/persist/storage/file/xml/model/PersistException.java @@ -0,0 +1,15 @@ +/* + * Copyright (c) 2013 Cisco Systems, Inc. and others. All rights reserved. + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License v1.0 which accompanies this distribution, + * and is available at http://www.eclipse.org/legal/epl-v10.html + */ +package org.opendaylight.controller.config.persist.storage.file.xml.model; + +final class PersistException extends RuntimeException { + + public PersistException(String s, Exception e) { + super(s, e); + } +} diff --git a/opendaylight/config/config-persister-file-xml-adapter/src/main/java/org/opendaylight/controller/config/persist/storage/file/xml/model/SnapshotHandler.java b/opendaylight/config/config-persister-file-xml-adapter/src/main/java/org/opendaylight/controller/config/persist/storage/file/xml/model/SnapshotHandler.java new file mode 100644 index 0000000000..dd39410409 --- /dev/null +++ b/opendaylight/config/config-persister-file-xml-adapter/src/main/java/org/opendaylight/controller/config/persist/storage/file/xml/model/SnapshotHandler.java @@ -0,0 +1,47 @@ +/* + * Copyright (c) 2013 Cisco Systems, Inc. and others. All rights reserved. + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License v1.0 which accompanies this distribution, + * and is available at http://www.eclipse.org/legal/epl-v10.html + */ +package org.opendaylight.controller.config.persist.storage.file.xml.model; + +import javax.xml.bind.ValidationEventHandler; +import javax.xml.bind.annotation.DomHandler; +import javax.xml.transform.Source; +import javax.xml.transform.stream.StreamResult; +import javax.xml.transform.stream.StreamSource; +import java.io.StringReader; +import java.io.StringWriter; + +class SnapshotHandler implements DomHandler { + + private static final String START_TAG = ""; + private static final String END_TAG = ""; + + private StringWriter xmlWriter = new StringWriter(); + + public StreamResult createUnmarshaller(ValidationEventHandler errorHandler) { + xmlWriter.getBuffer().setLength(0); + return new StreamResult(xmlWriter); + } + + public String getElement(StreamResult rt) { + String xml = rt.getWriter().toString(); + int beginIndex = xml.indexOf(START_TAG) + START_TAG.length(); + int endIndex = xml.indexOf(END_TAG); + return xml.substring(beginIndex, endIndex); + } + + public Source marshal(String n, ValidationEventHandler errorHandler) { + try { + String xml = START_TAG + n.trim() + END_TAG; + StringReader xmlReader = new StringReader(xml); + return new StreamSource(xmlReader); + } catch(Exception e) { + throw new RuntimeException(e); + } + } + +} diff --git a/opendaylight/config/config-persister-file-xml-adapter/src/test/java/org/opendaylight/controller/config/persist/storage/file/xml/FileStorageAdapterTest.java b/opendaylight/config/config-persister-file-xml-adapter/src/test/java/org/opendaylight/controller/config/persist/storage/file/xml/FileStorageAdapterTest.java new file mode 100644 index 0000000000..d6bbeb31da --- /dev/null +++ b/opendaylight/config/config-persister-file-xml-adapter/src/test/java/org/opendaylight/controller/config/persist/storage/file/xml/FileStorageAdapterTest.java @@ -0,0 +1,188 @@ +/* + * Copyright (c) 2013 Cisco Systems, Inc. and others. All rights reserved. + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License v1.0 which accompanies this distribution, + * and is available at http://www.eclipse.org/legal/epl-v10.html + */ + +package org.opendaylight.controller.config.persist.storage.file.xml; + +import com.google.common.base.Charsets; +import junit.framework.Assert; +import org.junit.Before; +import org.junit.Test; +import org.mockito.Mockito; +import org.opendaylight.controller.config.persist.api.ConfigSnapshotHolder; + +import java.io.File; +import java.nio.file.Files; +import java.util.List; +import java.util.SortedSet; +import java.util.TreeSet; + +import static junit.framework.Assert.assertFalse; +import static org.hamcrest.CoreMatchers.is; +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertThat; + +public class FileStorageAdapterTest { + + private static int i; + private File file; + + @Before + public void setUp() throws Exception { + file = Files.createTempFile("testFilePersist", ".txt").toFile(); + if (!file.exists()) + return; + com.google.common.io.Files.write("", file, Charsets.UTF_8); + i = 1; + } + + @Test + public void testFileAdapter() throws Exception { + XmlFileStorageAdapter storage = new XmlFileStorageAdapter(); + storage.setFileStorage(file); + storage.setNumberOfBackups(Integer.MAX_VALUE); + final ConfigSnapshotHolder holder = new ConfigSnapshotHolder() { + @Override + public String getConfigSnapshot() { + return createConfig(); + } + + @Override + public SortedSet getCapabilities() { + return createCaps(); + } + }; + storage.persistConfig(holder); + + storage.persistConfig(holder); + + assertEquals(27, com.google.common.io.Files.readLines(file, Charsets.UTF_8).size()); + List lastConf = storage.loadLastConfigs(); + assertEquals(1, lastConf.size()); + ConfigSnapshotHolder configSnapshotHolder = lastConf.get(0); + assertEquals("2", + configSnapshotHolder.getConfigSnapshot().replaceAll("\\s", "")); + assertEquals(createCaps(), configSnapshotHolder.getCapabilities()); + + storage = new XmlFileStorageAdapter(); + storage.setFileStorage(file); + storage.setNumberOfBackups(Integer.MAX_VALUE); + + List last = storage.loadLastConfigs(); + Assert.assertEquals(createCaps(), last.get(0).getCapabilities()); + } + + private SortedSet createCaps() { + SortedSet caps = new TreeSet<>(); + + caps.add("cap1" + i); + caps.add("cap2" + i); + caps.add("urn:opendaylight:params:xml:ns:yang:controller:netty?module=netty&revision=2013-11-19" + i); + caps.add("capaaaa as dasfasdf s2" + i); + return caps; + } + + @Test + public void testFileAdapterOneBackup() throws Exception { + XmlFileStorageAdapter storage = new XmlFileStorageAdapter(); + storage.setFileStorage(file); + storage.setNumberOfBackups(1); + final ConfigSnapshotHolder holder = new ConfigSnapshotHolder() { + @Override + public String getConfigSnapshot() { + return createConfig(); + } + + @Override + public SortedSet getCapabilities() { + return createCaps(); + } + }; + storage.persistConfig(holder); + + storage.persistConfig(holder); + + assertEquals(16, com.google.common.io.Files.readLines(file, Charsets.UTF_8).size()); + + List lastConf = storage.loadLastConfigs(); + assertEquals(1, lastConf.size()); + ConfigSnapshotHolder configSnapshotHolder = lastConf.get(0); + assertEquals("2", + configSnapshotHolder.getConfigSnapshot().replaceAll("\\s", "")); + } + + @Test + public void testFileAdapterOnlyTwoBackups() throws Exception { + XmlFileStorageAdapter storage = new XmlFileStorageAdapter(); + storage.setFileStorage(file); + storage.setNumberOfBackups(2); + final ConfigSnapshotHolder holder = new ConfigSnapshotHolder() { + @Override + public String getConfigSnapshot() { + return createConfig(); + } + + @Override + public SortedSet getCapabilities() { + return createCaps(); + } + }; + storage.persistConfig(holder); + + storage.persistConfig(holder); + storage.persistConfig(holder); + + List readLines = com.google.common.io.Files.readLines(file, Charsets.UTF_8); + assertEquals(27, readLines.size()); + + List lastConf = storage.loadLastConfigs(); + assertEquals(1, lastConf.size()); + ConfigSnapshotHolder configSnapshotHolder = lastConf.get(0); + assertEquals("3", + configSnapshotHolder.getConfigSnapshot().replaceAll("\\s", "")); + assertFalse(readLines.contains(holder.getConfigSnapshot())); + } + + @Test + public void testNoLastConfig() throws Exception { + File file = Files.createTempFile("testFilePersist", ".txt").toFile(); + if (!file.exists()) + return; + XmlFileStorageAdapter storage = new XmlFileStorageAdapter(); + storage.setFileStorage(file); + + List elementOptional = storage.loadLastConfigs(); + assertThat(elementOptional.size(), is(0)); + } + + @Test(expected = NullPointerException.class) + public void testNoProperties() throws Exception { + XmlFileStorageAdapter storage = new XmlFileStorageAdapter(); + storage.loadLastConfigs(); + } + + @Test(expected = NullPointerException.class) + public void testNoProperties2() throws Exception { + XmlFileStorageAdapter storage = new XmlFileStorageAdapter(); + storage.persistConfig(new ConfigSnapshotHolder() { + @Override + public String getConfigSnapshot() { + return Mockito.mock(String.class); + } + + @Override + public SortedSet getCapabilities() { + return new TreeSet<>(); + } + } ); + } + + static String createConfig() { + return "" + i++ + ""; + } + +} diff --git a/opendaylight/config/config-util/src/main/java/org/opendaylight/controller/config/util/ConfigRegistryJMXClient.java b/opendaylight/config/config-util/src/main/java/org/opendaylight/controller/config/util/ConfigRegistryJMXClient.java index 4ecc7c3a5c..8badb75f05 100644 --- a/opendaylight/config/config-util/src/main/java/org/opendaylight/controller/config/util/ConfigRegistryJMXClient.java +++ b/opendaylight/config/config-util/src/main/java/org/opendaylight/controller/config/util/ConfigRegistryJMXClient.java @@ -7,10 +7,11 @@ */ package org.opendaylight.controller.config.util; -import java.util.Arrays; -import java.util.List; -import java.util.Map; -import java.util.Set; +import org.opendaylight.controller.config.api.ConflictingVersionException; +import org.opendaylight.controller.config.api.ValidationException; +import org.opendaylight.controller.config.api.jmx.CommitStatus; +import org.opendaylight.controller.config.api.jmx.ConfigRegistryMXBean; +import org.opendaylight.controller.config.api.jmx.ObjectNameUtil; import javax.management.AttributeNotFoundException; import javax.management.InstanceNotFoundException; @@ -21,12 +22,10 @@ import javax.management.MBeanServer; import javax.management.ObjectInstance; import javax.management.ObjectName; import javax.management.ReflectionException; - -import org.opendaylight.controller.config.api.ConflictingVersionException; -import org.opendaylight.controller.config.api.ValidationException; -import org.opendaylight.controller.config.api.jmx.CommitStatus; -import org.opendaylight.controller.config.api.jmx.ConfigRegistryMXBean; -import org.opendaylight.controller.config.api.jmx.ObjectNameUtil; +import java.util.Arrays; +import java.util.List; +import java.util.Map; +import java.util.Set; public class ConfigRegistryJMXClient implements ConfigRegistryClient { private final ConfigRegistryMXBean configRegistryMXBeanProxy; @@ -198,4 +197,8 @@ public class ConfigRegistryJMXClient implements ConfigRegistryClient { } } + @Override + public Set getAvailableModuleFactoryQNames() { + return configRegistryMXBeanProxy.getAvailableModuleFactoryQNames(); + } } diff --git a/opendaylight/config/config-util/src/main/java/org/opendaylight/controller/config/util/ConfigTransactionJMXClient.java b/opendaylight/config/config-util/src/main/java/org/opendaylight/controller/config/util/ConfigTransactionJMXClient.java index bd6f6fa884..0db1e5b822 100644 --- a/opendaylight/config/config-util/src/main/java/org/opendaylight/controller/config/util/ConfigTransactionJMXClient.java +++ b/opendaylight/config/config-util/src/main/java/org/opendaylight/controller/config/util/ConfigTransactionJMXClient.java @@ -233,4 +233,9 @@ public class ConfigTransactionJMXClient implements ConfigTransactionClient { + attrName + " for " + on, e); } } + + @Override + public Set getAvailableModuleFactoryQNames() { + return configTransactionControllerMXBeanProxy.getAvailableModuleFactoryQNames(); + } } diff --git a/opendaylight/config/config-util/src/test/java/org/opendaylight/controller/config/util/TestingConfigRegistry.java b/opendaylight/config/config-util/src/test/java/org/opendaylight/controller/config/util/TestingConfigRegistry.java index ba6262780c..65341714df 100644 --- a/opendaylight/config/config-util/src/test/java/org/opendaylight/controller/config/util/TestingConfigRegistry.java +++ b/opendaylight/config/config-util/src/test/java/org/opendaylight/controller/config/util/TestingConfigRegistry.java @@ -173,4 +173,9 @@ public class TestingConfigRegistry implements ConfigRegistryMXBean { public String getServiceInterfaceName(String namespace, String localName) { throw new UnsupportedOperationException(); } + + @Override + public Set getAvailableModuleFactoryQNames() { + throw new UnsupportedOperationException(); + } } diff --git a/opendaylight/config/config-util/src/test/java/org/opendaylight/controller/config/util/TestingConfigTransactionController.java b/opendaylight/config/config-util/src/test/java/org/opendaylight/controller/config/util/TestingConfigTransactionController.java index 1c522f17b0..44eb73af79 100644 --- a/opendaylight/config/config-util/src/test/java/org/opendaylight/controller/config/util/TestingConfigTransactionController.java +++ b/opendaylight/config/config-util/src/test/java/org/opendaylight/controller/config/util/TestingConfigTransactionController.java @@ -160,4 +160,9 @@ public class TestingConfigTransactionController implements public boolean removeServiceReferences(ObjectName objectName) throws InstanceNotFoundException { throw new UnsupportedOperationException(); } + + @Override + public Set getAvailableModuleFactoryQNames() { + throw new UnsupportedOperationException(); + } } diff --git a/opendaylight/config/pom.xml b/opendaylight/config/pom.xml index 9f0145fffe..eba5e07c0f 100644 --- a/opendaylight/config/pom.xml +++ b/opendaylight/config/pom.xml @@ -26,6 +26,7 @@ config-util config-persister-api config-persister-file-adapter + config-persister-file-xml-adapter yang-jmx-generator yang-jmx-generator-plugin yang-store-api @@ -39,6 +40,7 @@ netty-event-executor-config netty-timer-config config-persister-directory-adapter + config-persister-directory-xml-adapter yang-test-plugin diff --git a/opendaylight/config/yang-jmx-generator-plugin/src/main/java/org/opendaylight/controller/config/yangjmxgenerator/plugin/ftl/AbstractFactoryTemplate.java b/opendaylight/config/yang-jmx-generator-plugin/src/main/java/org/opendaylight/controller/config/yangjmxgenerator/plugin/ftl/AbstractFactoryTemplate.java index 47b68ebf9a..35dc7a3600 100644 --- a/opendaylight/config/yang-jmx-generator-plugin/src/main/java/org/opendaylight/controller/config/yangjmxgenerator/plugin/ftl/AbstractFactoryTemplate.java +++ b/opendaylight/config/yang-jmx-generator-plugin/src/main/java/org/opendaylight/controller/config/yangjmxgenerator/plugin/ftl/AbstractFactoryTemplate.java @@ -14,6 +14,7 @@ import org.opendaylight.controller.config.api.ModuleIdentifier; import org.opendaylight.controller.config.api.annotations.AbstractServiceInterface; import org.opendaylight.controller.config.spi.Module; import org.opendaylight.controller.config.spi.ModuleFactory; +import org.opendaylight.controller.config.yangjmxgenerator.ModuleMXBeanEntry; import org.opendaylight.controller.config.yangjmxgenerator.plugin.ftl.model.Constructor; import org.opendaylight.controller.config.yangjmxgenerator.plugin.ftl.model.Field; import org.opendaylight.controller.config.yangjmxgenerator.plugin.ftl.model.Header; @@ -33,11 +34,12 @@ public class AbstractFactoryTemplate extends GeneralClassTemplate { private final String globallyUniqueName, moduleInstanceType; private final List providedServices; + private final ModuleMXBeanEntry mbe; public AbstractFactoryTemplate(Header header, String packageName, - String abstractFactoryName, String globallyUniqueName, - String moduleInstanceType, List fields, - List providedServices) { + String abstractFactoryName, String globallyUniqueName, + String moduleInstanceType, List fields, + List providedServices, ModuleMXBeanEntry mbe) { super(header, packageName, abstractFactoryName, Collections . emptyList(), implementedIfcs, fields, Collections . emptyList(), true, false, Collections @@ -45,6 +47,7 @@ public class AbstractFactoryTemplate extends GeneralClassTemplate { this.globallyUniqueName = globallyUniqueName; this.moduleInstanceType = moduleInstanceType; this.providedServices = providedServices; + this.mbe = mbe; } public String getGloballyUniqueName() { @@ -92,4 +95,7 @@ public class AbstractFactoryTemplate extends GeneralClassTemplate { return "factory_abs_template.ftl"; } + public ModuleMXBeanEntry getMbe() { + return mbe; + } } diff --git a/opendaylight/config/yang-jmx-generator-plugin/src/main/java/org/opendaylight/controller/config/yangjmxgenerator/plugin/ftl/TemplateFactory.java b/opendaylight/config/yang-jmx-generator-plugin/src/main/java/org/opendaylight/controller/config/yangjmxgenerator/plugin/ftl/TemplateFactory.java index 115bb85b61..28e0256c05 100644 --- a/opendaylight/config/yang-jmx-generator-plugin/src/main/java/org/opendaylight/controller/config/yangjmxgenerator/plugin/ftl/TemplateFactory.java +++ b/opendaylight/config/yang-jmx-generator-plugin/src/main/java/org/opendaylight/controller/config/yangjmxgenerator/plugin/ftl/TemplateFactory.java @@ -210,8 +210,7 @@ public class TemplateFactory { sieTemplate.getAnnotations().add( Annotation.createDescriptionAnnotation(sie .getNullableDescription())); - sieTemplate.getAnnotations().add(Annotation.createSieAnnotation(sie.getQName(), sie.getExportedOsgiClassName - ())); + sieTemplate.getAnnotations().addAll(Annotation.createSieAnnotations(sie)); return sieTemplate; } @@ -236,7 +235,7 @@ public class TemplateFactory { mbe.getPackageName(), mbe.getAbstractFactoryName(), mbe.getGloballyUniqueName(), mbe.getFullyQualifiedName(mbe .getStubModuleName()), attrProcessor.getFields(), - Lists.newArrayList(transformed)); + Lists.newArrayList(transformed), mbe); } public static AbstractModuleTemplate abstractModuleTemplateFromMbe( diff --git a/opendaylight/config/yang-jmx-generator-plugin/src/main/java/org/opendaylight/controller/config/yangjmxgenerator/plugin/ftl/model/Annotation.java b/opendaylight/config/yang-jmx-generator-plugin/src/main/java/org/opendaylight/controller/config/yangjmxgenerator/plugin/ftl/model/Annotation.java index 59368e8e49..7cf241725d 100644 --- a/opendaylight/config/yang-jmx-generator-plugin/src/main/java/org/opendaylight/controller/config/yangjmxgenerator/plugin/ftl/model/Annotation.java +++ b/opendaylight/config/yang-jmx-generator-plugin/src/main/java/org/opendaylight/controller/config/yangjmxgenerator/plugin/ftl/model/Annotation.java @@ -7,13 +7,15 @@ */ package org.opendaylight.controller.config.yangjmxgenerator.plugin.ftl.model; +import java.util.ArrayList; +import java.util.Collection; import java.util.List; import org.opendaylight.controller.config.api.annotations.Description; import org.opendaylight.controller.config.api.annotations.RequireInterface; import org.opendaylight.controller.config.api.annotations.ServiceInterfaceAnnotation; +import org.opendaylight.yangtools.yang.binding.annotations.ModuleQName; import org.opendaylight.controller.config.yangjmxgenerator.ServiceInterfaceEntry; -import org.opendaylight.yangtools.yang.common.QName; import com.google.common.base.Preconditions; import com.google.common.collect.Lists; @@ -42,22 +44,36 @@ public class Annotation { Lists.newArrayList(new Parameter("value", q(description)))); } - public static Annotation createSieAnnotation(QName qname, - String exportedClassName) { - Preconditions.checkNotNull(qname, + public static Collection createSieAnnotations(ServiceInterfaceEntry sie){ + + String exportedClassName = sie.getExportedOsgiClassName(); + Preconditions.checkNotNull(sie.getQName(), "Cannot create annotation from null qname"); Preconditions.checkNotNull(exportedClassName, "Cannot create annotation from null exportedClassName"); + List result = new ArrayList<>(); + { + List params = Lists.newArrayList(new Parameter("value", q(sie.getQName().toString()))); + params.add(new Parameter("osgiRegistrationType", exportedClassName + ".class")); - List params = Lists.newArrayList(new Parameter("value", q(qname.toString()))); - params.add(new Parameter("osgiRegistrationType", exportedClassName + ".class")); + params.add(new Parameter("namespace", q(sie.getQName().getNamespace().toString()))); + params.add(new Parameter("revision", q(sie.getQName().getFormattedRevision()))); + params.add(new Parameter("localName", q(sie.getQName().getLocalName()))); - params.add(new Parameter("namespace", q(qname.getNamespace().toString()))); - params.add(new Parameter("revision", q(qname.getFormattedRevision()))); - params.add(new Parameter("localName", q(qname.getLocalName()))); + Annotation sieAnnotation = new Annotation(ServiceInterfaceAnnotation.class.getCanonicalName(), params); + result.add(sieAnnotation); - return new Annotation( - ServiceInterfaceAnnotation.class.getCanonicalName(), params); + } + { + List params = new ArrayList<>(); + params.add(new Parameter("namespace", q(sie.getYangModuleQName().getNamespace().toString()))); + params.add(new Parameter("revision", q(sie.getYangModuleQName().getFormattedRevision()))); + params.add(new Parameter("name", q(sie.getYangModuleQName().getLocalName()))); + + Annotation moduleQNameAnnotation = new Annotation(ModuleQName.class.getCanonicalName(), params); + result.add(moduleQNameAnnotation); + } + return result; } public static Annotation createRequireIfcAnnotation( diff --git a/opendaylight/config/yang-jmx-generator-plugin/src/main/resources/freeMarker/factory_abs_template.ftl b/opendaylight/config/yang-jmx-generator-plugin/src/main/resources/freeMarker/factory_abs_template.ftl index 37fd05bc52..b9bbf1f1b5 100644 --- a/opendaylight/config/yang-jmx-generator-plugin/src/main/resources/freeMarker/factory_abs_template.ftl +++ b/opendaylight/config/yang-jmx-generator-plugin/src/main/resources/freeMarker/factory_abs_template.ftl @@ -2,6 +2,7 @@ package ${packageName}; <@javadocD object=javadoc/> +@org.opendaylight.yangtools.yang.binding.annotations.ModuleQName(namespace="${mbe.getYangModuleQName().getNamespace().toString()}",revision="${mbe.getYangModuleQName().getFormattedRevision()}",name="${mbe.getYangModuleQName().getLocalName()}") <@typeDeclarationD object=typeDeclaration/> { diff --git a/opendaylight/config/yang-jmx-generator/pom.xml b/opendaylight/config/yang-jmx-generator/pom.xml index c312cc8493..c66b112566 100644 --- a/opendaylight/config/yang-jmx-generator/pom.xml +++ b/opendaylight/config/yang-jmx-generator/pom.xml @@ -57,6 +57,10 @@ commons-lang3 test + + org.opendaylight.yangtools + binding-type-provider + diff --git a/opendaylight/config/yang-jmx-generator/src/main/java/org/opendaylight/controller/config/yangjmxgenerator/ModuleMXBeanEntry.java b/opendaylight/config/yang-jmx-generator/src/main/java/org/opendaylight/controller/config/yangjmxgenerator/ModuleMXBeanEntry.java index 4eba739b46..869488e777 100644 --- a/opendaylight/config/yang-jmx-generator/src/main/java/org/opendaylight/controller/config/yangjmxgenerator/ModuleMXBeanEntry.java +++ b/opendaylight/config/yang-jmx-generator/src/main/java/org/opendaylight/controller/config/yangjmxgenerator/ModuleMXBeanEntry.java @@ -136,11 +136,13 @@ public class ModuleMXBeanEntry extends AbstractEntry { private final Map providedServices; private Collection runtimeBeans; + private final QName yangModuleQName; public ModuleMXBeanEntry(IdentitySchemaNode id, Map yangToAttributes, String packageName, Map providedServices2, String javaNamePrefix, - String namespace, Collection runtimeBeans) { + String namespace, Collection runtimeBeans, + QName yangModuleQName) { this.globallyUniqueName = id.getQName().getLocalName(); this.yangToAttributes = yangToAttributes; this.nullableDescription = id.getDescription(); @@ -149,6 +151,7 @@ public class ModuleMXBeanEntry extends AbstractEntry { this.namespace = checkNotNull(namespace); this.providedServices = Collections.unmodifiableMap(providedServices2); this.runtimeBeans = runtimeBeans; + this.yangModuleQName = yangModuleQName; } public String getMXBeanInterfaceName() { @@ -395,7 +398,8 @@ public class ModuleMXBeanEntry extends AbstractEntry { moduleIdentity, yangToAttributes, packageName, providedServices, javaNamePrefix, currentModule .getNamespace().toString(), - runtimeBeans); + runtimeBeans, + ModuleUtil.getQName(currentModule)); moduleMXBeanEntry.setYangModuleName(currentModule .getName()); moduleMXBeanEntry @@ -730,6 +734,10 @@ public class ModuleMXBeanEntry extends AbstractEntry { return nullableDescription; } + public QName getYangModuleQName() { + return yangModuleQName; + } + @Override public String toString() { return "ModuleMXBeanEntry{" + "globallyUniqueName='" diff --git a/opendaylight/config/yang-jmx-generator/src/main/java/org/opendaylight/controller/config/yangjmxgenerator/ModuleUtil.java b/opendaylight/config/yang-jmx-generator/src/main/java/org/opendaylight/controller/config/yangjmxgenerator/ModuleUtil.java new file mode 100644 index 0000000000..5fea8fd078 --- /dev/null +++ b/opendaylight/config/yang-jmx-generator/src/main/java/org/opendaylight/controller/config/yangjmxgenerator/ModuleUtil.java @@ -0,0 +1,18 @@ +/* + * Copyright (c) 2013 Cisco Systems, Inc. and others. All rights reserved. + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License v1.0 which accompanies this distribution, + * and is available at http://www.eclipse.org/legal/epl-v10.html + */ +package org.opendaylight.controller.config.yangjmxgenerator; + +import org.opendaylight.yangtools.yang.common.QName; +import org.opendaylight.yangtools.yang.model.api.Module; + +public class ModuleUtil { + + public static QName getQName(Module currentModule){ + return new QName(currentModule.getNamespace(), currentModule.getRevision(), currentModule.getName()); + } +} diff --git a/opendaylight/config/yang-jmx-generator/src/main/java/org/opendaylight/controller/config/yangjmxgenerator/ServiceInterfaceEntry.java b/opendaylight/config/yang-jmx-generator/src/main/java/org/opendaylight/controller/config/yangjmxgenerator/ServiceInterfaceEntry.java index 71cd0900eb..aa2d6a5d7f 100644 --- a/opendaylight/config/yang-jmx-generator/src/main/java/org/opendaylight/controller/config/yangjmxgenerator/ServiceInterfaceEntry.java +++ b/opendaylight/config/yang-jmx-generator/src/main/java/org/opendaylight/controller/config/yangjmxgenerator/ServiceInterfaceEntry.java @@ -57,13 +57,14 @@ public class ServiceInterfaceEntry extends AbstractEntry { private final String exportedOsgiClassName; private final QName qName; private final String nullableDescription, packageName, typeName; + private final QName yangModuleQName; - private ServiceInterfaceEntry(IdentitySchemaNode id, String packageName) { - this(Optional. absent(), id, packageName); + private ServiceInterfaceEntry(IdentitySchemaNode id, String packageName, QName yangModuleQName) { + this(Optional. absent(), id, packageName, yangModuleQName); } private ServiceInterfaceEntry(Optional base, - IdentitySchemaNode id, String packageName) { + IdentitySchemaNode id, String packageName, QName yangModuleQName) { checkNotNull(base); this.maybeBaseCache = base; List unknownSchemaNodes = id.getUnknownSchemaNodes(); @@ -93,6 +94,7 @@ public class ServiceInterfaceEntry extends AbstractEntry { nullableDescription = id.getDescription(); typeName = getSimpleName(exportedOsgiClassName) + CLASS_NAME_SUFFIX; this.packageName = packageName; + this.yangModuleQName = yangModuleQName; } private static final String getSimpleName(String fullyQualifiedName) { @@ -120,14 +122,14 @@ public class ServiceInterfaceEntry extends AbstractEntry { * @return Map of QNames as keys and ServiceInterfaceEntry instances as * values */ - public static Map create(Module module, + public static Map create(Module currentModule, String packageName) { logger.debug("Generating ServiceInterfaces from {} to package {}", - module.getNamespace(), packageName); + currentModule.getNamespace(), packageName); Map identitiesToSIs = new HashMap<>(); Set notVisited = new HashSet<>( - module.getIdentities()); + currentModule.getIdentities()); int lastSize = notVisited.size() + 1; while (notVisited.size() > 0) { if (notVisited.size() == lastSize) { @@ -148,18 +150,18 @@ public class ServiceInterfaceEntry extends AbstractEntry { } else if (identity.getBaseIdentity().getQName() .equals(SERVICE_TYPE_Q_NAME)) { // this is a base type - created = new ServiceInterfaceEntry(identity, packageName); + created = new ServiceInterfaceEntry(identity, packageName, ModuleUtil.getQName(currentModule)); } else { ServiceInterfaceEntry foundBase = identitiesToSIs .get(identity.getBaseIdentity()); // derived type, did we convert the parent? if (foundBase != null) { created = new ServiceInterfaceEntry( - Optional.of(foundBase), identity, packageName); + Optional.of(foundBase), identity, packageName, ModuleUtil.getQName(currentModule)); } } if (created != null) { - created.setYangModuleName(module.getName()); + created.setYangModuleName(currentModule.getName()); // TODO how to get local name created.setYangModuleLocalname(identity.getQName() .getLocalName()); @@ -190,6 +192,10 @@ public class ServiceInterfaceEntry extends AbstractEntry { return typeName; } + public QName getYangModuleQName() { + return yangModuleQName; + } + @Override public boolean equals(Object o) { if (this == o) diff --git a/opendaylight/config/yang-jmx-generator/src/main/java/org/opendaylight/controller/config/yangjmxgenerator/TypeProviderWrapper.java b/opendaylight/config/yang-jmx-generator/src/main/java/org/opendaylight/controller/config/yangjmxgenerator/TypeProviderWrapper.java index 764ecd3886..c43fead0fc 100644 --- a/opendaylight/config/yang-jmx-generator/src/main/java/org/opendaylight/controller/config/yangjmxgenerator/TypeProviderWrapper.java +++ b/opendaylight/config/yang-jmx-generator/src/main/java/org/opendaylight/controller/config/yangjmxgenerator/TypeProviderWrapper.java @@ -64,4 +64,8 @@ public class TypeProviderWrapper { public String getJMXParamForBaseType(TypeDefinition baseType) { return typeProvider.getConstructorPropertyName(baseType); } + + public String getJMXParamForUnionInnerType(TypeDefinition unionInnerType) { + return typeProvider.getParamNameFromType(unionInnerType); + } } diff --git a/opendaylight/config/yang-jmx-generator/src/main/java/org/opendaylight/controller/config/yangjmxgenerator/attribute/JavaAttribute.java b/opendaylight/config/yang-jmx-generator/src/main/java/org/opendaylight/controller/config/yangjmxgenerator/attribute/JavaAttribute.java index 3e20e4a55a..e01063ef92 100644 --- a/opendaylight/config/yang-jmx-generator/src/main/java/org/opendaylight/controller/config/yangjmxgenerator/attribute/JavaAttribute.java +++ b/opendaylight/config/yang-jmx-generator/src/main/java/org/opendaylight/controller/config/yangjmxgenerator/attribute/JavaAttribute.java @@ -7,20 +7,26 @@ */ package org.opendaylight.controller.config.yangjmxgenerator.attribute; +import com.google.common.base.Preconditions; import org.opendaylight.controller.config.yangjmxgenerator.TypeProviderWrapper; import org.opendaylight.yangtools.sal.binding.model.api.Type; import org.opendaylight.yangtools.yang.model.api.LeafListSchemaNode; import org.opendaylight.yangtools.yang.model.api.LeafSchemaNode; import org.opendaylight.yangtools.yang.model.api.TypeDefinition; +import org.opendaylight.yangtools.yang.model.api.type.UnionTypeDefinition; import javax.management.openmbean.ArrayType; import javax.management.openmbean.CompositeType; import javax.management.openmbean.OpenDataException; import javax.management.openmbean.OpenType; import javax.management.openmbean.SimpleType; +import java.util.Arrays; +import java.util.List; public class JavaAttribute extends AbstractAttribute implements TypedAttribute { + public static final String DESCRIPTION_OF_VALUE_ATTRIBUTE_FOR_UNION = "valueOfArtificialUnionProperty"; + private final Type type; private final String nullableDescription, nullableDefault, nullableDefaultWrappedForCode; private final TypeProviderWrapper typeProviderWrapper; @@ -47,6 +53,11 @@ public class JavaAttribute extends AbstractAttribute implements TypedAttribute { this.nullableDescription = leaf.getDescription(); } + public boolean isUnion() { + TypeDefinition base = getBaseType(typeProviderWrapper, typeDefinition); + return base instanceof UnionTypeDefinition; + } + public TypeDefinition getTypeDefinition() { return typeDefinition; } @@ -132,13 +143,70 @@ public class JavaAttribute extends AbstractAttribute implements TypedAttribute { return getArrayType(); } else if (isEnum(baseType)) { return getSimpleType(baseType); - } else if (isDerivedType(baseType)) { + } else if (isUnion()) { + return getCompositeTypeForUnion(baseTypeDefinition); + } else if (isDerivedType(baseType, getType())) { return getCompositeType(baseType, baseTypeDefinition); } return getSimpleType(getType()); } + private OpenType getCompositeTypeForUnion(TypeDefinition baseTypeDefinition) { + Preconditions.checkArgument(baseTypeDefinition instanceof UnionTypeDefinition, + "Expected %s instance but was %s", UnionTypeDefinition.class, baseTypeDefinition); + + List> types = ((UnionTypeDefinition) baseTypeDefinition).getTypes(); + + String[] itemNames = new String[types.size()+1]; + OpenType[] itemTypes = new OpenType[itemNames.length]; + + addArtificialPropertyToUnionCompositeType(baseTypeDefinition, itemNames, itemTypes); + + String description = getNullableDescription() == null ? getAttributeYangName() : getNullableDescription(); + + int i = 1; + for (TypeDefinition innerTypeDefinition : types) { + + Type innerType = typeProviderWrapper.getType(innerTypeDefinition, innerTypeDefinition); + + TypeDefinition baseInnerTypeDefinition = getBaseType(typeProviderWrapper, innerTypeDefinition); + Type innerTypeBaseType = typeProviderWrapper.getType(baseInnerTypeDefinition, baseInnerTypeDefinition); + + OpenType innerCompositeType; + + if(isDerivedType(innerTypeBaseType, innerType)) { + innerCompositeType = getCompositeType(innerTypeBaseType, baseInnerTypeDefinition); + } else { + innerCompositeType = SimpleTypeResolver.getSimpleType(innerType); + } + + itemNames[i] = typeProviderWrapper.getJMXParamForUnionInnerType(innerTypeDefinition); + itemTypes[i++] = innerCompositeType; + } + + String[] descriptions = Arrays.copyOf(itemNames, itemNames.length); + descriptions[0] = DESCRIPTION_OF_VALUE_ATTRIBUTE_FOR_UNION; + + try { + return new CompositeType(getUpperCaseCammelCase(), description, itemNames, descriptions, itemTypes); + } catch (OpenDataException e) { + throw new RuntimeException("Unable to create " + CompositeType.class + " with inner elements " + + Arrays.toString(itemTypes), e); + } + } + + public static final Class TYPE_OF_ARTIFICIAL_UNION_PROPERTY = char.class; + + private void addArtificialPropertyToUnionCompositeType(TypeDefinition baseTypeDefinition, String[] itemNames, OpenType[] itemTypes) { + String artificialPropertyName = typeProviderWrapper.getJMXParamForBaseType(baseTypeDefinition); + itemNames[0] = artificialPropertyName; + + OpenType artificialPropertyType = getArrayOpenTypeForSimpleType(TYPE_OF_ARTIFICIAL_UNION_PROPERTY.getName(), + SimpleTypeResolver.getSimpleType(TYPE_OF_ARTIFICIAL_UNION_PROPERTY.getName())); + itemTypes[0] = artificialPropertyType; + } + private boolean isEnum(Type baseType) { return baseType.getFullyQualifiedName().equals(Enum.class.getName()); } @@ -163,12 +231,15 @@ public class JavaAttribute extends AbstractAttribute implements TypedAttribute { throw new RuntimeException("Unable to create " + CompositeType.class + " with inner element of type " + itemTypes, e); } - } private OpenType getArrayType() { String innerTypeFullyQName = getInnerType(getType()); SimpleType innerSimpleType = SimpleTypeResolver.getSimpleType(innerTypeFullyQName); + return getArrayOpenTypeForSimpleType(innerTypeFullyQName, innerSimpleType); + } + + private OpenType getArrayOpenTypeForSimpleType(String innerTypeFullyQName, SimpleType innerSimpleType) { try { ArrayType arrayType = isPrimitive(innerTypeFullyQName) ? new ArrayType<>(innerSimpleType, true) : new ArrayType<>(1, innerSimpleType); @@ -191,8 +262,8 @@ public class JavaAttribute extends AbstractAttribute implements TypedAttribute { return type.getName().endsWith("[]"); } - private boolean isDerivedType(Type baseType) { - return baseType.equals(getType()) == false; + private boolean isDerivedType(Type baseType, Type currentType) { + return baseType.equals(currentType) == false; } private static String getInnerType(Type type) { diff --git a/opendaylight/config/yang-jmx-generator/src/main/java/org/opendaylight/controller/config/yangjmxgenerator/attribute/SimpleTypeResolver.java b/opendaylight/config/yang-jmx-generator/src/main/java/org/opendaylight/controller/config/yangjmxgenerator/attribute/SimpleTypeResolver.java index 87b55f3756..f4bd979fac 100644 --- a/opendaylight/config/yang-jmx-generator/src/main/java/org/opendaylight/controller/config/yangjmxgenerator/attribute/SimpleTypeResolver.java +++ b/opendaylight/config/yang-jmx-generator/src/main/java/org/opendaylight/controller/config/yangjmxgenerator/attribute/SimpleTypeResolver.java @@ -59,6 +59,8 @@ public class SimpleTypeResolver { JAVA_TYPE_TO_SIMPLE_TYPE.put(Date.class.getName(), SimpleType.DATE); JAVA_TYPE_TO_SIMPLE_TYPE.put(Double.class.getName(), SimpleType.DOUBLE); JAVA_TYPE_TO_SIMPLE_TYPE.put(double.class.getName(), SimpleType.DOUBLE); + + JAVA_TYPE_TO_SIMPLE_TYPE.put(char.class.getName(), SimpleType.CHARACTER); } } diff --git a/opendaylight/config/yang-test/src/main/java/org/opendaylight/yang/gen/v1/urn/opendaylight/params/xml/ns/yang/controller/config/test/types/rev131127/UnionTestBuilder.java b/opendaylight/config/yang-test/src/main/java/org/opendaylight/yang/gen/v1/urn/opendaylight/params/xml/ns/yang/controller/config/test/types/rev131127/UnionTestBuilder.java new file mode 100644 index 0000000000..c49319be9f --- /dev/null +++ b/opendaylight/config/yang-test/src/main/java/org/opendaylight/yang/gen/v1/urn/opendaylight/params/xml/ns/yang/controller/config/test/types/rev131127/UnionTestBuilder.java @@ -0,0 +1,24 @@ +/* + * Copyright (c) 2013 Cisco Systems, Inc. and others. All rights reserved. + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License v1.0 which accompanies this distribution, + * and is available at http://www.eclipse.org/legal/epl-v10.html + */ +package org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.controller.config.test.types.rev131127; + + +/** +**/ +public class UnionTestBuilder { + + public static UnionTest getDefaultInstance(String defaultValue) { + try { + int i = Integer.valueOf(defaultValue); + return new UnionTest(new ExtendTwice(i)); + } catch (NumberFormatException e) { + return new UnionTest(defaultValue); + } + } + +} diff --git a/opendaylight/config/yang-test/src/main/yang/config-test-impl.yang b/opendaylight/config/yang-test/src/main/yang/config-test-impl.yang index 9ad7a44915..f7cea0a52a 100644 --- a/opendaylight/config/yang-test/src/main/yang/config-test-impl.yang +++ b/opendaylight/config/yang-test/src/main/yang/config-test-impl.yang @@ -61,10 +61,6 @@ module config-test-impl { default 127.0.0.1; } - leaf ip { - type inet:ip-address; - // TODO defaults for union default 0:0:0:0:0:0:0:1; - } } leaf as-number { @@ -136,6 +132,16 @@ module config-test-impl { default ONE; } + leaf ip { + type inet:ip-address; + default 0:0:0:0:0:0:0:1; + } + + leaf union-test-attr { + type tt:unionTest; + default 456; + } + leaf sleep-factor { type decimal64 { fraction-digits 2; diff --git a/opendaylight/config/yang-test/src/main/yang/types/test-types.yang b/opendaylight/config/yang-test/src/main/yang/types/test-types.yang index 84fbcb089d..8c086d8ace 100644 --- a/opendaylight/config/yang-test/src/main/yang/types/test-types.yang +++ b/opendaylight/config/yang-test/src/main/yang/types/test-types.yang @@ -23,4 +23,12 @@ module test-types { } } + typedef unionTest { + type union { + type string; + type uint32; + type extend-twice; + } + } + } diff --git a/opendaylight/distribution/opendaylight/pom.xml b/opendaylight/distribution/opendaylight/pom.xml index 4296048049..35e160e827 100644 --- a/opendaylight/distribution/opendaylight/pom.xml +++ b/opendaylight/distribution/opendaylight/pom.xml @@ -223,11 +223,21 @@ config-persister-file-adapter ${config.version} - - org.opendaylight.controller - config-persister-directory-adapter - ${config.version} - + + org.opendaylight.controller + config-persister-file-xml-adapter + ${config.version} + + + org.opendaylight.controller + config-persister-directory-adapter + ${config.version} + + + org.opendaylight.controller + config-persister-directory-xml-adapter + ${config.version} + @@ -466,7 +476,6 @@ - integrationtests false @@ -475,41 +484,57 @@ org.apache.maven.plugins - maven-invoker-plugin - 1.5 + maven-dependency-plugin + 2.8 + + + copy + package + + copy + + + - false - ../sanitytest - - pom.xml - - true - true - - clean - verify - - - - - integration-test - - install - run - - - - + + + org.opendaylight.controller + sanitytest + ${controller.version} + jar + + + + + + org.codehaus.mojo + exec-maven-plugin + 1.2.1 + + + sanity-test + package + + exec + + + + + ${java.home}/bin/java + + -cp + ./target/dependency/* + org.opendaylight.controller.distribution.Sanity + + + + ${java.home} + + + + - - - - org.opendaylight.controller - controller-maven-plugin - 0.1.0-SNAPSHOT - - @@ -1337,6 +1362,13 @@ ${commons.httpclient.version} + + org.opendaylight.controller + sanitytest + ${controller.version} + + + @@ -1379,8 +1411,6 @@ - - diff --git a/opendaylight/distribution/opendaylight/runsanity.bat b/opendaylight/distribution/opendaylight/runsanity.bat new file mode 100644 index 0000000000..f219828bad --- /dev/null +++ b/opendaylight/distribution/opendaylight/runsanity.bat @@ -0,0 +1,23 @@ +rem Inject the sanitytest jar as a controller plugin +copy .\target\dependency\sanitytest*.jar .\target\distribution.opendaylight-osgipackage\opendaylight\plugins + +rem Store the current working directory in a variable so that we can get back to it later +set cwd=%cd% + +rem Switch to the distribution folder +cd .\target\distribution.opendaylight-osgipackage\opendaylight + +rem Run the controller +cmd.exe /c run.bat + +rem Store the exit value of the controller in a variable +set success=%ERRORLEVEL% + +rem Switch back to the directory from which this script was invoked +cd %cwd% + +rem Remove the sanitytest jar from the plugins directory +del .\target\distribution.opendaylight-osgipackage\opendaylight\plugins\sanitytest*.jar + +rem Exit using the exit code that we had captured earlier after running the controller +exit /b %SUCCESS% \ No newline at end of file diff --git a/opendaylight/distribution/opendaylight/runsanity.sh b/opendaylight/distribution/opendaylight/runsanity.sh new file mode 100755 index 0000000000..4ee9555b97 --- /dev/null +++ b/opendaylight/distribution/opendaylight/runsanity.sh @@ -0,0 +1,24 @@ +# Inject the sanitytest jar as a controller plugin +cp ./target/dependency/sanitytest*.jar ./target/distribution.opendaylight-osgipackage/opendaylight/plugins + +# Store the current working directory in a variable so that we can get back to it later +cwd=`pwd` + +# Switch to the distribution folder +cd ./target/distribution.opendaylight-osgipackage/opendaylight/ + +# Run the controller +./run.sh + +# Store the exit value of the controller in a variable +success=`echo $?` + +# Switch back to the directory from which this script was invoked +cd $cwd + +# Remove the sanitytest jar from the plugins directory +rm ./target/distribution.opendaylight-osgipackage/opendaylight/plugins/sanitytest*.jar + +# Exit using the exit code that we had captured earlier after running the controller +exit $success + diff --git a/opendaylight/distribution/opendaylight/src/assemble/bin.xml b/opendaylight/distribution/opendaylight/src/assemble/bin.xml index 1e8f34e5b7..8fea175614 100644 --- a/opendaylight/distribution/opendaylight/src/assemble/bin.xml +++ b/opendaylight/distribution/opendaylight/src/assemble/bin.xml @@ -27,6 +27,7 @@ com.sun.jersey:jersey-json com.sun.jersey:jersey-server org.opendaylight.controller:logging.bridge + org.opendaylight.controller:sanitytest ${artifact.groupId}.${artifact.artifactId}-${artifact.version}${dashClassifier?}.${artifact.extension} diff --git a/opendaylight/distribution/opendaylight/src/main/resources/configuration/config.ini b/opendaylight/distribution/opendaylight/src/main/resources/configuration/config.ini index 7d57e6005e..ba5d862c57 100644 --- a/opendaylight/distribution/opendaylight/src/main/resources/configuration/config.ini +++ b/opendaylight/distribution/opendaylight/src/main/resources/configuration/config.ini @@ -29,8 +29,16 @@ netconf.config.persister.1.storageAdapterClass=org.opendaylight.controller.confi netconf.config.persister.1.properties.directoryStorage=configuration/initial/ netconf.config.persister.1.readonly=true -netconf.config.persister.2.storageAdapterClass=org.opendaylight.controller.config.persist.storage.file.FileStorageAdapter -netconf.config.persister.2.properties.fileStorage=configuration/current/controller.currentconfig.txt +#netconf.config.persister.3.storageAdapterClass=org.opendaylight.controller.config.persist.storage.directory.xml.XmlDirectoryStorageAdapter +#netconf.config.persister.3.properties.directoryStorage=configuration/initialXml/ +#netconf.config.persister.3.readonly=true + +#netconf.config.persister.4.storageAdapterClass=org.opendaylight.controller.config.persist.storage.file.FileStorageAdapter +#netconf.config.persister.4.properties.fileStorage=configuration/current/controller.currentconfig.txt +#netconf.config.persister.4.properties.numberOfBackups=1 + +netconf.config.persister.2.storageAdapterClass=org.opendaylight.controller.config.persist.storage.file.xml.XmlFileStorageAdapter +netconf.config.persister.2.properties.fileStorage=configuration/current/controller.currentconfig.xml netconf.config.persister.2.properties.numberOfBackups=1 diff --git a/opendaylight/distribution/opendaylight/src/main/resources/run.bat b/opendaylight/distribution/opendaylight/src/main/resources/run.bat index a8e33d2632..9d6ac8d1de 100644 --- a/opendaylight/distribution/opendaylight/src/main/resources/run.bat +++ b/opendaylight/distribution/opendaylight/src/main/resources/run.bat @@ -140,7 +140,7 @@ SET RUN_CMD="%JAVA_HOME%\bin\java.exe" -Dopendaylight.controller %extraJVMOpts% ECHO %RUN_CMD% if "%startEnabled%" NEQ "" ( - START /B cmd /C CALL %RUN_CMD% + START /B cmd /C CALL %RUN_CMD% > %basedir%\logs\controller.out 2>&1 ECHO Running controller in the background. ) else ( %RUN_CMD% diff --git a/opendaylight/distribution/sanitytest/pom.xml b/opendaylight/distribution/sanitytest/pom.xml index ce710d120e..9d5ba5cc95 100644 --- a/opendaylight/distribution/sanitytest/pom.xml +++ b/opendaylight/distribution/sanitytest/pom.xml @@ -16,153 +16,43 @@ sanitytest 0.4.1-SNAPSHOT - jar - - - ${project.basedir}/../opendaylight/target/distribution.opendaylight-osgipackage/opendaylight - ${distro.dir}/run.bat - - 127.0.0.1 - 300 - - - - - non-windows - - - !windows - - - - ${distro.dir}/run.sh - /tmp/opendaylight.PID - - - - + bundle org.osgi org.osgi.core provided - - - junit - junit - test - - - - org.ow2.chameleon.management - chameleon-mbeans - test - - - - - org.apache.maven.plugins - maven-install-plugin - ${install.plugin.version} + org.apache.felix + maven-bundle-plugin + ${bundle.plugin.version} + true - true + + + org.opendaylight.controller.sanitytest + + + javax.xml.bind.annotation, + org.osgi.service.component, + org.slf4j, + org.eclipse.osgi.framework.console, + org.osgi.framework, + org.eclipse.osgi.baseadaptor, + org.eclipse.osgi.framework.adaptor, + org.osgi.framework.wiring + + + org.opendaylight.controller.sanitytest.internal.Activator + + + ${project.basedir}/META-INF - - - default-install - none - - - - - - org.apache.maven.plugins - maven-enforcer-plugin - ${enforcer.plugin.version} - - - enforce-files-exist - pre-integration-test - - enforce - - - - - - ${distro.script} - - - - true - - - - - - - org.opendaylight.controller - controller-maven-plugin - 0.1.0-SNAPSHOT - - ${distro.dir} - localhost - 8080 - admin - admin - ${distro.script} - ${distro.pid} - - - - - start-controller - pre-integration-test - - - -start - -jmx - -Djava.rmi.server.hostname=${sanitytest.bind.address} - - 60 - - - run - - - - - stop-controller - post-integration-test - - stop - - - - - - - - org.apache.maven.plugins - maven-failsafe-plugin - ${failsafe.version} - - - ${distro.dir} - ${sanitytest.bind.address} - ${sanitytest.timeout} - - - - - - diff --git a/opendaylight/distribution/sanitytest/src/main/java/org/opendaylight/controller/distribution/Sanity.java b/opendaylight/distribution/sanitytest/src/main/java/org/opendaylight/controller/distribution/Sanity.java new file mode 100644 index 0000000000..7fc25e2b81 --- /dev/null +++ b/opendaylight/distribution/sanitytest/src/main/java/org/opendaylight/controller/distribution/Sanity.java @@ -0,0 +1,48 @@ +package org.opendaylight.controller.distribution; + +import java.io.IOException; +import java.io.InputStream; +import java.io.OutputStream; + +import java.util.ArrayList; +import java.util.List; + +public class Sanity { + + static void copy(InputStream in, OutputStream out) throws IOException { + while (true) { + int c = in.read(); + if (c == -1) break; + out.write((char)c); + } + } + + public static void main(String[] args) throws IOException, InterruptedException { + String cwd = System.getProperty("user.dir"); + + System.out.println("Current working directory = " + cwd); + + String os = System.getProperty("os.name").toLowerCase(); + List script = new ArrayList(); + + if(os.contains("windows")){ + script.add("cmd.exe"); + script.add("/c"); + script.add("runsanity.bat"); + } else { + script.add("./runsanity.sh"); + } + + ProcessBuilder processBuilder = new ProcessBuilder(); + processBuilder.inheritIO().command(script); + Process p = processBuilder.start(); + + copy(p.getInputStream(), System.out); + + p.waitFor(); + + System.out.println("Test exited with exitValue = " + p.exitValue()); + + System.exit(p.exitValue()); + } +} diff --git a/opendaylight/distribution/sanitytest/src/main/java/org/opendaylight/controller/sanitytest/internal/Activator.java b/opendaylight/distribution/sanitytest/src/main/java/org/opendaylight/controller/sanitytest/internal/Activator.java new file mode 100644 index 0000000000..08f0700168 --- /dev/null +++ b/opendaylight/distribution/sanitytest/src/main/java/org/opendaylight/controller/sanitytest/internal/Activator.java @@ -0,0 +1,101 @@ +package org.opendaylight.controller.sanitytest.internal; + +import java.util.Timer; +import java.util.TimerTask; + +import org.osgi.framework.Bundle; +import org.osgi.framework.BundleActivator; +import org.osgi.framework.BundleContext; +import org.osgi.framework.wiring.BundleRevision; + +public class Activator implements BundleActivator { + //10 Second initial, 1 second subsequent + private static final int INITIAL_DELAY = 10000; + private static final int SUBSEQUENT_DELAY = 1000; + private static final int MAX_ATTEMPTS = 120; + + + private String stateToString(int state) { + switch (state) { + case Bundle.ACTIVE: + return "ACTIVE"; + case Bundle.INSTALLED: + return "INSTALLED"; + case Bundle.RESOLVED: + return "RESOLVED"; + case Bundle.UNINSTALLED: + return "UNINSTALLED"; + case Bundle.STARTING: + return "STARTING"; + default: + return "Not CONVERTED: state value is " + state; + } + } + + public void start(final BundleContext bundleContext) throws Exception { + Timer monitorTimer = new Timer("monitor timer", true); + monitorTimer.schedule(new TimerTask() { + @Override + public void run() { + int countup = 0; + boolean failed = false; + boolean resolved = false; + while (!resolved) { + resolved = true; + failed = false; + for(Bundle bundle : bundleContext.getBundles()){ + /* + * A bundle should be ACTIVE, unless it a fragment, in which case it should be RESOLVED + */ + int state = bundle.getState(); + if ((bundle.adapt(BundleRevision.class).getTypes() & BundleRevision.TYPE_FRAGMENT) != 0) { + //fragment + if (state != Bundle.RESOLVED) { + System.out.println("------ Failed to activate/resolve fragment = " + bundle.getSymbolicName() + " state = " + stateToString(bundle.getState())); + failed = true; + if (state == Bundle.STARTING) + resolved = false; + } + } else { + if(state != Bundle.ACTIVE) { + System.out.println("------ Failed to activate/resolve bundle = " + bundle.getSymbolicName() + " state = " + stateToString(bundle.getState())); + failed = true; + if (state == Bundle.STARTING) + resolved = false; + } + } + } + if (!resolved) { + countup++; + if (countup < MAX_ATTEMPTS) { + System.out.println("all bundles haven't finished starting, will repeat"); + try { + Thread.sleep(SUBSEQUENT_DELAY); + } catch (Exception e) { + System.out.println("Thread.sleep interuptted."); + break; + } + } else + resolved = true; + } + } + + if(failed){ + System.out.flush(); + System.out.println("exiting with 1 as failed"); + System.out.close(); + Runtime.getRuntime().exit(1); + } else { + System.out.flush(); + System.out.println("exiting with 0 as succeeded"); + System.out.close(); + Runtime.getRuntime().exit(0); + } + } + }, INITIAL_DELAY); + } + + public void stop(BundleContext bundleContext) throws Exception { + + } +} diff --git a/opendaylight/distribution/sanitytest/src/test/java/org/opendaylight/controller/distribution/test/SanityIT.java b/opendaylight/distribution/sanitytest/src/test/java/org/opendaylight/controller/distribution/test/SanityIT.java deleted file mode 100644 index 931e88fc4f..0000000000 --- a/opendaylight/distribution/sanitytest/src/test/java/org/opendaylight/controller/distribution/test/SanityIT.java +++ /dev/null @@ -1,329 +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.distribution.test; - -import java.io.File; -import java.io.FileFilter; -import java.io.FileInputStream; -import java.io.FileNotFoundException; -import java.io.IOException; -import java.net.HttpURLConnection; -import java.net.Socket; -import java.net.URL; -import java.util.Collections; -import java.util.Date; -import java.util.HashSet; -import java.util.Properties; -import java.util.Set; -import java.util.jar.Attributes; -import java.util.jar.JarFile; - -import javax.management.JMX; -import javax.management.MBeanServerConnection; -import javax.management.Notification; -import javax.management.NotificationListener; -import javax.management.ObjectName; -import javax.management.remote.JMXConnector; -import javax.management.remote.JMXConnectorFactory; -import javax.management.remote.JMXServiceURL; - -import org.junit.Assert; -import org.junit.BeforeClass; -import org.junit.Test; -import org.osgi.framework.Bundle; -import org.osgi.framework.Constants; -import org.ow2.chameleon.management.beans.BundleMXBean; -import org.ow2.chameleon.management.beans.OSGiPlatformMXBean; - -/** - * This integration test assumes a running local controller. The test does the - * following: - * 1) Wait for HTTP, JMX and OF ports to open - * 2) Establishes a JMX connection and registers a bundle notification listener - * 3) Waits till all bundles reach expected states or the timeout period elapses - */ -public class SanityIT { - private static final int OF_PORT = Integer.getInteger("ctrl.of.port", 6633); - private static final int HTTP_PORT = Integer.getInteger("ctrl.http.port", 8080); - private static final int JMX_PORT = Integer.getInteger("ctrl.jmx.port", 1088); - private static final int RMI_PORT = Integer.getInteger("ctrl.rmi.port", 1099); - private static final String CTRL_HOST = System.getProperty("ctrl.host", "127.0.0.1"); - private static final String CTRL_HOME = System.getProperty("ctrl.home"); - private static final long TIMEOUT_MILLIS = - Integer.getInteger("ctrl.start.timeout", 3*60) * 1000L; - private static final String JMX_URL = - "service:jmx:rmi:///jndi/rmi://" + CTRL_HOST + ":" + JMX_PORT + "/jmxrmi"; - - private static final Set bundles = - Collections.synchronizedSet(new HashSet()); - private static final Set fragments = - Collections.synchronizedSet(new HashSet()); - - @BeforeClass - public static void loadBundles() throws IOException { - log(" ctrl.home: " + CTRL_HOME); - log(" ctrl.host: " + CTRL_HOST); - log("ctrl.start.timeout: " + TIMEOUT_MILLIS); - log(" jmx.url: " + JMX_URL); - - Assert.assertNotNull(CTRL_HOME); - File ctrlHome = new File(CTRL_HOME); - Assert.assertTrue(ctrlHome.exists() && ctrlHome.isDirectory()); - File configDir = new File(ctrlHome, "configuration"); - Assert.assertTrue(configDir.exists() && configDir.isDirectory()); - File configIni = new File(configDir, "config.ini"); - Assert.assertTrue(configIni.exists()); - Properties config = new Properties(); - config.load(new FileInputStream(configIni)); - processBundles(configDir, config.getProperty("osgi.bundles")); - processBundles(new File(ctrlHome, "plugins")); - log("Bundles found in installation: " + bundles.size()); - log("Fragments found in installation: " + fragments.size()); - } - -@Test - public void sanityTest() throws Exception { - // wait for http, jmx & of ports to open - long startTime = System.currentTimeMillis(); - waitForListening(OF_PORT, false, startTime); - waitForListening(JMX_PORT, false, startTime); - waitForListening(HTTP_PORT, false, startTime); - - // open jmx connection - JMXServiceURL serviceUrl = new JMXServiceURL(JMX_URL); - JMXConnector jmxConnector = JMXConnectorFactory.connect(serviceUrl, null); - final MBeanServerConnection conn = jmxConnector.getMBeanServerConnection(); - - ObjectName fmkName = new ObjectName("org.ow2.chameleon:type=framework"); - OSGiPlatformMXBean fmkBean= JMX.newMBeanProxy(conn, fmkName, - OSGiPlatformMXBean.class, true); - conn.addNotificationListener(fmkName, new NotificationListener() { - - @Override - public void handleNotification(Notification n, Object handback) { - try { - //log("Notification: source: " + n.getSource()); - ObjectName bundleName = new ObjectName( - "org.ow2.chameleon:type=bundle,id=" + n.getUserData()); - BundleMXBean bundleBean = JMX.newMXBeanProxy(conn, - bundleName, BundleMXBean.class, true); - log("Bundle state change: " + bundleBean.getSymbolicName() + - " : " + stateToString(bundleBean.getState())); - handleBundleEvent(bundleBean); - // if its a system bundle, notify the main thread - if (bundleBean.getBundleId() == 0 && - bundleBean.getState() == Bundle.ACTIVE) - { - synchronized(SanityIT.this) { - SanityIT.this.notify(); - } - } - } catch (Exception e) { - e.printStackTrace(); - } - } - }, null, null); - - if (checkAllBundles(conn) > 0) { - log("Waiting for system bundle to start... (times out in: " + TIMEOUT_MILLIS + "ms)"); - long timeElapsed = System.currentTimeMillis() - startTime; - synchronized(this) { - this.wait(TIMEOUT_MILLIS - timeElapsed); - } - log("System bundle started. Revalidating bundle states for all bundles..."); - - // Sometimes, the system bundle starts earlier than other bundles(?). The - // following loop will cover that case. - do { - Thread.sleep(2000); // 2s seems appropriate given the default timeout - if (checkAllBundles(conn) == 0) { - break; - } - } while(System.currentTimeMillis() - startTime < TIMEOUT_MILLIS); - } - try { - jmxConnector.close(); - } catch (Exception ignore) { - // dont want the tests to fail in case we can't close jmx connection - ignore.printStackTrace(); - } - if (bundles.size() + fragments.size() == 0) { - log("All bundles have reached expected state"); - } else { - log("The following bundles did not reach expected state: "); - for (String s : bundles) log("Bundle: " + s); - for (String s : fragments) log("Fragment: " + s); - - } - Assert.assertTrue(bundles.size() == 0 && fragments.size() == 0); - } - - private static int checkAllBundles(MBeanServerConnection conn) throws Exception { - ObjectName allBundlesName = new ObjectName("org.ow2.chameleon:*"); - Set bundleNames = conn.queryNames(allBundlesName, null); - for (ObjectName bundleName : bundleNames) { - if ("bundle".equals(bundleName.getKeyProperty("type"))) { - BundleMXBean bundleBean = JMX.newMBeanProxy(conn, bundleName, - BundleMXBean.class, true); - handleBundleEvent(bundleBean); - } - } - int remaining = bundles.size() + fragments.size(); - if (remaining > 0) { - log("Bundles not in expected states: " + remaining + " Waiting..."); - } - return remaining; - } - - private synchronized static void handleBundleEvent(BundleMXBean bundleBean) { - String name = bundleBean.getSymbolicName(); - int state = bundleBean.getState(); - // BUG in BundleMXBeanImpl - can't get bundle headers :( - // String fragHost = bundleBean.getBundleHeaders().get(Constants.FRAGMENT_HOST); - if (bundles.contains(name) && (state == Bundle.RESOLVED || state == Bundle.ACTIVE)) { - bundles.remove(name); - } else if (fragments.contains(name) && state == Bundle.RESOLVED) { - fragments.remove(name); - } - //log("Bundles to be started: " + bundles.size()); - } - - - // reference\:file\:../lib/org.apache.felix.fileinstall-3.1.6.jar@1:start,\ - private static void processBundles(File dir, String property) { - Assert.assertTrue(property == null || property.length() > 0); - for(String s : property.split(",")) { - int idx = s.indexOf("@"); - s = s.substring(15, (idx == -1 ? s.length() : idx)); - if (!s.endsWith(".jar")) s = s + ".jar"; - processJar(new File(dir, s)); - } - } - - public static void processBundles(File dir) throws IOException { - if (!dir.exists()) throw new FileNotFoundException("Cannot find dir:" + dir); - dir.listFiles(new FileFilter() { - - @Override - public boolean accept(File file) { - //p("---- " + file); - if (file.getName().endsWith(".jar")) { - return processJar(file); - } - return false; - } - }); - } - - public static boolean processJar(File file) { - try { - //log("----" + file); - JarFile jar = new JarFile(file, false); - Attributes jarAttributes = jar.getManifest().getMainAttributes(); - String bundleName = jarAttributes.getValue(Constants.BUNDLE_SYMBOLICNAME); - String fragHost = jarAttributes.getValue(Constants.FRAGMENT_HOST); - if (bundleName == null) { - log("Found a non bundle file:" + file); - return false; - } else { - int idx = bundleName.indexOf(';'); - if (idx > -1) { - bundleName = bundleName.substring(0, idx); - } - } - - if (fragHost == null) { - if (!bundles.add(bundleName)) { - throw new IllegalStateException( - "Found duplicate bundles with same symbolic name: " - + bundleName); - } - } else { - // fragments attaching to framework can't be detected - if (fragHost.contains("extension:=\"framework\"")) return false; - if (!fragments.add(bundleName)) { - throw new IllegalStateException( - "Found duplicate fragments with same symbolic name: " - + bundleName); - } - } - } catch (IOException e) { - throw new IllegalStateException("Error processing jar: " + file , e); - } - return true; - } - - public static long waitForListening(int port, boolean isHTTP, long beginTime) - throws InterruptedException { - long timeElapsedMillis = System.currentTimeMillis() - beginTime; - long sleepTimeMillis = 500L; // 0.5 secs - - while (timeElapsedMillis < TIMEOUT_MILLIS) { - long timeRemaining = TIMEOUT_MILLIS - timeElapsedMillis; - sleepTimeMillis *= 2; // exponential backoff - long toSleep = (sleepTimeMillis > timeRemaining) - ? timeRemaining : sleepTimeMillis; - Thread.sleep(toSleep); - timeElapsedMillis = System.currentTimeMillis() - beginTime; - if (isHTTP ? connectHTTP(port) : connectTCP(port)) { - log("Port is open: " + port); - return timeElapsedMillis; - } - } - throw new IllegalStateException("Timeout waiting for port: " + port); - } - - private static void log(String msg) { - System.out.format("[SanityIT] [%s] %s %s", new Date().toString(), msg, - System.lineSeparator()); - } - - public static boolean connectTCP(int port) { - String host = CTRL_HOST.length() == 0 ? null : CTRL_HOST; - try { - Socket sock = new Socket(host, port); - sock.getPort(); - try { - sock.close(); - } catch (IOException ignore) { - // Can't close socket. Ingore and let downstream validate health - } - return true; - } catch (IOException ioe) { - return false; - } - } - - public static boolean connectHTTP(int port) { - String host = CTRL_HOST.length() == 0 ? "localhost" : CTRL_HOST; - try { - URL url = new URL("http", host, port, "/"); - HttpURLConnection con; - con = (HttpURLConnection) url.openConnection(); - return (con.getResponseCode() > 0); - } catch (IOException e) { - return false; - } - } - - private String stateToString(int state) { - switch (state) { - case Bundle.ACTIVE: return "ACTIVE"; - case Bundle.INSTALLED: return "INSTALLED"; - case Bundle.RESOLVED: return "RESOLVED"; - case Bundle.UNINSTALLED: return "UNINSTALLED"; - case Bundle.STARTING: return "STARTING"; - case Bundle.STOPPING: return "STOPPING"; - default: return "UNKNOWN: " + state; - } - } - - - - -} diff --git a/opendaylight/md-sal/compatibility/sal-compatibility/src/main/java/org/opendaylight/controller/sal/compatibility/adsal/FlowStatisticsAdapter.java b/opendaylight/md-sal/compatibility/sal-compatibility/src/main/java/org/opendaylight/controller/sal/compatibility/adsal/FlowStatisticsAdapter.java index f5c5620d7c..09585d6273 100644 --- a/opendaylight/md-sal/compatibility/sal-compatibility/src/main/java/org/opendaylight/controller/sal/compatibility/adsal/FlowStatisticsAdapter.java +++ b/opendaylight/md-sal/compatibility/sal-compatibility/src/main/java/org/opendaylight/controller/sal/compatibility/adsal/FlowStatisticsAdapter.java @@ -21,12 +21,22 @@ import org.opendaylight.controller.sal.reader.NodeDescription; import org.opendaylight.controller.sal.reader.NodeTableStatistics; import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.yang.types.rev100924.Counter64; import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.statistics.rev130819.FlowStatisticsUpdatedBuilder; +import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.statistics.rev130819.GetAggregateFlowStatisticsFromFlowTableForAllFlowsInput; +import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.statistics.rev130819.GetAggregateFlowStatisticsFromFlowTableForAllFlowsOutput; +import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.statistics.rev130819.GetAggregateFlowStatisticsFromFlowTableForGivenMatchInput; +import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.statistics.rev130819.GetAggregateFlowStatisticsFromFlowTableForGivenMatchOutput; +import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.statistics.rev130819.GetAllFlowStatisticsFromFlowTableInput; +import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.statistics.rev130819.GetAllFlowStatisticsFromFlowTableOutput; import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.statistics.rev130819.GetAllFlowStatisticsInput; import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.statistics.rev130819.GetAllFlowStatisticsOutput; import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.statistics.rev130819.GetAllFlowStatisticsOutputBuilder; +import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.statistics.rev130819.GetAllFlowsStatisticsFromAllFlowTablesInput; +import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.statistics.rev130819.GetAllFlowsStatisticsFromAllFlowTablesOutput; import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.statistics.rev130819.GetAllNodeConnectorStatisticsInput; import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.statistics.rev130819.GetAllNodeConnectorStatisticsOutput; import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.statistics.rev130819.GetAllNodeConnectorStatisticsOutputBuilder; +import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.statistics.rev130819.GetFlowStatisticsFromFlowTableInput; +import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.statistics.rev130819.GetFlowStatisticsFromFlowTableOutput; import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.statistics.rev130819.GetFlowStatisticsInput; import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.statistics.rev130819.GetFlowStatisticsOutput; import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.statistics.rev130819.GetFlowStatisticsOutputBuilder; @@ -292,4 +302,39 @@ public class FlowStatisticsAdapter implements OpendaylightFlowStatisticsService, return builder.build(); } + @Override + public Future> getAggregateFlowStatisticsFromFlowTableForAllFlows( + GetAggregateFlowStatisticsFromFlowTableForAllFlowsInput input) { + // TODO Auto-generated method stub + return null; + } + + @Override + public Future> getAggregateFlowStatisticsFromFlowTableForGivenMatch( + GetAggregateFlowStatisticsFromFlowTableForGivenMatchInput input) { + // TODO Auto-generated method stub + return null; + } + + @Override + public Future> getAllFlowStatisticsFromFlowTable( + GetAllFlowStatisticsFromFlowTableInput input) { + // TODO Auto-generated method stub + return null; + } + + @Override + public Future> getAllFlowsStatisticsFromAllFlowTables( + GetAllFlowsStatisticsFromAllFlowTablesInput input) { + // TODO Auto-generated method stub + return null; + } + + @Override + public Future> getFlowStatisticsFromFlowTable( + GetFlowStatisticsFromFlowTableInput input) { + // TODO Auto-generated method stub + return null; + } + } diff --git a/opendaylight/md-sal/model/model-flow-base/src/main/yang/match-types.yang b/opendaylight/md-sal/model/model-flow-base/src/main/yang/match-types.yang index 7dcd254ad7..1ed1b6827b 100644 --- a/opendaylight/md-sal/model/model-flow-base/src/main/yang/match-types.yang +++ b/opendaylight/md-sal/model/model-flow-base/src/main/yang/match-types.yang @@ -9,7 +9,7 @@ module opendaylight-match-types { revision "2013-10-26" { description "Initial revision of macth types"; } - + grouping "mac-address-filter" { leaf address { mandatory true; @@ -61,14 +61,14 @@ module opendaylight-match-types { container vlan-id { description "VLAN id."; presence "Match field is active and set"; - + + leaf vlan-id-present { + type boolean; + } + leaf vlan-id { - mandatory true; type l2t:vlan-id; } - leaf mask { - type binary; - } } leaf vlan-pcp { description "VLAN priority."; diff --git a/opendaylight/md-sal/model/model-flow-base/src/main/yang/opendaylight-action-types.yang b/opendaylight/md-sal/model/model-flow-base/src/main/yang/opendaylight-action-types.yang index 81303d6867..43754a1dfd 100644 --- a/opendaylight/md-sal/model/model-flow-base/src/main/yang/opendaylight-action-types.yang +++ b/opendaylight/md-sal/model/model-flow-base/src/main/yang/opendaylight-action-types.yang @@ -332,7 +332,11 @@ module opendaylight-action-types { } } } - + + case strip-vlan-action-case { + container strip-vlan-action { + } + } case sw-path-action-case { container sw-path-action { @@ -340,4 +344,4 @@ module opendaylight-action-types { } } } -} \ No newline at end of file +} diff --git a/opendaylight/md-sal/model/model-flow-base/src/main/yang/opendaylight-flow-types.yang b/opendaylight/md-sal/model/model-flow-base/src/main/yang/opendaylight-flow-types.yang index e83306db50..2bcd405223 100644 --- a/opendaylight/md-sal/model/model-flow-base/src/main/yang/opendaylight-flow-types.yang +++ b/opendaylight/md-sal/model/model-flow-base/src/main/yang/opendaylight-flow-types.yang @@ -12,6 +12,41 @@ module opendaylight-flow-types { description "Initial revision of flow service"; } + typedef output-port-values { + type enumeration { + enum MAX { + value 1; + } + enum IN_PORT { + value 2; + } + enum TABLE { + value 3; + } + enum NORMAL { + value 4; + } + enum FLOOD { + value 5; + } + enum ALL { + value 6; + } + enum CONTROLLER { + value 7; + } + enum LOCAL { + value 8; + } + enum ANY { + value 9; + } + enum NONE { + value 10; + } + + } + } grouping instruction-list { list instruction { key "order"; @@ -227,4 +262,4 @@ module opendaylight-flow-types { uses match:match; } } -} \ No newline at end of file +} diff --git a/opendaylight/md-sal/model/model-flow-base/src/main/yang/table-types.yang b/opendaylight/md-sal/model/model-flow-base/src/main/yang/table-types.yang index 3774f950fc..5e747e4722 100644 --- a/opendaylight/md-sal/model/model-flow-base/src/main/yang/table-types.yang +++ b/opendaylight/md-sal/model/model-flow-base/src/main/yang/table-types.yang @@ -11,6 +11,10 @@ module opendaylight-table-types { description "Initial revision of table service"; } + typedef table-id { + type uint8; + } + typedef table-ref { type instance-identifier; } diff --git a/opendaylight/md-sal/model/model-flow-service/src/main/yang/flow-node-inventory.yang b/opendaylight/md-sal/model/model-flow-service/src/main/yang/flow-node-inventory.yang index d717e87f76..e55c50fb29 100644 --- a/opendaylight/md-sal/model/model-flow-service/src/main/yang/flow-node-inventory.yang +++ b/opendaylight/md-sal/model/model-flow-service/src/main/yang/flow-node-inventory.yang @@ -15,7 +15,60 @@ module flow-node-inventory { revision "2013-08-19" { description "Flow Capable Node extensions to the Inventory model"; } - + + identity feature-capability { + } + + identity flow-feature-capability-flow-stats { + description "Flow statistics"; + base feature-capability; + } + + identity flow-feature-capability-table-stats { + description "Table statistics"; + base feature-capability; + } + + identity flow-feature-capability-port-stats { + description "Port statistics"; + base feature-capability; + } + + identity flow-feature-capability-stp { + description "802.1d spanning tree"; + base feature-capability; + } + + identity flow-feature-capability-reserved { + description "Reserved, must be zero"; + base feature-capability; + } + + identity flow-feature-capability-ip-reasm { + description "Can reassemble IP fragments"; + base feature-capability; + } + + identity flow-feature-capability-queue-stats { + description "Queue statistics"; + base feature-capability; + } + + identity flow-feature-capability-arp-match-ip { + description "Match IP addresses in ARP pkts"; + base feature-capability; + } + + identity flow-feature-capability-group-stats { + description "Group statistics"; + base feature-capability; + } + + identity flow-feature-capability-port-blocked { + description "Switch will block looping ports"; + base feature-capability; + } + grouping feature { leaf support-state { type inv:support-type; @@ -70,7 +123,8 @@ module flow-node-inventory { uses meter:meter; } } - + + grouping flow-node { leaf manufacturer { @@ -122,6 +176,24 @@ module flow-node-inventory { } } } + + container switch-features { + + leaf max_buffers { + type uint32; + } + + leaf max_tables { + type uint8; + } + + leaf-list capabilities { + type identityref { + base feature-capability; + } + } + + } } grouping flow-node-connector { @@ -149,9 +221,10 @@ module flow-node-inventory { ext:augment-identifier "flow-capable-node-connector-update-fields"; uses flow-node-connector; } - + augment "/inv:node-connector-updated" { ext:augment-identifier "flow-capable-node-connector-updated"; uses flow-node-connector; } + } \ No newline at end of file diff --git a/opendaylight/md-sal/model/model-flow-statistics/src/main/yang/flow-statistics.yang b/opendaylight/md-sal/model/model-flow-statistics/src/main/yang/flow-statistics.yang index 87d1559e49..3bd37bcf33 100644 --- a/opendaylight/md-sal/model/model-flow-statistics/src/main/yang/flow-statistics.yang +++ b/opendaylight/md-sal/model/model-flow-statistics/src/main/yang/flow-statistics.yang @@ -3,28 +3,156 @@ module opendaylight-flow-statistics { prefix flowstat; import yang-ext {prefix ext; revision-date "2013-07-09";} + import ietf-yang-types {prefix yang; revision-date "2010-09-24";} import opendaylight-inventory {prefix inv;revision-date "2013-08-19";} import opendaylight-flow-types {prefix flow-types;revision-date "2013-10-26";} - import sal-flow {prefix flow;} import opendaylight-statistics-types {prefix stat-types;revision-date "2013-09-25";} + import opendaylight-table-types {prefix table-types;revision-date "2013-10-26";} + import flow-node-inventory {prefix flow-node;revision-date "2013-08-19";} + import flow-capable-transaction {prefix tr;} + import sal-flow {prefix flow;} + revision "2013-08-19" { - description "Initial revision of flow service"; + description "Initial revision of flow statistics service"; + } + + //Augment flow statistics data to the flow-capable-node->table->flow + augment "/inv:nodes/inv:node/flow-node:table/flow-node:flow" { + ext:augment-identifier "flow-statistics-data"; + uses flow-statistics; + } + + grouping flow-statistics { + container flow-statistics { + //config "false"; + uses flow-types:flow; + uses stat-types:generic-statistics; + } + } + + typedef flow-id { + description "flow id"; + type yang:counter32; + } + + grouping flow-and-statistics-map-list { + description "List of flow and statistics map"; + list flow-and-statistics-map-list { + key "flow-id"; + leaf flow-id { + type flow-id; + } + uses flow-and-statistics-map; + } + } + + grouping flow-and-statistics-map{ + description "Mapping between flow and its statistics"; + uses flow-types:flow; + uses stat-types:generic-statistics; + } + + // RPC calls to fetch flow statistics + rpc get-all-flows-statistics-from-all-flow-tables { + description "Fetch statistics of all the flow present in all the flow tables of the switch"; + input { + uses inv:node-context-ref; + } + output { + uses flow-and-statistics-map-list; + uses tr:transaction-aware; + } + } - rpc get-node-connector-statistics { + rpc get-all-flow-statistics-from-flow-table { + description "Fetch statistics of all the flow present in the specific flow table of the switch"; input { uses inv:node-context-ref; - leaf node-connector { - type inv:node-connector-ref; + leaf table-id { + type table-types:table-id; } } output { - uses stat-types:node-connector-statistics; + uses flow-and-statistics-map-list; + uses tr:transaction-aware; } } - rpc get-flow-statistics { + rpc get-flow-statistics-from-flow-table { + description "Fetch statistics of the specific flow present in the specific flow table of the switch"; + input { + uses inv:node-context-ref; + uses flow-types:flow; + } + output { + uses flow-and-statistics-map-list; + uses tr:transaction-aware; + } + } + + notification flows-statistics-update { + description "Flows statistics sent by switch"; + leaf moreReplies { + type boolean; + } + uses inv:node; + uses flow-and-statistics-map-list; + uses tr:transaction-aware; + } + + //Models for aggregate flow statistics collection + augment "/inv:nodes/inv:node/flow-node:table" { + ext:augment-identifier "aggregate-flow-statistics-data"; + uses aggregate-flow-statistics; + } + + grouping aggregate-flow-statistics { + container aggregate-flow-statistics { + //config "false"; + uses stat-types:aggregate-flow-statistics; + } + } + + // RPC calls to fetch flow statistics + rpc get-aggregate-flow-statistics-from-flow-table-for-all-flows { + description "Fetch aggregate statistics for all the flows present in the specific flow table of the switch"; + input { + uses inv:node-context-ref; + leaf table-id { + type table-types:table-id; + } + } + output { + uses stat-types:aggregate-flow-statistics; + uses tr:transaction-aware; + } + } + rpc get-aggregate-flow-statistics-from-flow-table-for-given-match { + description "Fetch aggregate statistics for all the flow matches to the given match from the given table of the switch"; + input { + uses inv:node-context-ref; + uses flow-types:flow; + } + output { + uses stat-types:aggregate-flow-statistics; + uses tr:transaction-aware; + } + } + + notification aggregate-flow-statistics-update { + description "Aggregate flow statistics for a table, sent by switch"; + leaf moreReplies { + type boolean; + } + uses inv:node; + uses stat-types:aggregate-flow-statistics; + uses tr:transaction-aware; + } + + //Keeping flow statistics RPC call for backward compatibility for sal-compatibility layer --START + rpc get-flow-statistics { input { uses inv:node-context-ref; uses flow-types:flow; @@ -45,6 +173,25 @@ module opendaylight-flow-statistics { } } + notification flow-statistics-updated { + uses flow-types:flow-statistics; + } + + //Keeping flow statistics RPC call for backward compatibility for sal-compatibility layer --END + + //RPC call to fetch node connector statistics + rpc get-node-connector-statistics { + input { + uses inv:node-context-ref; + leaf node-connector { + type inv:node-connector-ref; + } + } + output { + uses stat-types:node-connector-statistics; + } + } + rpc get-all-node-connector-statistics { input { uses inv:node-context-ref; @@ -56,10 +203,6 @@ module opendaylight-flow-statistics { } } - notification flow-statistics-updated { - uses flow-types:flow-statistics; - } - rpc get-flow-table-statistics { input { uses inv:node-context-ref; @@ -79,6 +222,4 @@ module opendaylight-flow-statistics { notification node-connector-statistics-updated { uses stat-types:node-connector-statistics; } - - } diff --git a/opendaylight/md-sal/model/model-flow-statistics/src/main/yang/flow-table-statistics.yang b/opendaylight/md-sal/model/model-flow-statistics/src/main/yang/flow-table-statistics.yang new file mode 100644 index 0000000000..b8233545c5 --- /dev/null +++ b/opendaylight/md-sal/model/model-flow-statistics/src/main/yang/flow-table-statistics.yang @@ -0,0 +1,69 @@ +module opendaylight-flow-table-statistics { + namespace "urn:opendaylight:flow:table:statistics"; + prefix flowtablestat; + + import flow-capable-transaction {prefix tr;} + import yang-ext {prefix ext; revision-date "2013-07-09";} + import ietf-yang-types {prefix yang; revision-date "2010-09-24";} + import opendaylight-inventory {prefix inv;revision-date "2013-08-19";} + import flow-node-inventory {prefix flow-node;revision-date "2013-08-19";} + import opendaylight-table-types {prefix table-types;revision-date "2013-10-26";} + import opendaylight-statistics-types {prefix stat-types;revision-date "2013-09-25";} + + + contact + "Anilkumar Vishnoi + Email: avishnoi@in.ibm.com"; + + revision "2013-12-15" { + description "Initial revision of flow table statistics model"; + } + + //Augment flow table statistics data to the table + augment "/inv:nodes/inv:node/flow-node:table" { + ext:augment-identifier "flow-table-statistics-data"; + uses flow-table-statistics; + } + + grouping flow-table-statistics { + container flow-table-statistics { + //config "false"; + uses stat-types:generic-table-statistics; + } + } + + //RPC calls to fetch flow table statistics + grouping flow-table-and-statistics-map { + list flow-table-and-statistics-map { + key "table-id"; + leaf table-id { + type table-types:table-id; + } + uses stat-types:generic-table-statistics; + } + } + + rpc get-flow-tables-statistics { + description "Fetch statistics of all the flow tables present on the tarnet node"; + input { + uses inv:node-context-ref; + } + output { + uses flow-table-and-statistics-map; + uses tr:transaction-aware; + } + } + + //Notification to receive table statistics update + + notification flow-table-statistics-update { + description "Receive flow table statistics update"; + + leaf moreReplies { + type boolean; + } + uses inv:node; + uses flow-table-and-statistics-map; + uses tr:transaction-aware; + } +} diff --git a/opendaylight/md-sal/model/model-flow-statistics/src/main/yang/port-statistics.yang b/opendaylight/md-sal/model/model-flow-statistics/src/main/yang/port-statistics.yang new file mode 100644 index 0000000000..0cb6a60cfe --- /dev/null +++ b/opendaylight/md-sal/model/model-flow-statistics/src/main/yang/port-statistics.yang @@ -0,0 +1,78 @@ +module opendaylight-port-statistics { + namespace "urn:opendaylight:port:statistics"; + prefix portstat; + + import flow-capable-transaction {prefix tr;} + import yang-ext {prefix ext; revision-date "2013-07-09";} + import ietf-yang-types {prefix yang; revision-date "2010-09-24";} + import opendaylight-inventory {prefix inv;revision-date "2013-08-19";} + import opendaylight-statistics-types {prefix stat-types;revision-date "2013-09-25";} + + contact + "Anilkumar Vishnoi + Email: avishnoi@in.ibm.com"; + + revision "2013-12-14" { + description "Initial revision of port statistics model"; + } + + //Augment port statistics data to the flow-capable-node-connector + augment "/inv:nodes/inv:node/inv:node-connector" { + ext:augment-identifier "flow-capable-node-connector-statistics-data"; + uses flow-capable-node-connector-statistics; + } + + grouping flow-capable-node-connector-statistics { + container flow-capable-node-connector-statistics { + //config "false"; + uses stat-types:node-connector-statistics; + } + } + + // RPC calls + rpc get-all-ports-statistics { + description "Get statistics for all the ports from the node"; + input { + uses inv:node-context-ref; + } + output { + uses stat-types:node-connector-statistics; + uses tr:transaction-aware; + } + } + + rpc get-port-statistics { + description "Get statistics for given port from the node"; + input { + uses inv:node-context-ref; + leaf node-connector-id { + type inv:node-connector-id; + } + } + output { + uses stat-types:node-connector-statistics; + uses tr:transaction-aware; + } + } + + //Notification for port statistics update + grouping node-connector-statistics-and-port-number-map { + description "List of flow and statistics map"; + list node-connector-statistics-and-port-number-map { + key "node-connector-id"; + leaf node-connector-id { + type inv:node-connector-id; + } + uses stat-types:node-connector-statistics; + } + } + + notification port-statistics-update { + leaf moreReplies { + type boolean; + } + uses inv:node; + uses node-connector-statistics-and-port-number-map; + uses tr:transaction-aware; + } +} diff --git a/opendaylight/md-sal/model/model-flow-statistics/src/main/yang/statistics-types.yang b/opendaylight/md-sal/model/model-flow-statistics/src/main/yang/statistics-types.yang index d0b2e6a959..6d5bec1280 100644 --- a/opendaylight/md-sal/model/model-flow-statistics/src/main/yang/statistics-types.yang +++ b/opendaylight/md-sal/model/model-flow-statistics/src/main/yang/statistics-types.yang @@ -60,4 +60,52 @@ module opendaylight-statistics-types { } } } + + grouping generic-statistics { + description "Generic grouping for statistics"; + leaf packet-count { + type yang:counter64; + } + + leaf byte-count { + type yang:counter64; + } + + container duration { + leaf second { + type yang:counter64; + } + leaf nanosecond { + type yang:counter64; + } + } + } + + grouping generic-table-statistics { + description "Generic grouping holding generic statistics related to switch table"; + leaf active-flows { + type yang:counter32; + } + leaf packets-looked-up { + type yang:counter64; + } + leaf packets-matched { + type yang:counter64; + } + } + + grouping aggregate-flow-statistics { + description "Aggregate flow statistics"; + leaf packet-count { + type yang:counter64; + } + + leaf byte-count { + type yang:counter64; + } + leaf flow-count { + type yang:counter32; + } + } + } \ No newline at end of file diff --git a/opendaylight/md-sal/pom.xml b/opendaylight/md-sal/pom.xml index b34621d02d..4f2b255afd 100644 --- a/opendaylight/md-sal/pom.xml +++ b/opendaylight/md-sal/pom.xml @@ -120,6 +120,7 @@ https://sonar.opendaylight.org/ ${user.name}-private-view java + 3.0.0 @@ -427,6 +428,26 @@ org.apache.felix maven-bundle-plugin + + org.codehaus.mojo + build-helper-maven-plugin + 1.8 + + + add-source + generate-sources + + add-source + + + + ${project.build.directory}/generated-sources/config + ${project.build.directory}/generated-sources/sal + + + + + org.apache.maven.plugins maven-jar-plugin diff --git a/opendaylight/md-sal/sal-binding-api/src/main/java/org/opendaylight/controller/sal/binding/api/RpcAvailabilityListener.java b/opendaylight/md-sal/sal-binding-api/src/main/java/org/opendaylight/controller/sal/binding/api/RpcAvailabilityListener.java new file mode 100644 index 0000000000..e25b93918a --- /dev/null +++ b/opendaylight/md-sal/sal-binding-api/src/main/java/org/opendaylight/controller/sal/binding/api/RpcAvailabilityListener.java @@ -0,0 +1,5 @@ +package org.opendaylight.controller.sal.binding.api; + +public interface RpcAvailabilityListener { + +} diff --git a/opendaylight/md-sal/sal-binding-broker/pom.xml b/opendaylight/md-sal/sal-binding-broker/pom.xml index f9f72094f8..1b0f78384f 100644 --- a/opendaylight/md-sal/sal-binding-broker/pom.xml +++ b/opendaylight/md-sal/sal-binding-broker/pom.xml @@ -250,6 +250,12 @@ ietf-inet-types 2010.09.24.2-SNAPSHOT + + org.opendaylight.yangtools.model + ietf-topology-l3-unicast-igp + 2013.10.21.0-SNAPSHOT + test + org.opendaylight.controller.model model-flow-base diff --git a/opendaylight/md-sal/sal-binding-broker/src/main/java/org/opendaylight/controller/config/yang/md/sal/binding/impl/DataBrokerImplModule.java b/opendaylight/md-sal/sal-binding-broker/src/main/java/org/opendaylight/controller/config/yang/md/sal/binding/impl/DataBrokerImplModule.java index 74b6ad8a23..01dc6b8c0c 100644 --- a/opendaylight/md-sal/sal-binding-broker/src/main/java/org/opendaylight/controller/config/yang/md/sal/binding/impl/DataBrokerImplModule.java +++ b/opendaylight/md-sal/sal-binding-broker/src/main/java/org/opendaylight/controller/config/yang/md/sal/binding/impl/DataBrokerImplModule.java @@ -16,7 +16,7 @@ import java.util.concurrent.ScheduledExecutorService; import org.opendaylight.controller.config.yang.md.sal.binding.statistics.DataBrokerRuntimeMXBeanImpl; import org.opendaylight.controller.md.sal.common.impl.routing.AbstractDataReadRouter; import org.opendaylight.controller.sal.binding.impl.DataBrokerImpl; -import org.opendaylight.controller.sal.binding.impl.connect.dom.BindingIndependentDataServiceConnector; +import org.opendaylight.controller.sal.binding.impl.connect.dom.BindingIndependentConnector; import org.opendaylight.controller.sal.binding.impl.connect.dom.BindingIndependentMappingService; import org.opendaylight.controller.sal.core.api.Broker; import org.opendaylight.controller.sal.core.api.data.DataProviderService; @@ -63,7 +63,7 @@ public final class DataBrokerImplModule extends BindingIndependentMappingService mappingService = getMappingServiceDependency(); if (domBroker != null && mappingService != null) { - BindingIndependentDataServiceConnector runtimeMapping = new BindingIndependentDataServiceConnector(); + BindingIndependentConnector runtimeMapping = new BindingIndependentConnector(); runtimeMapping.setMappingService(mappingService); runtimeMapping.setBaDataService(dataBindingBroker); domBroker.registerProvider(runtimeMapping, getBundleContext()); diff --git a/opendaylight/md-sal/sal-binding-broker/src/main/java/org/opendaylight/controller/config/yang/md/sal/binding/impl/RuntimeMappingModule.java b/opendaylight/md-sal/sal-binding-broker/src/main/java/org/opendaylight/controller/config/yang/md/sal/binding/impl/RuntimeMappingModule.java index 1bf15c182f..99b7ed8acf 100644 --- a/opendaylight/md-sal/sal-binding-broker/src/main/java/org/opendaylight/controller/config/yang/md/sal/binding/impl/RuntimeMappingModule.java +++ b/opendaylight/md-sal/sal-binding-broker/src/main/java/org/opendaylight/controller/config/yang/md/sal/binding/impl/RuntimeMappingModule.java @@ -11,6 +11,7 @@ package org.opendaylight.controller.config.yang.md.sal.binding.impl; import javassist.ClassPool; +import org.opendaylight.controller.sal.binding.codegen.impl.SingletonHolder; import org.opendaylight.controller.sal.binding.dom.serializer.impl.RuntimeGeneratedMappingServiceImpl; import org.osgi.framework.BundleContext; @@ -50,8 +51,7 @@ public final class RuntimeMappingModule extends @Override public java.lang.AutoCloseable createInstance() { RuntimeGeneratedMappingServiceImpl service = new RuntimeGeneratedMappingServiceImpl(); - ClassPool pool = new ClassPool(); // Should be default singleton - service.setPool(pool); + service.setPool(SingletonHolder.CLASS_POOL); service.start(getBundleContext()); return service; } diff --git a/opendaylight/md-sal/sal-binding-broker/src/main/java/org/opendaylight/controller/sal/binding/codegen/RuntimeCodeHelper.xtend b/opendaylight/md-sal/sal-binding-broker/src/main/java/org/opendaylight/controller/sal/binding/codegen/RuntimeCodeHelper.xtend index f0f92da18e..dff0d215b2 100644 --- a/opendaylight/md-sal/sal-binding-broker/src/main/java/org/opendaylight/controller/sal/binding/codegen/RuntimeCodeHelper.xtend +++ b/opendaylight/md-sal/sal-binding-broker/src/main/java/org/opendaylight/controller/sal/binding/codegen/RuntimeCodeHelper.xtend @@ -76,7 +76,6 @@ class RuntimeCodeHelper { if (field == null) throw new UnsupportedOperationException( "Unable to set routing table. Table field does not exists"); field.set(target,routingTable); - } } diff --git a/opendaylight/md-sal/sal-binding-broker/src/main/java/org/opendaylight/controller/sal/binding/codegen/impl/RpcRouterCodegenInstance.java b/opendaylight/md-sal/sal-binding-broker/src/main/java/org/opendaylight/controller/sal/binding/codegen/impl/RpcRouterCodegenInstance.java new file mode 100644 index 0000000000..780d0bd4c7 --- /dev/null +++ b/opendaylight/md-sal/sal-binding-broker/src/main/java/org/opendaylight/controller/sal/binding/codegen/impl/RpcRouterCodegenInstance.java @@ -0,0 +1,161 @@ +package org.opendaylight.controller.sal.binding.codegen.impl; + +import org.opendaylight.yangtools.yang.binding.RpcService; +import org.opendaylight.controller.sal.binding.api.BindingAwareBroker.RoutedRpcRegistration; +import org.opendaylight.controller.sal.binding.api.BindingAwareBroker.RpcRegistration; +import org.opendaylight.controller.sal.binding.spi.RpcRouter; +import org.opendaylight.yangtools.yang.binding.BaseIdentity; +import org.opendaylight.yangtools.yang.binding.InstanceIdentifier; + +import static org.opendaylight.controller.sal.binding.codegen.RuntimeCodeHelper.*; + +import java.util.Map; +import java.util.Set; +import java.util.HashMap; + +import org.opendaylight.controller.sal.binding.spi.RpcRoutingTable; +import org.opendaylight.yangtools.yang.binding.DataContainer; +import org.opendaylight.yangtools.yang.binding.RpcImplementation; +import org.opendaylight.controller.md.sal.common.api.routing.MutableRoutingTable; +import org.opendaylight.controller.md.sal.common.api.routing.RouteChange; +import org.opendaylight.controller.md.sal.common.api.routing.RouteChangeListener; +import org.opendaylight.yangtools.concepts.AbstractObjectRegistration; +import org.opendaylight.yangtools.concepts.ListenerRegistration; +import org.opendaylight.yangtools.concepts.util.ListenerRegistry; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import com.google.common.collect.ImmutableMap; +import com.google.common.collect.ImmutableSet; + +public class RpcRouterCodegenInstance implements // + RpcRouter, RouteChangeListener, InstanceIdentifier> { + + private static final Logger LOG = LoggerFactory.getLogger(RpcRouterCodegenInstance.class); + + private T defaultService; + + private final Class serviceType; + + private final T invocationProxy; + + private final Set> contexts; + + private final ListenerRegistry, InstanceIdentifier>> listeners; + + private final Map, RpcRoutingTableImpl> routingTables; + + public RpcRouterCodegenInstance(Class type, T routerImpl, Set> contexts, + Set> inputs) { + this.listeners = ListenerRegistry.create(); + this.serviceType = type; + this.invocationProxy = routerImpl; + this.contexts = ImmutableSet.copyOf(contexts); + Map, RpcRoutingTableImpl> mutableRoutingTables = new HashMap<>(); + for (Class ctx : contexts) { + RpcRoutingTableImpl table = new RpcRoutingTableImpl<>(ctx); + Map invokerView = table.getRoutes(); + setRoutingTable((RpcService) invocationProxy, ctx, invokerView); + mutableRoutingTables.put(ctx, table); + table.registerRouteChangeListener(this); + } + this.routingTables = ImmutableMap.copyOf(mutableRoutingTables); + } + + @Override + public Class getServiceType() { + return serviceType; + } + + @Override + public T getInvocationProxy() { + return invocationProxy; + } + + @Override + @SuppressWarnings("unchecked") + public RpcRoutingTable getRoutingTable(Class routeContext) { + return (RpcRoutingTable) routingTables.get(routeContext); + } + + @Override + public T getDefaultService() { + return defaultService; + } + + @Override + public Set> getContexts() { + return contexts; + } + + @Override + public , InstanceIdentifier>> ListenerRegistration registerRouteChangeListener( + L listener) { + return listeners.registerWithType(listener); + } + + @Override + public void onRouteChange(RouteChange, InstanceIdentifier> change) { + for (ListenerRegistration, InstanceIdentifier>> listener : listeners) { + try { + listener.getInstance().onRouteChange(change); + } catch (Exception e) { + LOG.error("Error occured during invoker listener {}", listener.getInstance(), e); + } + } + } + + @Override + public T getService(Class context, InstanceIdentifier path) { + return routingTables.get(context).getRoute(path); + } + + @Override + public RoutedRpcRegistration addRoutedRpcImplementation(T service) { + return new RoutedRpcRegistrationImpl(service); + } + + @Override + public RpcRegistration registerDefaultService(T service) { + // TODO Auto-generated method stub + return null; + } + + private class RoutedRpcRegistrationImpl extends AbstractObjectRegistration implements RoutedRpcRegistration { + + public RoutedRpcRegistrationImpl(T instance) { + super(instance); + } + + @Override + public Class getServiceType() { + return serviceType; + } + + @Override + public void registerPath(Class context, InstanceIdentifier path) { + routingTables.get(context).updateRoute(path, getInstance()); + } + + @Override + public void unregisterPath(Class context, InstanceIdentifier path) { + routingTables.get(context).removeRoute(path, getInstance()); + + } + + @Override + public void registerInstance(Class context, InstanceIdentifier instance) { + registerPath(context, instance); + } + + @Override + public void unregisterInstance(Class context, InstanceIdentifier instance) { + unregisterPath(context, instance); + } + + @Override + protected void removeRegistration() { + + } + } +} diff --git a/opendaylight/md-sal/sal-binding-broker/src/main/java/org/opendaylight/controller/sal/binding/codegen/impl/RpcRouterCodegenInstance.xtend b/opendaylight/md-sal/sal-binding-broker/src/main/java/org/opendaylight/controller/sal/binding/codegen/impl/RpcRouterCodegenInstance.xtend deleted file mode 100644 index b6dcde19ee..0000000000 --- a/opendaylight/md-sal/sal-binding-broker/src/main/java/org/opendaylight/controller/sal/binding/codegen/impl/RpcRouterCodegenInstance.xtend +++ /dev/null @@ -1,64 +0,0 @@ -package org.opendaylight.controller.sal.binding.codegen.impl - -import org.opendaylight.yangtools.yang.binding.RpcService -import org.opendaylight.controller.sal.binding.spi.RpcRouter -import org.opendaylight.yangtools.yang.binding.BaseIdentity -import org.opendaylight.yangtools.yang.binding.InstanceIdentifier -import static extension org.opendaylight.controller.sal.binding.codegen.RuntimeCodeHelper.* -import java.util.Set -import java.util.HashMap -import org.opendaylight.controller.sal.binding.spi.RpcRoutingTable -import org.opendaylight.yangtools.yang.binding.DataContainer -import org.opendaylight.yangtools.yang.binding.RpcImplementation - -class RpcRouterCodegenInstance implements RpcRouter { - - @Property - val T invocationProxy - - @Property - val RpcImplementation invokerDelegate; - - @Property - val Class serviceType - - @Property - val Set> contexts - - @Property - val Set> supportedInputs; - - val routingTables = new HashMap, RpcRoutingTableImpl>; - - @Property - var T defaultService - - new(Class type, T routerImpl, Set> contexts, - Set> inputs) { - _serviceType = type - _invocationProxy = routerImpl - _invokerDelegate = routerImpl as RpcImplementation - _contexts = contexts - _supportedInputs = inputs; - - for (ctx : contexts) { - val table = XtendHelper.createRoutingTable(ctx) - invocationProxy.setRoutingTable(ctx, table.routes); - routingTables.put(ctx, table); - } - } - - override getRoutingTable(Class table) { - routingTables.get(table) as RpcRoutingTable - } - - override getService(Class context, InstanceIdentifier path) { - val table = getRoutingTable(context); - return table.getRoute(path); - } - - override invoke(Class type, T input) { - return invokerDelegate.invoke(type, input); - } - -} diff --git a/opendaylight/md-sal/sal-binding-broker/src/main/java/org/opendaylight/controller/sal/binding/codegen/impl/RpcRoutingTableImpl.java b/opendaylight/md-sal/sal-binding-broker/src/main/java/org/opendaylight/controller/sal/binding/codegen/impl/RpcRoutingTableImpl.java new file mode 100644 index 0000000000..f9592351f6 --- /dev/null +++ b/opendaylight/md-sal/sal-binding-broker/src/main/java/org/opendaylight/controller/sal/binding/codegen/impl/RpcRoutingTableImpl.java @@ -0,0 +1,125 @@ +package org.opendaylight.controller.sal.binding.codegen.impl; + +import org.opendaylight.controller.sal.binding.spi.RpcRoutingTable; +import org.opendaylight.yangtools.yang.binding.BaseIdentity; +import org.opendaylight.yangtools.yang.binding.RpcService; +import org.opendaylight.yangtools.yang.binding.InstanceIdentifier; + +import java.util.Collections; +import java.util.Map; +import java.util.concurrent.ConcurrentHashMap; +import java.util.concurrent.ConcurrentMap; + +import org.opendaylight.yangtools.yang.binding.DataObject; +import org.opendaylight.controller.md.sal.common.api.routing.RouteChangePublisher; +import org.opendaylight.controller.md.sal.common.api.routing.RouteChangeListener; +import org.opendaylight.controller.md.sal.common.impl.routing.RoutingUtils; +import org.opendaylight.yangtools.concepts.AbstractObjectRegistration; +import org.opendaylight.yangtools.concepts.ListenerRegistration; +import org.opendaylight.yangtools.concepts.Mutable; + +class RpcRoutingTableImpl // +implements // + Mutable, // + RpcRoutingTable, // + RouteChangePublisher, InstanceIdentifier> { + + private final Class identifier; + private final ConcurrentMap, S> routes; + private final Map, S> unmodifiableRoutes; + + private RouteChangeListener, InstanceIdentifier> listener; + private S defaultRoute; + + public RpcRoutingTableImpl(Class identifier) { + super(); + this.identifier = identifier; + this.routes = new ConcurrentHashMap<>(); + this.unmodifiableRoutes = Collections.unmodifiableMap(routes); + } + + @Override + public void setDefaultRoute(S target) { + defaultRoute = target; + } + + @Override + public S getDefaultRoute() { + return defaultRoute; + } + + @Override + public , InstanceIdentifier>> ListenerRegistration registerRouteChangeListener( + L listener) { + return (ListenerRegistration) new SingletonListenerRegistration(listener); + } + + @Override + public Class getIdentifier() { + return identifier; + } + + @Override + @SuppressWarnings("unchecked") + public void updateRoute(InstanceIdentifier path, S service) { + S previous = this.routes.put(path, service); + @SuppressWarnings("rawtypes") + RouteChangeListener listenerCapture = listener; + if (previous == null && listenerCapture != null) { + listenerCapture.onRouteChange(RoutingUtils.announcementChange(identifier, path)); + } + } + + + @Override + @SuppressWarnings("unchecked") + public void removeRoute(InstanceIdentifier path) { + S previous = this.routes.remove(path); + @SuppressWarnings("rawtypes") + RouteChangeListener listenerCapture = listener; + if (previous != null && listenerCapture != null) { + listenerCapture.onRouteChange(RoutingUtils.removalChange(identifier, path)); + } + } + + public void removeRoute(InstanceIdentifier path, S service) { + @SuppressWarnings("rawtypes") + RouteChangeListener listenerCapture = listener; + if (routes.remove(path, service) && listenerCapture != null) { + listenerCapture.onRouteChange(RoutingUtils.removalChange(identifier, path)); + } + } + + @Override + public S getRoute(InstanceIdentifier nodeInstance) { + S route = routes.get(nodeInstance); + if (route != null) { + return route; + } + return getDefaultRoute(); + } + + @Override + public Map, S> getRoutes() { + return unmodifiableRoutes; + } + + protected void removeAllReferences(S service) { + + } + + private class SingletonListenerRegistration, InstanceIdentifier>> extends + AbstractObjectRegistration + implements ListenerRegistration { + + public SingletonListenerRegistration(L instance) { + super(instance); + listener = instance; + } + + @Override + protected void removeRegistration() { + listener = null; + } + } +} \ No newline at end of file diff --git a/opendaylight/md-sal/sal-binding-broker/src/main/java/org/opendaylight/controller/sal/binding/codegen/impl/RpcRoutingTableImpl.xtend b/opendaylight/md-sal/sal-binding-broker/src/main/java/org/opendaylight/controller/sal/binding/codegen/impl/RpcRoutingTableImpl.xtend deleted file mode 100644 index 116a8177f9..0000000000 --- a/opendaylight/md-sal/sal-binding-broker/src/main/java/org/opendaylight/controller/sal/binding/codegen/impl/RpcRoutingTableImpl.xtend +++ /dev/null @@ -1,49 +0,0 @@ -package org.opendaylight.controller.sal.binding.codegen.impl - -import org.opendaylight.controller.sal.binding.spi.RpcRoutingTable -import org.opendaylight.yangtools.yang.binding.BaseIdentity -import org.opendaylight.yangtools.yang.binding.RpcService -import org.opendaylight.yangtools.yang.binding.InstanceIdentifier -import java.util.Map -import org.opendaylight.yangtools.yang.binding.DataObject -import java.util.HashMap - -class RpcRoutingTableImpl implements RpcRoutingTable{ - - @Property - val Class identifier; - - @Property - var S defaultRoute; - - @Property - val Map,S> routes; - - new(Class ident, Map,S> route) { - _identifier = ident - _routes = route - } - - new(Class ident) { - _identifier = ident - _routes = new HashMap - } - - - override getRoute(InstanceIdentifier nodeInstance) { - val ret = routes.get(nodeInstance); - if(ret !== null) { - return ret; - } - return defaultRoute; - } - - override removeRoute(InstanceIdentifier path) { - routes.remove(path); - } - - @SuppressWarnings("rawtypes") - override updateRoute(InstanceIdentifier path, S service) { - routes.put(path as InstanceIdentifier,service); - } -} \ No newline at end of file diff --git a/opendaylight/md-sal/sal-binding-broker/src/main/java/org/opendaylight/controller/sal/binding/codegen/impl/RuntimeCodeGenerator.xtend b/opendaylight/md-sal/sal-binding-broker/src/main/java/org/opendaylight/controller/sal/binding/codegen/impl/RuntimeCodeGenerator.xtend index 90fcbd99aa..7ebcf02e41 100644 --- a/opendaylight/md-sal/sal-binding-broker/src/main/java/org/opendaylight/controller/sal/binding/codegen/impl/RuntimeCodeGenerator.xtend +++ b/opendaylight/md-sal/sal-binding-broker/src/main/java/org/opendaylight/controller/sal/binding/codegen/impl/RuntimeCodeGenerator.xtend @@ -27,7 +27,7 @@ import org.opendaylight.yangtools.yang.binding.Notification import static extension org.opendaylight.controller.sal.binding.codegen.YangtoolsMappingHelper.* import static extension org.opendaylight.controller.sal.binding.codegen.RuntimeCodeSpecification.* import java.util.HashSet -import static org.opendaylight.controller.sal.binding.impl.util.ClassLoaderUtils.* +import static org.opendaylight.yangtools.concepts.util.ClassLoaderUtils.* import org.opendaylight.controller.sal.binding.spi.NotificationInvokerFactory import org.opendaylight.controller.sal.binding.spi.NotificationInvokerFactory.NotificationInvoker import java.util.Set @@ -37,6 +37,8 @@ import org.opendaylight.yangtools.yang.binding.annotations.QName import org.opendaylight.yangtools.yang.binding.DataContainer import org.opendaylight.yangtools.yang.binding.RpcImplementation import org.opendaylight.controller.sal.binding.codegen.util.JavassistUtils +import org.opendaylight.controller.sal.binding.impl.util.ClassLoaderUtils +import javassist.LoaderClassPath class RuntimeCodeGenerator implements org.opendaylight.controller.sal.binding.codegen.RuntimeCodeGenerator, NotificationInvokerFactory { @@ -45,40 +47,70 @@ class RuntimeCodeGenerator implements org.opendaylight.controller.sal.binding.co val extension JavassistUtils utils; val Map, RuntimeGeneratedInvokerPrototype> invokerClasses; - public new(ClassPool pool) { + + new(ClassPool pool) { classPool = pool; utils = new JavassistUtils(pool); invokerClasses = new WeakHashMap(); BROKER_NOTIFICATION_LISTENER = org.opendaylight.controller.sal.binding.api.NotificationListener.asCtClass; + pool.appendClassPath(new LoaderClassPath(RpcService.classLoader)); } override getDirectProxyFor(Class iface) { - val supertype = iface.asCtClass - val targetCls = createClass(iface.directProxyName, supertype) [ - field(DELEGATE_FIELD, iface); - implementMethodsFrom(supertype) [ - body = ''' - { - if(«DELEGATE_FIELD» == null) { + val T instance = withClassLoaderAndLock(iface.classLoader,lock) [| + val proxyName = iface.directProxyName; + val potentialClass = ClassLoaderUtils.tryToLoadClassWithTCCL(proxyName) + if(potentialClass != null) { + return potentialClass.newInstance as T; + } + val supertype = iface.asCtClass + val createdCls = createClass(iface.directProxyName, supertype) [ + field(DELEGATE_FIELD, iface); + implementsType(RpcImplementation.asCtClass) + implementMethodsFrom(supertype) [ + body = ''' + { + if(«DELEGATE_FIELD» == null) { + throw new java.lang.IllegalStateException("No provider is processing supplied message"); + } + return ($r) «DELEGATE_FIELD».«it.name»($$); + } + ''' + ] + implementMethodsFrom(RpcImplementation.asCtClass) [ + body = ''' + { throw new java.lang.IllegalStateException("No provider is processing supplied message"); + return ($r) null; } - return ($r) «DELEGATE_FIELD».«it.name»($$); - } - ''' + ''' + ] ] + return createdCls.toClass(iface.classLoader).newInstance as T ] - return targetCls.toClass(iface.classLoader).newInstance as T + return instance; } override getRouterFor(Class iface) { - val instance = >withClassLoaderAndLock(iface.classLoader,lock) [ | + val metadata = withClassLoader(iface.classLoader) [| + val supertype = iface.asCtClass + return supertype.rpcMetadata; + ] + + val instance = withClassLoaderAndLock(iface.classLoader,lock) [ | val supertype = iface.asCtClass - val metadata = supertype.rpcMetadata; + val routerName = iface.routerName; + val potentialClass = ClassLoaderUtils.tryToLoadClassWithTCCL(routerName) + if(potentialClass != null) { + return potentialClass.newInstance as T; + } + val targetCls = createClass(iface.routerName, supertype) [ - addInterface(RpcImplementation.asCtClass) + field(DELEGATE_FIELD, iface) //field(REMOTE_INVOKER_FIELD,iface); + implementsType(RpcImplementation.asCtClass) for (ctx : metadata.contexts) { field(ctx.routingTableField, Map) @@ -105,35 +137,18 @@ class RuntimeCodeGenerator implements org.opendaylight.controller.sal.binding.co } ] implementMethodsFrom(RpcImplementation.asCtClass) [ - switch (name) { - case "getSupportedInputs": - body = ''' - { - throw new java.lang.UnsupportedOperationException("Not implemented yet"); - return ($r) null; - }''' - case "invoke": { - val tmpBody = ''' - { - «FOR input : metadata.supportedInputs SEPARATOR " else "» - «val rpcMetadata = metadata.rpcInputs.get(input)» - if(«input.name».class.equals($1)) { - return ($r) this.«rpcMetadata.methodName»((«input.name») $2); - } - «ENDFOR» - throw new java.lang.IllegalArgumentException("Not supported message type"); - return ($r) null; - } - ''' - body = tmpBody - } + body = ''' + { + throw new java.lang.IllegalStateException("No provider is processing supplied message"); + return ($r) null; } + ''' ] ] - val instance = targetCls.toClass(iface.classLoader,iface.protectionDomain).newInstance as T - return new RpcRouterCodegenInstance(iface, instance, metadata.contexts,metadata.supportedInputs); + return targetCls.toClass(iface.classLoader,iface.protectionDomain).newInstance as T + ]; - return instance; + return new RpcRouterCodegenInstance(iface, instance, metadata.contexts,metadata.supportedInputs); } private def RpcServiceMetadata getRpcMetadata(CtClass iface) { 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 new file mode 100644 index 0000000000..266293fb6d --- /dev/null +++ b/opendaylight/md-sal/sal-binding-broker/src/main/java/org/opendaylight/controller/sal/binding/codegen/impl/SingletonHolder.java @@ -0,0 +1,14 @@ +package org.opendaylight.controller.sal.binding.codegen.impl; + +import org.opendaylight.controller.sal.binding.codegen.RuntimeCodeGenerator; +import org.opendaylight.controller.sal.binding.spi.NotificationInvokerFactory; + +import javassist.ClassPool; + +public class SingletonHolder { + + public static final ClassPool CLASS_POOL = new ClassPool(); + public static final org.opendaylight.controller.sal.binding.codegen.impl.RuntimeCodeGenerator RPC_GENERATOR_IMPL = new org.opendaylight.controller.sal.binding.codegen.impl.RuntimeCodeGenerator(CLASS_POOL); + public static final RuntimeCodeGenerator RPC_GENERATOR = RPC_GENERATOR_IMPL; + public static final NotificationInvokerFactory INVOKER_FACTORY = RPC_GENERATOR_IMPL.getInvokerFactory(); +} diff --git a/opendaylight/md-sal/sal-binding-broker/src/main/java/org/opendaylight/controller/sal/binding/dom/serializer/impl/LazyGeneratedCodecRegistry.java b/opendaylight/md-sal/sal-binding-broker/src/main/java/org/opendaylight/controller/sal/binding/dom/serializer/impl/LazyGeneratedCodecRegistry.java index 4b672f1140..f1ba5843ba 100644 --- a/opendaylight/md-sal/sal-binding-broker/src/main/java/org/opendaylight/controller/sal/binding/dom/serializer/impl/LazyGeneratedCodecRegistry.java +++ b/opendaylight/md-sal/sal-binding-broker/src/main/java/org/opendaylight/controller/sal/binding/dom/serializer/impl/LazyGeneratedCodecRegistry.java @@ -175,7 +175,7 @@ public class LazyGeneratedCodecRegistry implements // }); return ret; } catch (Exception e) { - LOG.error("Could not find augmentable for {}", augmentation, e); + LOG.debug("Could not find augmentable for {} using {}", augmentation, augmentation.getClassLoader(), e); return null; } } diff --git a/opendaylight/md-sal/sal-binding-broker/src/main/java/org/opendaylight/controller/sal/binding/dom/serializer/impl/RuntimeGeneratedMappingServiceImpl.xtend b/opendaylight/md-sal/sal-binding-broker/src/main/java/org/opendaylight/controller/sal/binding/dom/serializer/impl/RuntimeGeneratedMappingServiceImpl.xtend index 853e62aa38..1b3acf7674 100644 --- a/opendaylight/md-sal/sal-binding-broker/src/main/java/org/opendaylight/controller/sal/binding/dom/serializer/impl/RuntimeGeneratedMappingServiceImpl.xtend +++ b/opendaylight/md-sal/sal-binding-broker/src/main/java/org/opendaylight/controller/sal/binding/dom/serializer/impl/RuntimeGeneratedMappingServiceImpl.xtend @@ -43,6 +43,11 @@ import java.util.ArrayList import org.opendaylight.yangtools.yang.data.api.Node import org.opendaylight.yangtools.yang.data.impl.SimpleNodeTOImpl import org.opendaylight.yangtools.yang.data.impl.CompositeNodeTOImpl +import org.opendaylight.yangtools.yang.binding.RpcService +import java.util.Set +import org.opendaylight.yangtools.yang.common.QName +import com.google.common.collect.FluentIterable +import org.opendaylight.yangtools.binding.generator.util.BindingGeneratorUtil class RuntimeGeneratedMappingServiceImpl implements BindingIndependentMappingService, SchemaServiceListener, AutoCloseable { @@ -65,6 +70,9 @@ class RuntimeGeneratedMappingServiceImpl implements BindingIndependentMappingSer @Property val ConcurrentMap typeToSchemaNode = new ConcurrentHashMap(); + + @Property + val ConcurrentMap> serviceTypeToRpc = new ConcurrentHashMap(); val promisedTypeDefinitions = HashMultimap.>create; @@ -85,10 +93,17 @@ class RuntimeGeneratedMappingServiceImpl implements BindingIndependentMappingSer registry.onModuleContextAdded(schemaContext, entry.key, entry.value); binding.pathToType.putAll(entry.value.childNodes) - //val module = entry.key; + val module = entry.key; val context = entry.value; updateBindingFor(context.childNodes, schemaContext); updateBindingFor(context.cases, schemaContext); + val namespace = BindingGeneratorUtil.moduleNamespaceToPackageName(module); + + if(!module.rpcs.empty) { + val rpcs = FluentIterable.from(module.rpcs).transform[QName].toSet + val serviceClass = new ReferencedTypeImpl(namespace,BindingGeneratorUtil.parseToClassName(module.name)+"Service"); + serviceTypeToRpc.put(serviceClass,rpcs); + } val typedefs = context.typedefs; for (typedef : typedefs.entrySet) { @@ -186,15 +201,7 @@ class RuntimeGeneratedMappingServiceImpl implements BindingIndependentMappingSer } override dataObjectFromDataDom(InstanceIdentifier path, CompositeNode node) { - return tryDeserialization[ | - if (node == null) { - return null; - } - val targetType = path.targetType - val transformer = registry.getCodecForDataObject(targetType); - val ret = transformer.deserialize(node)?.value as DataObject; - return ret; - ] + dataObjectFromDataDom(path.targetType,node) as DataObject; } override fromDataDom(org.opendaylight.yangtools.yang.data.api.InstanceIdentifier entry) { @@ -243,6 +250,10 @@ class RuntimeGeneratedMappingServiceImpl implements BindingIndependentMappingSer listenerRegistration = ctx.registerService(SchemaServiceListener, this, new Hashtable()); } } + + override getRpcQNamesFor(Class service) { + return serviceTypeToRpc.get(new ReferencedTypeImpl(service.package.name,service.simpleName)); + } private def getSchemaWithRetry(Type type) { val typeDef = typeToSchemaNode.get(type); @@ -274,5 +285,16 @@ class RuntimeGeneratedMappingServiceImpl implements BindingIndependentMappingSer override close() throws Exception { listenerRegistration?.unregister(); } + + override dataObjectFromDataDom(Class container, CompositeNode domData) { + return tryDeserialization[ | + if (domData == null) { + return null; + } + val transformer = registry.getCodecForDataObject(container); + val ret = transformer.deserialize(domData)?.value as DataObject; + return ret; + ] + } } diff --git a/opendaylight/md-sal/sal-binding-broker/src/main/java/org/opendaylight/controller/sal/binding/dom/serializer/impl/TransformerGenerator.xtend b/opendaylight/md-sal/sal-binding-broker/src/main/java/org/opendaylight/controller/sal/binding/dom/serializer/impl/TransformerGenerator.xtend index 87c3286f95..4271ef9c1a 100644 --- a/opendaylight/md-sal/sal-binding-broker/src/main/java/org/opendaylight/controller/sal/binding/dom/serializer/impl/TransformerGenerator.xtend +++ b/opendaylight/md-sal/sal-binding-broker/src/main/java/org/opendaylight/controller/sal/binding/dom/serializer/impl/TransformerGenerator.xtend @@ -827,6 +827,11 @@ class TransformerGenerator { val ret = ctCls.toClassImpl(inputType.classLoader, inputType.protectionDomain) return ret as Class, Object>>; } + if (returnType.name == 'char[]') { + val ctCls = createUnionImplementation(inputType, typeSpec); + val ret = ctCls.toClassImpl(inputType.classLoader, inputType.protectionDomain) + return ret as Class, Object>>; + } val ctCls = createClass(typeSpec.codecClassName) [ //staticField(Map,"AUGMENTATION_SERIALIZERS"); @@ -897,6 +902,73 @@ class TransformerGenerator { } + def createUnionImplementation(Class inputType, GeneratedTransferObject typeSpec) { + return createClass(typeSpec.codecClassName) [ + val properties = typeSpec.allProperties; + //staticField(Map,"AUGMENTATION_SERIALIZERS"); + if (inputType.isYangBindingAvailable) { + implementsType(BINDING_CODEC) + staticField(it, INSTANCE_IDENTIFIER_CODEC, BindingCodec) + staticField(it, IDENTITYREF_CODEC, BindingCodec) + implementsType(BindingDeserializer.asCtClass) + } + method(Object, "toDomValue", Object) [ + modifiers = PUBLIC + FINAL + STATIC + val ctSpec = inputType.asCtClass; + bodyChecked = ''' + { + //System.out.println("«inputType.simpleName»#toDomValue: "+$1); + + if($1 == null) { + return null; + } + «typeSpec.resolvedName» _value = («typeSpec.resolvedName») $1; + «FOR property : properties.entrySet» + «IF property.key != "getValue"» + «property.value.resolvedName» «property.key» = («property.value.resolvedName») _value.«property.key»(); + if(«property.key» != null) { + return «serializeValue(property.value, property.key)»; + } + «ENDIF» + «ENDFOR» + + return null; + } + ''' + ] + method(Object, "serialize", Object) [ + bodyChecked = ''' + { + return toDomValue($1); + } + ''' + ] + method(Object, "fromDomValue", Object) [ + modifiers = PUBLIC + FINAL + STATIC + bodyChecked = ''' + { + //System.out.println("«inputType.simpleName»#fromDomValue: "+$1); + + if($1 == null) { + return null; + } + if($1 instanceof String) { + String _simpleValue = (String) $1; + return new «typeSpec.resolvedName»(_simpleValue.toCharArray()); + } + return null; + } + ''' + ] + method(Object, "deserialize", Object) [ + bodyChecked = '''{ + return fromDomValue($1); + } + ''' + ] + ] + } + def boolean isYangBindingAvailable(Class class1) { try { val bindingCodecClass = class1.classLoader.loadClass(BINDING_CODEC.name); @@ -1221,6 +1293,9 @@ class TransformerGenerator { } else if (CLASS_TYPE.equals(signature)) { return '''(«QName.resolvedName») «IDENTITYREF_CODEC».serialize(«property»)''' } + if ("char[]" == signature.name) { + return '''new String(«property»)'''; + } return '''«property»'''; } diff --git a/opendaylight/md-sal/sal-binding-broker/src/main/java/org/opendaylight/controller/sal/binding/impl/BindingAwareBrokerImpl.xtend b/opendaylight/md-sal/sal-binding-broker/src/main/java/org/opendaylight/controller/sal/binding/impl/BindingAwareBrokerImpl.xtend index 9381a5a070..8d3545fbbb 100644 --- a/opendaylight/md-sal/sal-binding-broker/src/main/java/org/opendaylight/controller/sal/binding/impl/BindingAwareBrokerImpl.xtend +++ b/opendaylight/md-sal/sal-binding-broker/src/main/java/org/opendaylight/controller/sal/binding/impl/BindingAwareBrokerImpl.xtend @@ -13,7 +13,6 @@ import org.opendaylight.yangtools.yang.binding.RpcService import javassist.ClassPool import org.osgi.framework.BundleContext import java.util.Map -import java.util.HashMap import javassist.LoaderClassPath import org.opendaylight.controller.sal.binding.api.BindingAwareBroker import java.util.Hashtable @@ -49,29 +48,14 @@ import java.util.concurrent.Callable import java.util.WeakHashMap import javax.annotation.concurrent.GuardedBy import org.opendaylight.controller.sal.binding.api.RpcProviderRegistry +import org.opendaylight.yangtools.concepts.ListenerRegistration +import org.opendaylight.yangtools.concepts.util.ListenerRegistry -class BindingAwareBrokerImpl implements BindingAwareBroker, RpcProviderRegistry, AutoCloseable { +class BindingAwareBrokerImpl extends RpcProviderRegistryImpl implements BindingAwareBroker, AutoCloseable { private static val log = LoggerFactory.getLogger(BindingAwareBrokerImpl) private InstanceIdentifier root = InstanceIdentifier.builder().toInstance(); - private static val clsPool = ClassPool.getDefault() - public static var RuntimeCodeGenerator generator; - - /** - * Map of all Managed Direct Proxies - * - */ - private val Map, RpcProxyContext> managedProxies = new ConcurrentHashMap(); - - /** - * - * Map of all available Rpc Routers - * - * - */ - private val Map, RpcRouter> rpcRouters = new WeakHashMap(); - @Property private var NotificationProviderService notifyBroker @@ -81,43 +65,15 @@ class BindingAwareBrokerImpl implements BindingAwareBroker, RpcProviderRegistry, @Property var BundleContext brokerBundleContext - ServiceRegistration notifyProviderRegistration - - ServiceRegistration notifyConsumerRegistration - - ServiceRegistration dataProviderRegistration - - ServiceRegistration dataConsumerRegistration - - private val proxyGenerationLock = new ReentrantLock; - - private val routerGenerationLock = new ReentrantLock; - public new(BundleContext bundleContext) { _brokerBundleContext = bundleContext; } def start() { log.info("Starting MD-SAL: Binding Aware Broker"); - initGenerator(); - - val executor = Executors.newCachedThreadPool; - - // Initialization of notificationBroker - log.info("Starting MD-SAL: Binding Aware Notification Broker"); - - log.info("Starting MD-SAL: Binding Aware Data Broker"); - - log.info("Starting MD-SAL: Binding Aware Data Broker"); - log.info("MD-SAL: Binding Aware Broker Started"); } - def initGenerator() { - // YANG Binding Class Loader - clsPool.appendClassPath(new LoaderClassPath(RpcService.classLoader)); - generator = new RuntimeCodeGenerator(clsPool); - } override registerConsumer(BindingAwareConsumer consumer, BundleContext bundleCtx) { val ctx = consumer.createContext(bundleCtx) @@ -139,247 +95,9 @@ class BindingAwareBrokerImpl implements BindingAwareBroker, RpcProviderRegistry, private def createContext(BindingAwareProvider provider, BundleContext providerCtx) { new OsgiProviderContext(providerCtx, this) } - - /** - * Returns a Managed Direct Proxy for supplied class - * - * Managed direct proxy is a generated proxy class conforming to the supplied interface - * which delegates all calls to the backing delegate. - * - * Proxy does not do any validation, null pointer checks or modifies data in any way, it - * is only use to avoid exposing direct references to backing implementation of service. - * - * If proxy class does not exist for supplied service class it will be generated automatically. - */ - private def getManagedDirectProxy(Class service) { - var RpcProxyContext existing = null - - if ((existing = managedProxies.get(service)) != null) { - return existing.proxy - } - return withLock(proxyGenerationLock) [ | - val maybeProxy = managedProxies.get(service); - if (maybeProxy !== null) { - return maybeProxy.proxy; - } - - - val proxyInstance = generator.getDirectProxyFor(service) - val rpcProxyCtx = new RpcProxyContext(proxyInstance.class) - val properties = new Hashtable() - rpcProxyCtx.proxy = proxyInstance as RpcService - properties.salServiceType = SAL_SERVICE_TYPE_CONSUMER_PROXY - rpcProxyCtx.registration = brokerBundleContext.registerService(service, rpcProxyCtx.proxy as T, properties) - managedProxies.put(service, rpcProxyCtx) - return rpcProxyCtx.proxy - ] - } - - private static def T withLock(ReentrantLock lock, Callable method) { - try { - lock.lock(); - val ret = method.call; - return ret; - } finally { - lock.unlock(); - } - } - - /** - * Registers RPC Implementation - * - */ - override addRpcImplementation(Class type, T service) { - checkNotNull(type, "Service type should not be null") - checkNotNull(service, "Service type should not be null") - - val proxy = getManagedDirectProxy(type) - checkState(proxy.delegate === null, "The Service for type %s is already registered", type) - - proxy.delegate = service; - return new RpcServiceRegistrationImpl(type, service, this); - } - - override RoutedRpcRegistration addRoutedRpcImplementation(Class type, T service) { - checkNotNull(type, "Service type should not be null") - checkNotNull(service, "Service type should not be null") - - val router = resolveRpcRouter(type); - checkState(router !== null) - return new RoutedRpcRegistrationImpl(service, router, this) - } - override getRpcService(Class service) { - checkNotNull(service, "Service should not be null"); - return getManagedDirectProxy(service) as T; - } - - private def RpcRouter resolveRpcRouter(Class type) { - - val router = rpcRouters.get(type); - if (router !== null) { - return router as RpcRouter; - } - - // We created Router - return withLock(routerGenerationLock) [ | - val maybeRouter = rpcRouters.get(type); - if (maybeRouter !== null) { - return maybeRouter as RpcRouter; - } - - val newRouter = generator.getRouterFor(type); - checkState(newRouter !== null); - rpcRouters.put(type, newRouter); - // We create / update Direct Proxy for router - val proxy = getManagedDirectProxy(type); - proxy.delegate = newRouter.invocationProxy - return newRouter; - ] - - } - - protected def void registerPath(RoutedRpcRegistrationImpl registration, - Class context, InstanceIdentifier path) { - - val router = registration.router; - val paths = registration.registeredPaths; - - val routingTable = router.getRoutingTable(context) - checkState(routingTable != null); - - // Updating internal structure of registration - routingTable.updateRoute(path, registration.instance) - - // Update routing table / send announce to message bus - val success = paths.put(context, path); - } - - protected def void unregisterPath(RoutedRpcRegistrationImpl registration, - Class context, InstanceIdentifier path) { - - val router = registration.router; - val paths = registration.registeredPaths; - - val routingTable = router.getRoutingTable(context) - checkState(routingTable != null); - - // Updating internal structure of registration - val target = routingTable.getRoute(path) - checkState(target === registration.instance) - routingTable.removeRoute(path) - checkState(paths.remove(context, path)); - } - - protected def void unregisterRoutedRpcService(RoutedRpcRegistrationImpl registration) { - - val router = registration.router; - val paths = registration.registeredPaths; - - for (ctxMap : registration.registeredPaths.entries) { - val context = ctxMap.key - val routingTable = router.getRoutingTable(context) - val path = ctxMap.value - routingTable.removeRoute(path) - } - } - - protected def void unregisterRpcService(RpcServiceRegistrationImpl registration) { - - val type = registration.serviceType; - - val proxy = managedProxies.get(type); - if (proxy.proxy.delegate === registration.instance) { - proxy.proxy.delegate = null; - } - } - - def createDelegate(Class type) { - getManagedDirectProxy(type); - } - - def getRpcRouters() { - return Collections.unmodifiableMap(rpcRouters); - } - - override close() { - dataConsumerRegistration.unregister() - dataProviderRegistration.unregister() - notifyConsumerRegistration.unregister() - notifyProviderRegistration.unregister() - } - -} - -class RoutedRpcRegistrationImpl extends AbstractObjectRegistration implements RoutedRpcRegistration { - - @Property - private val BindingAwareBrokerImpl broker; - - @Property - private val RpcRouter router; - - @Property - private val Multimap, InstanceIdentifier> registeredPaths = HashMultimap.create(); - - private var closed = false; - - new(T instance, RpcRouter backingRouter, BindingAwareBrokerImpl broker) { - super(instance) - _router = backingRouter; - _broker = broker; - } - - override protected removeRegistration() { - closed = true - broker.unregisterRoutedRpcService(this) - } - - override registerInstance(Class context, InstanceIdentifier instance) { - registerPath(context, instance); - } - - override unregisterInstance(Class context, InstanceIdentifier instance) { - unregisterPath(context, instance); - } - - override registerPath(Class context, InstanceIdentifier path) { - checkClosed() - broker.registerPath(this, context, path); - } - - override unregisterPath(Class context, InstanceIdentifier path) { - checkClosed() - broker.unregisterPath(this, context, path); - } - - override getServiceType() { - return router.serviceType; - } - - private def checkClosed() { - if (closed) - throw new IllegalStateException("Registration was closed."); - } - -} - -class RpcServiceRegistrationImpl extends AbstractObjectRegistration implements RpcRegistration { - - private var BindingAwareBrokerImpl broker; - - @Property - val Class serviceType; - - public new(Class type, T service, BindingAwareBrokerImpl broker) { - super(service); - this._serviceType = type; - this.broker = broker; - } - - override protected removeRegistration() { - broker.unregisterRpcService(this); - broker = null; + override close() throws Exception { + } -} +} \ No newline at end of file diff --git a/opendaylight/md-sal/sal-binding-broker/src/main/java/org/opendaylight/controller/sal/binding/impl/NotificationBrokerImpl.xtend b/opendaylight/md-sal/sal-binding-broker/src/main/java/org/opendaylight/controller/sal/binding/impl/NotificationBrokerImpl.xtend index e8b3850b77..b10c06f0c5 100644 --- a/opendaylight/md-sal/sal-binding-broker/src/main/java/org/opendaylight/controller/sal/binding/impl/NotificationBrokerImpl.xtend +++ b/opendaylight/md-sal/sal-binding-broker/src/main/java/org/opendaylight/controller/sal/binding/impl/NotificationBrokerImpl.xtend @@ -20,8 +20,8 @@ import org.opendaylight.yangtools.concepts.AbstractObjectRegistration import org.opendaylight.yangtools.concepts.ListenerRegistration import org.opendaylight.yangtools.concepts.Registration import org.opendaylight.yangtools.yang.binding.Notification -import org.slf4j.LoggerFactory - +import org.slf4j.LoggerFactory import org.opendaylight.controller.sal.binding.codegen.impl.SingletonHolder + class NotificationBrokerImpl implements NotificationProviderService, AutoCloseable { val Multimap, NotificationListener> listeners; @@ -29,6 +29,11 @@ class NotificationBrokerImpl implements NotificationProviderService, AutoCloseab @Property var ExecutorService executor; + new() { + listeners = HashMultimap.create() + } + + @Deprecated new(ExecutorService executor) { listeners = HashMultimap.create() this.executor = executor; @@ -100,7 +105,7 @@ class NotificationBrokerImpl implements NotificationProviderService, AutoCloseab override registerNotificationListener( org.opendaylight.yangtools.yang.binding.NotificationListener listener) { - val invoker = BindingAwareBrokerImpl.generator.invokerFactory.invokerFor(listener); + val invoker = SingletonHolder.INVOKER_FACTORY.invokerFor(listener); for (notifyType : invoker.supportedNotifications) { listeners.put(notifyType, invoker.invocationProxy) } diff --git a/opendaylight/md-sal/sal-binding-broker/src/main/java/org/opendaylight/controller/sal/binding/impl/OsgiConsumerContext.xtend b/opendaylight/md-sal/sal-binding-broker/src/main/java/org/opendaylight/controller/sal/binding/impl/OsgiConsumerContext.xtend index bc53108675..644c50b86a 100644 --- a/opendaylight/md-sal/sal-binding-broker/src/main/java/org/opendaylight/controller/sal/binding/impl/OsgiConsumerContext.xtend +++ b/opendaylight/md-sal/sal-binding-broker/src/main/java/org/opendaylight/controller/sal/binding/impl/OsgiConsumerContext.xtend @@ -45,8 +45,7 @@ class OsgiConsumerContext implements ConsumerContext { val ref = services.iterator().next() as ServiceReference; return bundleContext.getService(ref) as T; } else { - broker.createDelegate(module); - return getRpcService(module); + return broker.getRpcService(module); } } catch (InvalidSyntaxException e) { log.error("Created filter was invalid:", e.message, e) diff --git a/opendaylight/md-sal/sal-binding-broker/src/main/java/org/opendaylight/controller/sal/binding/impl/RpcProviderRegistryImpl.java b/opendaylight/md-sal/sal-binding-broker/src/main/java/org/opendaylight/controller/sal/binding/impl/RpcProviderRegistryImpl.java new file mode 100644 index 0000000000..bc862886d7 --- /dev/null +++ b/opendaylight/md-sal/sal-binding-broker/src/main/java/org/opendaylight/controller/sal/binding/impl/RpcProviderRegistryImpl.java @@ -0,0 +1,166 @@ +package org.opendaylight.controller.sal.binding.impl; + +import java.util.Map; +import java.util.Map.Entry; +import java.util.HashMap; +import java.util.Set; +import java.util.WeakHashMap; + +import javax.swing.tree.ExpandVetoException; + +import org.opendaylight.controller.md.sal.common.api.routing.RouteChange; +import org.opendaylight.controller.md.sal.common.api.routing.RouteChangeListener; +import org.opendaylight.controller.md.sal.common.api.routing.RouteChangePublisher; +import org.opendaylight.controller.md.sal.common.impl.routing.RoutingUtils; +import org.opendaylight.controller.sal.binding.api.RpcProviderRegistry; +import org.opendaylight.controller.sal.binding.api.BindingAwareBroker.RoutedRpcRegistration; +import org.opendaylight.controller.sal.binding.api.BindingAwareBroker.RpcRegistration; +import org.opendaylight.controller.sal.binding.codegen.RuntimeCodeGenerator; +import org.opendaylight.controller.sal.binding.codegen.RuntimeCodeHelper; +import org.opendaylight.controller.sal.binding.codegen.impl.SingletonHolder; +import org.opendaylight.controller.sal.binding.spi.RpcContextIdentifier; +import org.opendaylight.controller.sal.binding.spi.RpcRouter; +import org.opendaylight.yangtools.concepts.AbstractObjectRegistration; +import org.opendaylight.yangtools.concepts.Identifiable; +import org.opendaylight.yangtools.concepts.ListenerRegistration; +import org.opendaylight.yangtools.concepts.util.ListenerRegistry; +import org.opendaylight.yangtools.yang.binding.BaseIdentity; +import org.opendaylight.yangtools.yang.binding.InstanceIdentifier; +import org.opendaylight.yangtools.yang.binding.RpcService; + +import static com.google.common.base.Preconditions.*; + +public class RpcProviderRegistryImpl implements // + RpcProviderRegistry, // + RouteChangePublisher> { + + private RuntimeCodeGenerator rpcFactory = SingletonHolder.RPC_GENERATOR_IMPL; + + private final Map, RpcService> publicProxies = new WeakHashMap<>(); + private final Map, RpcRouter> rpcRouters = new WeakHashMap<>(); + private final ListenerRegistry>> routeChangeListeners = ListenerRegistry + .create(); + + @Override + public final RoutedRpcRegistration addRoutedRpcImplementation(Class type, + T implementation) throws IllegalStateException { + return getRpcRouter(type).addRoutedRpcImplementation(implementation); + } + + @Override + public final RpcRegistration addRpcImplementation(Class type, T implementation) + throws IllegalStateException { + RpcRouter potentialRouter = (RpcRouter) rpcRouters.get(type); + if (potentialRouter != null) { + checkState(potentialRouter.getDefaultService() == null, + "Default service for routed RPC already registered."); + return potentialRouter.registerDefaultService(implementation); + } + T publicProxy = getRpcService(type); + RpcService currentDelegate = RuntimeCodeHelper.getDelegate(publicProxy); + checkState(currentDelegate == null, "Rpc service is already registered"); + RuntimeCodeHelper.setDelegate(publicProxy, implementation); + return new RpcProxyRegistration(type, implementation, this); + } + + @Override + public final T getRpcService(Class type) { + + RpcService potentialProxy = publicProxies.get(type); + if (potentialProxy != null) { + return (T) potentialProxy; + } + T proxy = rpcFactory.getDirectProxyFor(type); + publicProxies.put(type, proxy); + return proxy; + } + + private RpcRouter getRpcRouter(Class type) { + RpcRouter potentialRouter = rpcRouters.get(type); + if (potentialRouter != null) { + return (RpcRouter) potentialRouter; + } + RpcRouter router = rpcFactory.getRouterFor(type); + router.registerRouteChangeListener(new RouteChangeForwarder(type)); + RuntimeCodeHelper.setDelegate(getRpcService(type), router.getInvocationProxy()); + rpcRouters.put(type, router); + return router; + } + + public >> ListenerRegistration registerRouteChangeListener( + L listener) { + return (ListenerRegistration) routeChangeListeners.register(listener); + } + + public RuntimeCodeGenerator getRpcFactory() { + return rpcFactory; + } + + public void setRpcFactory(RuntimeCodeGenerator rpcFactory) { + this.rpcFactory = rpcFactory; + } + + private class RouteChangeForwarder implements + RouteChangeListener, InstanceIdentifier> { + + private final Class type; + + public RouteChangeForwarder(Class type) { + this.type = type; + } + + @Override + public void onRouteChange(RouteChange, InstanceIdentifier> change) { + Map>> announcements = new HashMap<>(); + for (Entry, Set>> entry : change.getAnnouncements() + .entrySet()) { + RpcContextIdentifier key = RpcContextIdentifier.contextFor(type, entry.getKey()); + announcements.put(key, entry.getValue()); + } + Map>> removals = new HashMap<>(); + for (Entry, Set>> entry : change.getRemovals() + .entrySet()) { + RpcContextIdentifier key = RpcContextIdentifier.contextFor(type, entry.getKey()); + removals.put(key, entry.getValue()); + } + RouteChange> toPublish = RoutingUtils + .> change(announcements, removals); + for (ListenerRegistration>> listener : routeChangeListeners) { + try { + listener.getInstance().onRouteChange(toPublish); + } catch (Exception e) { + e.printStackTrace(); + } + } + } + } + + public static class RpcProxyRegistration extends AbstractObjectRegistration implements + RpcRegistration { + + private final Class serviceType; + private RpcProviderRegistryImpl registry; + + public RpcProxyRegistration(Class type, T service, RpcProviderRegistryImpl registry) { + super(service); + serviceType = type; + } + + @Override + public Class getServiceType() { + return serviceType; + } + + @Override + protected void removeRegistration() { + if (registry != null) { + T publicProxy = registry.getRpcService(serviceType); + RpcService currentDelegate = RuntimeCodeHelper.getDelegate(publicProxy); + if (currentDelegate == getInstance()) { + RuntimeCodeHelper.setDelegate(publicProxy, null); + } + registry = null; + } + } + } +} diff --git a/opendaylight/md-sal/sal-binding-broker/src/main/java/org/opendaylight/controller/sal/binding/impl/connect/dom/BindingIndependentDataServiceConnector.java b/opendaylight/md-sal/sal-binding-broker/src/main/java/org/opendaylight/controller/sal/binding/impl/connect/dom/BindingIndependentConnector.java similarity index 58% rename from opendaylight/md-sal/sal-binding-broker/src/main/java/org/opendaylight/controller/sal/binding/impl/connect/dom/BindingIndependentDataServiceConnector.java rename to opendaylight/md-sal/sal-binding-broker/src/main/java/org/opendaylight/controller/sal/binding/impl/connect/dom/BindingIndependentConnector.java index 9eff29f8cc..daa3914cf7 100644 --- a/opendaylight/md-sal/sal-binding-broker/src/main/java/org/opendaylight/controller/sal/binding/impl/connect/dom/BindingIndependentDataServiceConnector.java +++ b/opendaylight/md-sal/sal-binding-broker/src/main/java/org/opendaylight/controller/sal/binding/impl/connect/dom/BindingIndependentConnector.java @@ -1,42 +1,78 @@ package org.opendaylight.controller.sal.binding.impl.connect.dom; +import java.lang.ref.WeakReference; +import java.lang.reflect.InvocationTargetException; +import java.lang.reflect.Method; +import java.lang.reflect.ParameterizedType; import java.util.Collection; import java.util.Collections; +import java.util.HashMap; +import java.util.HashSet; import java.util.Map; import java.util.Map.Entry; +import java.util.Set; +import java.util.WeakHashMap; +import java.util.concurrent.Callable; import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.ConcurrentMap; import java.util.concurrent.ExecutionException; import java.util.concurrent.Future; + import org.opendaylight.controller.md.sal.common.api.RegistrationListener; import org.opendaylight.controller.md.sal.common.api.TransactionStatus; import org.opendaylight.controller.md.sal.common.api.data.DataCommitHandler; import org.opendaylight.controller.md.sal.common.api.data.DataCommitHandler.DataCommitTransaction; import org.opendaylight.controller.md.sal.common.api.data.DataCommitHandlerRegistration; import org.opendaylight.controller.md.sal.common.api.data.DataModification; +import org.opendaylight.controller.md.sal.common.api.routing.RouteChange; +import org.opendaylight.controller.md.sal.common.api.routing.RouteChangeListener; +import org.opendaylight.controller.sal.binding.api.RpcProviderRegistry; import org.opendaylight.controller.sal.binding.api.data.DataProviderService; import org.opendaylight.controller.sal.binding.api.data.RuntimeDataProvider; +import org.opendaylight.controller.sal.binding.impl.RpcProviderRegistryImpl; +import org.opendaylight.controller.sal.binding.spi.RpcContextIdentifier; +import org.opendaylight.controller.sal.binding.spi.RpcRouter; import org.opendaylight.controller.sal.common.util.Rpcs; import org.opendaylight.controller.sal.core.api.Provider; import org.opendaylight.controller.sal.core.api.Broker.ProviderSession; +import org.opendaylight.controller.sal.core.api.RpcImplementation; +import org.opendaylight.controller.sal.core.api.RpcProvisionRegistry; import org.opendaylight.controller.sal.core.api.data.DataModificationTransaction; +import org.opendaylight.yangtools.concepts.ListenerRegistration; import org.opendaylight.yangtools.concepts.Registration; +import org.opendaylight.yangtools.concepts.util.ClassLoaderUtils; import org.opendaylight.yangtools.yang.binding.Augmentable; import org.opendaylight.yangtools.yang.binding.Augmentation; +import org.opendaylight.yangtools.yang.binding.BaseIdentity; +import org.opendaylight.yangtools.yang.binding.BindingMapping; +import org.opendaylight.yangtools.yang.binding.DataContainer; import org.opendaylight.yangtools.yang.binding.DataObject; import org.opendaylight.yangtools.yang.binding.InstanceIdentifier; +import org.opendaylight.yangtools.yang.binding.RpcInput; +import org.opendaylight.yangtools.yang.binding.RpcService; +import org.opendaylight.yangtools.yang.binding.util.BindingReflections; +import org.opendaylight.yangtools.yang.common.QName; import org.opendaylight.yangtools.yang.common.RpcError; import org.opendaylight.yangtools.yang.common.RpcResult; import org.opendaylight.yangtools.yang.data.api.CompositeNode; import org.slf4j.Logger; import org.slf4j.LoggerFactory; -public class BindingIndependentDataServiceConnector implements // +import com.google.common.base.Function; +import com.google.common.base.Optional; +import com.google.common.collect.FluentIterable; +import com.google.common.collect.ImmutableSet; + +import static com.google.common.base.Preconditions.*; +import static org.opendaylight.yangtools.concepts.util.ClassLoaderUtils.*; + +public class BindingIndependentConnector implements // RuntimeDataProvider, // - Provider, AutoCloseable { + Provider, // + AutoCloseable { - private final Logger LOG = LoggerFactory.getLogger(BindingIndependentDataServiceConnector.class); + private final Logger LOG = LoggerFactory.getLogger(BindingIndependentConnector.class); private static final InstanceIdentifier ROOT = InstanceIdentifier.builder().toInstance(); @@ -59,26 +95,41 @@ public class BindingIndependentDataServiceConnector implements // private Registration> biCommitHandlerRegistration; + private RpcProvisionRegistry biRpcRegistry; + private RpcProviderRegistryImpl baRpcRegistry; + + private ListenerRegistration domToBindingRpcManager; + // private ListenerRegistration + // bindingToDomRpcManager; + + private Function, org.opendaylight.yangtools.yang.data.api.InstanceIdentifier> toDOMInstanceIdentifier = new Function, org.opendaylight.yangtools.yang.data.api.InstanceIdentifier>() { + + @Override + public org.opendaylight.yangtools.yang.data.api.InstanceIdentifier apply(InstanceIdentifier input) { + return mappingService.toDataDom(input); + } + + }; + @Override public DataObject readOperationalData(InstanceIdentifier path) { try { org.opendaylight.yangtools.yang.data.api.InstanceIdentifier biPath = mappingService.toDataDom(path); - - + CompositeNode result = biDataService.readOperationalData(biPath); Class targetType = path.getTargetType(); - - if(Augmentation.class.isAssignableFrom(targetType)) { + + if (Augmentation.class.isAssignableFrom(targetType)) { path = mappingService.fromDataDom(biPath); Class> augmentType = (Class>) targetType; DataObject parentTo = mappingService.dataObjectFromDataDom(path, result); - if(parentTo instanceof Augmentable) { + if (parentTo instanceof Augmentable) { return (DataObject) ((Augmentable) parentTo).getAugmentation(augmentType); } - + } return mappingService.dataObjectFromDataDom(path, result); - + } catch (DeserializationException e) { throw new IllegalStateException(e); } @@ -183,11 +234,24 @@ public class BindingIndependentDataServiceConnector implements // this.baDataService = baDataService; } + public RpcProviderRegistry getRpcRegistry() { + return baRpcRegistry; + } + + public void setRpcRegistry(RpcProviderRegistryImpl rpcRegistry) { + this.baRpcRegistry = rpcRegistry; + } + public void start() { baDataService.registerDataReader(ROOT, this); baCommitHandlerRegistration = baDataService.registerCommitHandler(ROOT, bindingToDomCommitHandler); biCommitHandlerRegistration = biDataService.registerCommitHandler(ROOT_BI, domToBindingCommitHandler); baDataService.registerCommitHandlerListener(domToBindingCommitHandler); + + if (baRpcRegistry != null && biRpcRegistry != null) { + domToBindingRpcManager = baRpcRegistry.registerRouteChangeListener(new DomToBindingRpcForwardingManager()); + + } } public void setMappingService(BindingIndependentMappingService mappingService) { @@ -205,6 +269,14 @@ public class BindingIndependentDataServiceConnector implements // start(); } + public void onRpcRouterCreated(Class serviceType, RpcRouter router) { + + } + + public void setDomRpcRegistry(RpcProvisionRegistry registry) { + biRpcRegistry = registry; + } + @Override public void close() throws Exception { if (baCommitHandlerRegistration != null) { @@ -358,4 +430,204 @@ public class BindingIndependentDataServiceConnector implements // return forwardedTransaction; } } + + private class DomToBindingRpcForwardingManager implements + RouteChangeListener> { + + private final Map, DomToBindingRpcForwarder> forwarders = new WeakHashMap<>(); + + @Override + public void onRouteChange(RouteChange> change) { + for (Entry>> entry : change.getAnnouncements().entrySet()) { + bindingRoutesAdded(entry); + } + } + + private void bindingRoutesAdded(Entry>> entry) { + Class context = entry.getKey().getRoutingContext(); + Class service = entry.getKey().getRpcService(); + if (context != null) { + getRpcForwarder(service, context).registerPaths(context, service, entry.getValue()); + } + } + + private DomToBindingRpcForwarder getRpcForwarder(Class service, + Class context) { + DomToBindingRpcForwarder potential = forwarders.get(service); + if (potential != null) { + return potential; + } + if (context == null) { + potential = new DomToBindingRpcForwarder(service); + } else { + potential = new DomToBindingRpcForwarder(service, context); + } + forwarders.put(service, potential); + return potential; + } + + } + + private class DomToBindingRpcForwarder implements RpcImplementation { + + private final Set supportedRpcs; + private final WeakReference> rpcServiceType; + private Set registrations; + + public DomToBindingRpcForwarder(Class service) { + this.rpcServiceType = new WeakReference>(service); + this.supportedRpcs = mappingService.getRpcQNamesFor(service); + for (QName rpc : supportedRpcs) { + biRpcRegistry.addRpcImplementation(rpc, this); + } + registrations = ImmutableSet.of(); + } + + public DomToBindingRpcForwarder(Class service, Class context) { + this.rpcServiceType = new WeakReference>(service); + this.supportedRpcs = mappingService.getRpcQNamesFor(service); + registrations = new HashSet<>(); + for (QName rpc : supportedRpcs) { + registrations.add(biRpcRegistry.addRoutedRpcImplementation(rpc, this)); + } + registrations = ImmutableSet.copyOf(registrations); + } + + public void registerPaths(Class context, Class service, + Set> set) { + QName ctx = BindingReflections.findQName(context); + for (org.opendaylight.yangtools.yang.data.api.InstanceIdentifier path : FluentIterable.from(set).transform( + toDOMInstanceIdentifier)) { + for (org.opendaylight.controller.sal.core.api.Broker.RoutedRpcRegistration reg : registrations) { + reg.registerPath(ctx, path); + } + } + } + + public void removePaths(Class context, Class service, + Set> set) { + QName ctx = BindingReflections.findQName(context); + for (org.opendaylight.yangtools.yang.data.api.InstanceIdentifier path : FluentIterable.from(set).transform( + toDOMInstanceIdentifier)) { + for (org.opendaylight.controller.sal.core.api.Broker.RoutedRpcRegistration reg : registrations) { + reg.unregisterPath(ctx, path); + } + } + } + + @Override + public Set getSupportedRpcs() { + return supportedRpcs; + } + + @Override + public RpcResult invokeRpc(QName rpc, CompositeNode domInput) { + checkArgument(rpc != null); + checkArgument(domInput != null); + + Class rpcType = rpcServiceType.get(); + checkState(rpcType != null); + RpcService rpcService = baRpcRegistry.getRpcService(rpcType); + checkState(rpcService != null); + CompositeNode domUnwrappedInput = domInput.getFirstCompositeByName(QName.create(rpc, "input")); + try { + return resolveInvocationStrategy(rpc, rpcType).invokeOn(rpcService, domUnwrappedInput); + } catch (Exception e) { + throw new IllegalStateException(e); + } + } + + private RpcInvocationStrategy resolveInvocationStrategy(final QName rpc, + final Class rpcType) throws Exception { + return ClassLoaderUtils.withClassLoader(rpcType.getClassLoader(), new Callable() { + @Override + public RpcInvocationStrategy call() throws Exception { + String methodName = BindingMapping.getMethodName(rpc); + Method targetMethod = null; + for (Method possibleMethod : rpcType.getMethods()) { + if (possibleMethod.getName().equals(methodName) + && BindingReflections.isRpcMethod(possibleMethod)) { + targetMethod = possibleMethod; + break; + } + } + checkState(targetMethod != null, "Rpc method not found"); + Optional> outputClass = BindingReflections.resolveRpcOutputClass(targetMethod); + Optional> inputClass = BindingReflections + .resolveRpcInputClass(targetMethod); + + RpcInvocationStrategy strategy = null; + if (outputClass.isPresent()) { + if (inputClass.isPresent()) { + strategy = new DefaultInvocationStrategy(targetMethod, outputClass.get(), inputClass.get()); + } else { + strategy = new NoInputNoOutputInvocationStrategy(targetMethod); + } + } else { + strategy = null; + } + return strategy; + } + + }); + } + } + + private abstract class RpcInvocationStrategy { + + protected final Method targetMethod; + + public RpcInvocationStrategy(Method targetMethod) { + this.targetMethod = targetMethod; + } + + public abstract RpcResult uncheckedInvoke(RpcService rpcService, CompositeNode domInput) + throws Exception; + + public RpcResult invokeOn(RpcService rpcService, CompositeNode domInput) throws Exception { + return uncheckedInvoke(rpcService, domInput); + } + } + + private class DefaultInvocationStrategy extends RpcInvocationStrategy { + + @SuppressWarnings("rawtypes") + private WeakReference inputClass; + + @SuppressWarnings("rawtypes") + private WeakReference outputClass; + + public DefaultInvocationStrategy(Method targetMethod, Class outputClass, + Class inputClass) { + super(targetMethod); + this.outputClass = new WeakReference(outputClass); + this.inputClass = new WeakReference(inputClass); + } + + @Override + public RpcResult uncheckedInvoke(RpcService rpcService, CompositeNode domInput) throws Exception { + DataContainer bindingInput = mappingService.dataObjectFromDataDom(inputClass.get(), domInput); + Future> result = (Future>) targetMethod.invoke(rpcService, bindingInput); + if (result == null) { + return Rpcs.getRpcResult(false); + } + RpcResult bindingResult = result.get(); + return Rpcs.getRpcResult(true); + } + + } + + private class NoInputNoOutputInvocationStrategy extends RpcInvocationStrategy { + + public NoInputNoOutputInvocationStrategy(Method targetMethod) { + super(targetMethod); + } + + public RpcResult uncheckedInvoke(RpcService rpcService, CompositeNode domInput) throws Exception { + Future> result = (Future>) targetMethod.invoke(rpcService); + RpcResult bindingResult = result.get(); + return Rpcs.getRpcResult(bindingResult.isSuccessful(), bindingResult.getErrors()); + } + + } } diff --git a/opendaylight/md-sal/sal-binding-broker/src/main/java/org/opendaylight/controller/sal/binding/impl/connect/dom/BindingIndependentMappingService.java b/opendaylight/md-sal/sal-binding-broker/src/main/java/org/opendaylight/controller/sal/binding/impl/connect/dom/BindingIndependentMappingService.java index b1983fe224..e16ae48ef4 100644 --- a/opendaylight/md-sal/sal-binding-broker/src/main/java/org/opendaylight/controller/sal/binding/impl/connect/dom/BindingIndependentMappingService.java +++ b/opendaylight/md-sal/sal-binding-broker/src/main/java/org/opendaylight/controller/sal/binding/impl/connect/dom/BindingIndependentMappingService.java @@ -1,10 +1,13 @@ package org.opendaylight.controller.sal.binding.impl.connect.dom; import java.util.Map.Entry; +import java.util.Set; -import org.opendaylight.yangtools.concepts.ListenerRegistration; +import org.opendaylight.yangtools.yang.binding.DataContainer; import org.opendaylight.yangtools.yang.binding.DataObject; import org.opendaylight.yangtools.yang.binding.InstanceIdentifier; +import org.opendaylight.yangtools.yang.binding.RpcService; +import org.opendaylight.yangtools.yang.common.QName; import org.opendaylight.yangtools.yang.data.api.CompositeNode; public interface BindingIndependentMappingService { @@ -19,5 +22,9 @@ public interface BindingIndependentMappingService { DataObject dataObjectFromDataDom(InstanceIdentifier path, CompositeNode result) throws DeserializationException; InstanceIdentifier fromDataDom(org.opendaylight.yangtools.yang.data.api.InstanceIdentifier entry) throws DeserializationException; + + Set getRpcQNamesFor(Class service); + + DataContainer dataObjectFromDataDom(Class inputClass, CompositeNode domInput); } diff --git a/opendaylight/md-sal/sal-binding-broker/src/main/java/org/opendaylight/controller/sal/binding/impl/util/ClassLoaderUtils.java b/opendaylight/md-sal/sal-binding-broker/src/main/java/org/opendaylight/controller/sal/binding/impl/util/ClassLoaderUtils.java index d230fd17f9..e0eb102992 100644 --- a/opendaylight/md-sal/sal-binding-broker/src/main/java/org/opendaylight/controller/sal/binding/impl/util/ClassLoaderUtils.java +++ b/opendaylight/md-sal/sal-binding-broker/src/main/java/org/opendaylight/controller/sal/binding/impl/util/ClassLoaderUtils.java @@ -56,6 +56,8 @@ public final class ClassLoaderUtils { public static Class loadClassWithTCCL(String name) throws ClassNotFoundException { if ("byte[]".equals(name)) { return byte[].class; + } else if("char[]".equals(name)) { + return char[].class; } try { return Thread.currentThread().getContextClassLoader().loadClass(name); @@ -78,8 +80,7 @@ public final class ClassLoaderUtils { try { return loadClassWithTCCL(fullyQualifiedName); } catch (ClassNotFoundException e) { - + return null; } - return null; } } \ No newline at end of file diff --git a/opendaylight/md-sal/sal-binding-broker/src/main/java/org/opendaylight/controller/sal/binding/spi/RoutingContext.java b/opendaylight/md-sal/sal-binding-broker/src/main/java/org/opendaylight/controller/sal/binding/spi/RoutingContext.java new file mode 100644 index 0000000000..49e056b100 --- /dev/null +++ b/opendaylight/md-sal/sal-binding-broker/src/main/java/org/opendaylight/controller/sal/binding/spi/RoutingContext.java @@ -0,0 +1,5 @@ +package org.opendaylight.controller.sal.binding.spi; + +public class RoutingContext { + +} diff --git a/opendaylight/md-sal/sal-binding-broker/src/main/java/org/opendaylight/controller/sal/binding/spi/RpcContextIdentifier.java b/opendaylight/md-sal/sal-binding-broker/src/main/java/org/opendaylight/controller/sal/binding/spi/RpcContextIdentifier.java new file mode 100644 index 0000000000..33569eb077 --- /dev/null +++ b/opendaylight/md-sal/sal-binding-broker/src/main/java/org/opendaylight/controller/sal/binding/spi/RpcContextIdentifier.java @@ -0,0 +1,65 @@ +package org.opendaylight.controller.sal.binding.spi; + +import org.opendaylight.yangtools.concepts.Immutable; +import org.opendaylight.yangtools.yang.binding.BaseIdentity; +import org.opendaylight.yangtools.yang.binding.RpcService; + +public final class RpcContextIdentifier implements Immutable{ + + public final Class rpcService; + public final Class routingContext; + + private RpcContextIdentifier(Class rpcService, Class routingContext) { + super(); + this.rpcService = rpcService; + this.routingContext = routingContext; + } + + public Class getRpcService() { + return rpcService; + } + + public Class getRoutingContext() { + return routingContext; + } + + public static final RpcContextIdentifier contextForGlobalRpc(Class serviceType) { + return new RpcContextIdentifier(serviceType, null); + } + + public static final RpcContextIdentifier contextFor(Class serviceType,Class routingContext) { + return new RpcContextIdentifier(serviceType, routingContext); + } + + @Override + public int hashCode() { + final int prime = 31; + int result = 1; + result = prime * result + ((routingContext == null) ? 0 : routingContext.hashCode()); + result = prime * result + ((rpcService == null) ? 0 : rpcService.hashCode()); + return result; + } + + @Override + public boolean equals(Object obj) { + if (this == obj) + return true; + if (obj == null) + return false; + if (getClass() != obj.getClass()) + return false; + RpcContextIdentifier other = (RpcContextIdentifier) obj; + if (routingContext == null) { + if (other.routingContext != null) + return false; + } else if (!routingContext.equals(other.routingContext)) + return false; + if (rpcService == null) { + if (other.rpcService != null) + return false; + } else if (!rpcService.equals(other.rpcService)) + return false; + return true; + } + +} diff --git a/opendaylight/md-sal/sal-binding-broker/src/main/java/org/opendaylight/controller/sal/binding/spi/RpcRouter.java b/opendaylight/md-sal/sal-binding-broker/src/main/java/org/opendaylight/controller/sal/binding/spi/RpcRouter.java index 7db90b62fd..621d048dfd 100644 --- a/opendaylight/md-sal/sal-binding-broker/src/main/java/org/opendaylight/controller/sal/binding/spi/RpcRouter.java +++ b/opendaylight/md-sal/sal-binding-broker/src/main/java/org/opendaylight/controller/sal/binding/spi/RpcRouter.java @@ -9,6 +9,9 @@ package org.opendaylight.controller.sal.binding.spi; import java.util.Set; +import org.opendaylight.controller.md.sal.common.api.routing.RouteChangePublisher; +import org.opendaylight.controller.sal.binding.api.BindingAwareBroker.RoutedRpcRegistration; +import org.opendaylight.controller.sal.binding.api.BindingAwareBroker.RpcRegistration; import org.opendaylight.yangtools.yang.binding.BaseIdentity; import org.opendaylight.yangtools.yang.binding.InstanceIdentifier; import org.opendaylight.yangtools.yang.binding.RpcImplementation; @@ -26,7 +29,8 @@ import org.opendaylight.yangtools.yang.binding.RpcService; * Type of RpcService for which router provides routing information * and route selection. */ -public interface RpcRouter extends RpcImplementation{ +public interface RpcRouter extends // + RouteChangePublisher, InstanceIdentifier> { /** * Returns a type of RpcService which is served by this instance of router. @@ -72,12 +76,11 @@ public interface RpcRouter extends RpcImplementation{ * @return default instance responsible for processing RPCs. */ T getDefaultService(); - - /** - * - */ - void setDefaultService(T service); Set> getContexts(); + + RoutedRpcRegistration addRoutedRpcImplementation(T service); + + RpcRegistration registerDefaultService(T service); } diff --git a/opendaylight/md-sal/sal-binding-broker/src/test/java/org/opendaylight/controller/sal/binding/test/AbstractDataServiceTest.java b/opendaylight/md-sal/sal-binding-broker/src/test/java/org/opendaylight/controller/sal/binding/test/AbstractDataServiceTest.java index a7a70c2839..633506fec6 100644 --- a/opendaylight/md-sal/sal-binding-broker/src/test/java/org/opendaylight/controller/sal/binding/test/AbstractDataServiceTest.java +++ b/opendaylight/md-sal/sal-binding-broker/src/test/java/org/opendaylight/controller/sal/binding/test/AbstractDataServiceTest.java @@ -12,7 +12,7 @@ import org.junit.After; import org.junit.Before; import org.opendaylight.controller.sal.binding.api.data.DataProviderService; import org.opendaylight.controller.sal.binding.impl.DataBrokerImpl; -import org.opendaylight.controller.sal.binding.impl.connect.dom.BindingIndependentDataServiceConnector; +import org.opendaylight.controller.sal.binding.impl.connect.dom.BindingIndependentConnector; import org.opendaylight.controller.sal.binding.impl.connect.dom.BindingIndependentMappingService; import org.opendaylight.controller.sal.binding.test.util.BindingBrokerTestFactory; import org.opendaylight.controller.sal.binding.test.util.BindingTestContext; diff --git a/opendaylight/md-sal/sal-binding-broker/src/test/java/org/opendaylight/controller/sal/binding/test/RuntimeCodeGeneratorTest.java b/opendaylight/md-sal/sal-binding-broker/src/test/java/org/opendaylight/controller/sal/binding/test/RuntimeCodeGeneratorTest.java index 1a97bd693a..9c9841a4a5 100644 --- a/opendaylight/md-sal/sal-binding-broker/src/test/java/org/opendaylight/controller/sal/binding/test/RuntimeCodeGeneratorTest.java +++ b/opendaylight/md-sal/sal-binding-broker/src/test/java/org/opendaylight/controller/sal/binding/test/RuntimeCodeGeneratorTest.java @@ -65,9 +65,6 @@ public class RuntimeCodeGeneratorTest { assertNotNull(product); assertNotNull(product.getInvocationProxy()); - assertNotNull(product.getSupportedInputs()); - assertTrue(product.getSupportedInputs().contains(SimpleInput.class)); - assertTrue(product.getSupportedInputs().contains(InheritedContextInput.class)); assertEquals("2 fields should be generated.", 2, product.getInvocationProxy().getClass().getFields().length); verifyRouting(product); diff --git a/opendaylight/md-sal/sal-binding-broker/src/test/java/org/opendaylight/controller/sal/binding/test/bugfix/UnionSerializationTest.java b/opendaylight/md-sal/sal-binding-broker/src/test/java/org/opendaylight/controller/sal/binding/test/bugfix/UnionSerializationTest.java new file mode 100644 index 0000000000..2057619bfd --- /dev/null +++ b/opendaylight/md-sal/sal-binding-broker/src/test/java/org/opendaylight/controller/sal/binding/test/bugfix/UnionSerializationTest.java @@ -0,0 +1,45 @@ +package org.opendaylight.controller.sal.binding.test.bugfix; + +import org.junit.Test; +import org.opendaylight.controller.sal.binding.test.AbstractDataServiceTest; +import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev100924.IpPrefix; +import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev100924.Ipv4Prefix; +import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.nt.l3.unicast.igp.topology.rev131021.igp.node.attributes.igp.node.attributes.Prefix; +import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.nt.l3.unicast.igp.topology.rev131021.igp.node.attributes.igp.node.attributes.PrefixBuilder; +import org.opendaylight.yangtools.yang.binding.InstanceIdentifier; +import org.opendaylight.yangtools.yang.data.api.CompositeNode; + + + + + + + + +import static org.junit.Assert.*; + +public class UnionSerializationTest extends AbstractDataServiceTest { + + public static final String PREFIX_STRING = "192.168.0.1/32"; + + + @Test + public void testPrefixSerialization() throws Exception { + + Ipv4Prefix ipv4prefix = new Ipv4Prefix(PREFIX_STRING); + IpPrefix ipPrefix = new IpPrefix(ipv4prefix); + Prefix prefix = new PrefixBuilder().setPrefix(ipPrefix).build(); + + CompositeNode serialized = testContext.getBindingToDomMappingService().toDataDom(prefix); + assertNotNull(serialized); + assertNotNull(serialized.getFirstSimpleByName(Prefix.QNAME)); + assertEquals(PREFIX_STRING, serialized.getFirstSimpleByName(Prefix.QNAME).getValue()); + + Prefix deserialized = (Prefix) testContext.getBindingToDomMappingService().dataObjectFromDataDom(InstanceIdentifier.builder().node(Prefix.class).build(), serialized); + assertNotNull(deserialized); + assertNotNull(deserialized.getPrefix()); + assertNotNull(deserialized.getPrefix().getIpv4Prefix()); + assertEquals(PREFIX_STRING, deserialized.getPrefix().getIpv4Prefix().getValue()); + } + +} diff --git a/opendaylight/md-sal/sal-binding-broker/src/test/java/org/opendaylight/controller/sal/binding/test/util/BindingTestContext.java b/opendaylight/md-sal/sal-binding-broker/src/test/java/org/opendaylight/controller/sal/binding/test/util/BindingTestContext.java index 4e611c5fe2..3217a31329 100644 --- a/opendaylight/md-sal/sal-binding-broker/src/test/java/org/opendaylight/controller/sal/binding/test/util/BindingTestContext.java +++ b/opendaylight/md-sal/sal-binding-broker/src/test/java/org/opendaylight/controller/sal/binding/test/util/BindingTestContext.java @@ -7,15 +7,22 @@ import java.util.Set; import javassist.ClassPool; +import org.opendaylight.controller.sal.binding.api.RpcProviderRegistry; import org.opendaylight.controller.sal.binding.api.data.DataProviderService; import org.opendaylight.controller.sal.binding.dom.serializer.impl.RuntimeGeneratedMappingServiceImpl; +import org.opendaylight.controller.sal.binding.impl.BindingAwareBrokerImpl; import org.opendaylight.controller.sal.binding.impl.DataBrokerImpl; -import org.opendaylight.controller.sal.binding.impl.connect.dom.BindingIndependentDataServiceConnector; +import org.opendaylight.controller.sal.binding.impl.NotificationBrokerImpl; +import org.opendaylight.controller.sal.binding.impl.connect.dom.BindingIndependentConnector; import org.opendaylight.controller.sal.binding.impl.connect.dom.BindingIndependentMappingService; import org.opendaylight.controller.sal.binding.test.AbstractDataServiceTest; +import org.opendaylight.controller.sal.core.api.RpcImplementation; +import org.opendaylight.controller.sal.core.api.RpcProvisionRegistry; import org.opendaylight.controller.sal.core.api.data.DataStore; +import org.opendaylight.controller.sal.dom.broker.BrokerImpl; import org.opendaylight.controller.sal.dom.broker.impl.DataStoreStatsWrapper; import org.opendaylight.controller.sal.dom.broker.impl.HashMapDataStore; +import org.opendaylight.controller.sal.dom.broker.impl.RpcRouterImpl; import org.opendaylight.controller.sal.dom.broker.impl.SchemaAwareDataStoreAdapter; import org.opendaylight.yangtools.yang.model.api.Module; import org.opendaylight.yangtools.yang.model.api.SchemaContext; @@ -31,7 +38,7 @@ import com.google.common.util.concurrent.MoreExecutors; import static com.google.common.base.Preconditions.*; -public class BindingTestContext { +public class BindingTestContext implements AutoCloseable { public static final org.opendaylight.yangtools.yang.data.api.InstanceIdentifier TREE_ROOT = org.opendaylight.yangtools.yang.data.api.InstanceIdentifier @@ -40,10 +47,15 @@ public class BindingTestContext { private static final Logger LOG = LoggerFactory.getLogger(BindingTestContext.class); private RuntimeGeneratedMappingServiceImpl mappingServiceImpl; + + + private BindingAwareBrokerImpl baBrokerImpl; private DataBrokerImpl baDataImpl; + private NotificationBrokerImpl baNotifyImpl; + private BindingIndependentConnector baConnectDataServiceImpl; + private org.opendaylight.controller.sal.dom.broker.DataBrokerImpl biDataImpl; - - private BindingIndependentDataServiceConnector connectorServiceImpl; + private BrokerImpl biBrokerImpl; private HashMapDataStore rawDataStore; private SchemaAwareDataStoreAdapter schemaAwareDataStore; private DataStoreStatsWrapper dataStoreStats; @@ -56,6 +68,7 @@ public class BindingTestContext { private final ClassPool classPool; private final boolean startWithSchema; + protected BindingTestContext(ListeningExecutorService executor, ClassPool classPool, boolean startWithSchema) { this.executor = executor; @@ -93,15 +106,29 @@ public class BindingTestContext { baDataImpl.setExecutor(executor); } + public void startBindingBroker() { + checkState(executor != null,"Executor needs to be set"); + checkState(baDataImpl != null,"Binding Data Broker must be started"); + checkState(baNotifyImpl != null, "Notification Service must be started"); + baBrokerImpl = new BindingAwareBrokerImpl(null); + + baBrokerImpl.setDataBroker(baDataImpl); + baBrokerImpl.setNotifyBroker(baNotifyImpl); + + baBrokerImpl.start(); + } + public void startBindingToDomDataConnector() { checkState(baDataImpl != null,"Binding Data Broker needs to be started"); checkState(biDataImpl != null,"DOM Data Broker needs to be started."); checkState(mappingServiceImpl != null,"DOM Mapping Service needs to be started."); - connectorServiceImpl = new BindingIndependentDataServiceConnector(); - connectorServiceImpl.setBaDataService(baDataImpl); - connectorServiceImpl.setBiDataService(biDataImpl); - connectorServiceImpl.setMappingService(mappingServiceImpl); - connectorServiceImpl.start(); + baConnectDataServiceImpl = new BindingIndependentConnector(); + baConnectDataServiceImpl.setRpcRegistry(baBrokerImpl); + baConnectDataServiceImpl.setDomRpcRegistry(getDomRpcRegistry()); + baConnectDataServiceImpl.setBaDataService(baDataImpl); + baConnectDataServiceImpl.setBiDataService(biDataImpl); + baConnectDataServiceImpl.setMappingService(mappingServiceImpl); + baConnectDataServiceImpl.start(); } public void startBindingToDomMappingService() { @@ -149,8 +176,11 @@ public class BindingTestContext { public void start() { startBindingDataBroker(); + startBindingNotificationBroker(); + startBindingBroker(); startDomDataBroker(); startDomDataStore(); + startDomBroker(); startBindingToDomMappingService(); startBindingToDomDataConnector(); if(startWithSchema) { @@ -158,6 +188,19 @@ public class BindingTestContext { } } + private void startDomBroker() { + checkState(executor != null); + biBrokerImpl = new BrokerImpl(); + biBrokerImpl.setExecutor(executor); + biBrokerImpl.setRouter(new RpcRouterImpl("test")); + } + + public void startBindingNotificationBroker() { + checkState(executor != null); + baNotifyImpl = new NotificationBrokerImpl(executor); + + } + public void loadYangSchemaFromClasspath() { String[] files = getAllYangFilesOnClasspath(); updateYangSchema(files); @@ -196,4 +239,24 @@ public class BindingTestContext { dataStoreStats.getRequestCommitCount(), dataStoreStats.getRequestCommitTotalTime(), dataStoreStats.getRequestCommitAverageTime()); } + + public RpcProviderRegistry getBindingRpcRegistry() { + return baBrokerImpl; + } + + public RpcProvisionRegistry getDomRpcRegistry() { + if(biBrokerImpl == null) { + return null; + } + return biBrokerImpl.getRouter(); + } + + public RpcImplementation getDomRpcInvoker() { + return biBrokerImpl.getRouter(); + } + + @Override + public void close() throws Exception { + + } } diff --git a/opendaylight/md-sal/sal-binding-dom-it/pom.xml b/opendaylight/md-sal/sal-binding-dom-it/pom.xml index 6525fa078e..7391139d0f 100644 --- a/opendaylight/md-sal/sal-binding-dom-it/pom.xml +++ b/opendaylight/md-sal/sal-binding-dom-it/pom.xml @@ -13,7 +13,6 @@ scm:git:ssh://git.opendaylight.org:29418/controller.git https://wiki.opendaylight.org/view/OpenDaylight_Controller:MD-SAL - @@ -49,6 +48,12 @@ + + org.ops4j.pax.exam + pax-exam-container-native + test + ${exam.version} + org.opendaylight.controller sal-binding-broker-impl diff --git a/opendaylight/md-sal/sal-binding-dom-it/src/test/java/org/opendaylight/controller/sal/binding/test/connect/dom/CrossBrokerRpcTest.java b/opendaylight/md-sal/sal-binding-dom-it/src/test/java/org/opendaylight/controller/sal/binding/test/connect/dom/CrossBrokerRpcTest.java new file mode 100644 index 0000000000..92a0a3a98d --- /dev/null +++ b/opendaylight/md-sal/sal-binding-dom-it/src/test/java/org/opendaylight/controller/sal/binding/test/connect/dom/CrossBrokerRpcTest.java @@ -0,0 +1,159 @@ +package org.opendaylight.controller.sal.binding.test.connect.dom; + +import java.math.BigInteger; +import java.util.Collections; +import java.util.concurrent.Future; + +import org.junit.After; +import org.junit.Before; +import org.junit.Test; +import org.opendaylight.controller.sal.binding.api.BindingAwareBroker.RoutedRpcRegistration; +import org.opendaylight.controller.sal.binding.api.RpcProviderRegistry; +import org.opendaylight.controller.sal.binding.test.util.BindingBrokerTestFactory; +import org.opendaylight.controller.sal.binding.test.util.BindingTestContext; +import org.opendaylight.controller.sal.common.util.Rpcs; +import org.opendaylight.controller.sal.core.api.RpcImplementation; +import org.opendaylight.controller.sal.core.api.RpcProvisionRegistry; +import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.service.rev130819.AddFlowInput; +import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.service.rev130819.AddFlowInputBuilder; +import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.service.rev130819.AddFlowOutput; +import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.service.rev130819.AddFlowOutputBuilder; +import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.service.rev130819.NodeFlowRemoved; +import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.service.rev130819.RemoveFlowInput; +import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.service.rev130819.RemoveFlowOutput; +import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.service.rev130819.SalFlowService; +import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.service.rev130819.UpdateFlowInput; +import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.service.rev130819.UpdateFlowOutput; +import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.transaction.rev131103.TransactionId; +import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.nodes.Node; +import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.nodes.NodeKey; +import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.NodeContext; +import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.NodeId; +import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.NodeRef; +import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.Nodes; +import org.opendaylight.yangtools.yang.binding.BaseIdentity; +import org.opendaylight.yangtools.yang.binding.DataObject; +import org.opendaylight.yangtools.yang.binding.InstanceIdentifier; +import org.opendaylight.yangtools.yang.common.QName; +import org.opendaylight.yangtools.yang.common.RpcError; +import org.opendaylight.yangtools.yang.common.RpcResult; +import org.opendaylight.yangtools.yang.data.api.CompositeNode; +import org.opendaylight.yangtools.yang.data.impl.CompositeNodeTOImpl; + +import static junit.framework.Assert.*; + +import com.google.common.collect.HashMultimap; +import com.google.common.collect.ImmutableList; +import com.google.common.collect.Multimap; +import com.google.common.util.concurrent.Futures; +import com.google.common.util.concurrent.MoreExecutors; + +public class CrossBrokerRpcTest { + + protected RpcProviderRegistry baRpcRegistry; + protected RpcProvisionRegistry biRpcRegistry; + private BindingTestContext testContext; + private RpcImplementation biRpcInvoker; + private MessageCapturingFlowService flowService; + + public static final NodeId NODE_A = new NodeId("a"); + public static final NodeId NODE_B = new NodeId("b"); + public static final NodeId NODE_C = new NodeId("c"); + public static final NodeId NODE_D = new NodeId("d"); + + public static final InstanceIdentifier BA_NODE_A_ID = createBANodeIdentifier(NODE_A); + public static final InstanceIdentifier BA_NODE_B_ID = createBANodeIdentifier(NODE_B); + public static final InstanceIdentifier BA_NODE_C_ID = createBANodeIdentifier(NODE_C); + public static final InstanceIdentifier BA_NODE_D_ID = createBANodeIdentifier(NODE_D); + + public static final org.opendaylight.yangtools.yang.data.api.InstanceIdentifier BI_NODE_A_ID = createBINodeIdentifier(NODE_A); + public static final org.opendaylight.yangtools.yang.data.api.InstanceIdentifier BI_NODE_B_ID = createBINodeIdentifier(NODE_B); + public static final org.opendaylight.yangtools.yang.data.api.InstanceIdentifier BI_NODE_C_ID = createBINodeIdentifier(NODE_C); + public static final org.opendaylight.yangtools.yang.data.api.InstanceIdentifier BI_NODE_D_ID = createBINodeIdentifier(NODE_D); + + private static final QName NODE_ID_QNAME = QName.create(Node.QNAME, "id"); + private static final QName ADD_FLOW_QNAME = QName.create(NodeFlowRemoved.QNAME, "add-flow"); + private static final QName REMOVE_FLOW_QNAME = QName.create(NodeFlowRemoved.QNAME, "remove-flow"); + private static final QName UPDATE_FLOW_QNAME = QName.create(NodeFlowRemoved.QNAME, "update-flow"); + + @Before + public void setup() { + BindingBrokerTestFactory testFactory = new BindingBrokerTestFactory(); + testFactory.setExecutor(MoreExecutors.sameThreadExecutor()); + testFactory.setStartWithParsedSchema(true); + testContext = testFactory.getTestContext(); + + testContext.start(); + baRpcRegistry = testContext.getBindingRpcRegistry(); + biRpcRegistry = testContext.getDomRpcRegistry(); + biRpcInvoker = testContext.getDomRpcInvoker(); + assertNotNull(baRpcRegistry); + assertNotNull(biRpcRegistry); + + flowService = MessageCapturingFlowService.create(baRpcRegistry); + + } + + @Test + public void bindingRoutedRpcProvider_DomInvokerTest() { + + flowService// + .registerPath(NodeContext.class, BA_NODE_A_ID) // + .registerPath(NodeContext.class, BA_NODE_B_ID) // + .setAddFlowResult(addFlowResult(true, 10)); + + SalFlowService baFlowInvoker = baRpcRegistry.getRpcService(SalFlowService.class); + assertNotSame(flowService, baFlowInvoker); + + AddFlowInput addFlowA = addFlow(BA_NODE_A_ID) // + .setPriority(100).setBarrier(true).build(); + + CompositeNode addFlowDom = toDomRpc(ADD_FLOW_QNAME, addFlowA); + assertNotNull(addFlowDom); + RpcResult domResult = biRpcInvoker.invokeRpc(ADD_FLOW_QNAME, addFlowDom); + assertNotNull(domResult); + assertTrue("DOM result is successful.", domResult.isSuccessful()); + assertTrue("Bidning Add Flow RPC was captured.", flowService.getReceivedAddFlows().containsKey(BA_NODE_A_ID)); + assertEquals(addFlowA, flowService.getReceivedAddFlows().get(BA_NODE_A_ID).iterator().next()); + } + + public void bindingRpcInvoker_DomRoutedProviderTest() { + + } + + private CompositeNode toDomRpcInput(DataObject addFlowA) { + return testContext.getBindingToDomMappingService().toDataDom(addFlowA); + } + + @After + public void teardown() throws Exception { + testContext.close(); + } + + private static InstanceIdentifier createBANodeIdentifier(NodeId node) { + return InstanceIdentifier.builder(Nodes.class).child(Node.class, new NodeKey(node)).toInstance(); + } + + private static org.opendaylight.yangtools.yang.data.api.InstanceIdentifier createBINodeIdentifier(NodeId node) { + return org.opendaylight.yangtools.yang.data.api.InstanceIdentifier.builder().node(Nodes.QNAME) + .nodeWithKey(Node.QNAME, NODE_ID_QNAME, node.getValue()).toInstance(); + } + + private Future> addFlowResult(boolean success, long xid) { + AddFlowOutput output = new AddFlowOutputBuilder() // + .setTransactionId(new TransactionId(BigInteger.valueOf(xid))).build(); + RpcResult result = Rpcs.getRpcResult(success, output, ImmutableList. of()); + return Futures.immediateFuture(result); + } + + private static AddFlowInputBuilder addFlow(InstanceIdentifier nodeId) { + AddFlowInputBuilder builder = new AddFlowInputBuilder(); + builder.setNode(new NodeRef(nodeId)); + return builder; + } + + private CompositeNode toDomRpc(QName rpcName, AddFlowInput addFlowA) { + return new CompositeNodeTOImpl(rpcName, null, + Collections.> singletonList(toDomRpcInput(addFlowA))); + } +} diff --git a/opendaylight/md-sal/sal-binding-dom-it/src/test/java/org/opendaylight/controller/sal/binding/test/connect/dom/MessageCapturingFlowService.java b/opendaylight/md-sal/sal-binding-dom-it/src/test/java/org/opendaylight/controller/sal/binding/test/connect/dom/MessageCapturingFlowService.java new file mode 100644 index 0000000000..74f07818d5 --- /dev/null +++ b/opendaylight/md-sal/sal-binding-dom-it/src/test/java/org/opendaylight/controller/sal/binding/test/connect/dom/MessageCapturingFlowService.java @@ -0,0 +1,122 @@ +package org.opendaylight.controller.sal.binding.test.connect.dom; + +import static junit.framework.Assert.assertNotNull; + +import java.util.concurrent.Future; + +import org.opendaylight.controller.sal.binding.api.RpcProviderRegistry; +import org.opendaylight.controller.sal.binding.api.BindingAwareBroker.RoutedRpcRegistration; +import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.service.rev130819.AddFlowInput; +import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.service.rev130819.AddFlowOutput; +import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.service.rev130819.RemoveFlowInput; +import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.service.rev130819.RemoveFlowOutput; +import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.service.rev130819.SalFlowService; +import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.service.rev130819.UpdateFlowInput; +import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.service.rev130819.UpdateFlowOutput; +import org.opendaylight.yangtools.yang.binding.BaseIdentity; +import org.opendaylight.yangtools.yang.binding.InstanceIdentifier; +import org.opendaylight.yangtools.yang.common.RpcResult; + +import com.google.common.collect.HashMultimap; +import com.google.common.collect.Multimap; + +public class MessageCapturingFlowService implements SalFlowService, AutoCloseable { + + private Future> addFlowResult; + private Future> removeFlowResult; + private Future> updateFlowResult; + + private final Multimap, AddFlowInput> receivedAddFlows = HashMultimap.create(); + private final Multimap, RemoveFlowInput> receivedRemoveFlows = HashMultimap.create(); + private final Multimap, UpdateFlowInput> receivedUpdateFlows = HashMultimap.create(); + private RoutedRpcRegistration registration; + + @Override + public Future> addFlow(AddFlowInput arg0) { + receivedAddFlows.put(arg0.getNode().getValue(), arg0); + return addFlowResult; + } + + @Override + public Future> removeFlow(RemoveFlowInput arg0) { + receivedRemoveFlows.put(arg0.getNode().getValue(), arg0); + return removeFlowResult; + } + + @Override + public Future> updateFlow(UpdateFlowInput arg0) { + receivedUpdateFlows.put(arg0.getNode().getValue(), arg0); + return updateFlowResult; + } + + public Future> getAddFlowResult() { + return addFlowResult; + } + + public MessageCapturingFlowService setAddFlowResult(Future> addFlowResult) { + this.addFlowResult = addFlowResult; + return this; + } + + public Future> getRemoveFlowResult() { + return removeFlowResult; + } + + public MessageCapturingFlowService setRemoveFlowResult(Future> removeFlowResult) { + this.removeFlowResult = removeFlowResult; + return this; + } + + public Future> getUpdateFlowResult() { + return updateFlowResult; + } + + public MessageCapturingFlowService setUpdateFlowResult(Future> updateFlowResult) { + this.updateFlowResult = updateFlowResult; + return this; + } + + public Multimap, AddFlowInput> getReceivedAddFlows() { + return receivedAddFlows; + } + + public Multimap, RemoveFlowInput> getReceivedRemoveFlows() { + return receivedRemoveFlows; + } + + public Multimap, UpdateFlowInput> getReceivedUpdateFlows() { + return receivedUpdateFlows; + } + + public MessageCapturingFlowService registerTo(RpcProviderRegistry registry) { + registration = registry.addRoutedRpcImplementation(SalFlowService.class, this); + assertNotNull(registration); + return this; + } + + public void close() throws Exception { + registration.close(); + } + + public MessageCapturingFlowService registerPath(Class context, InstanceIdentifier path) { + registration.registerPath(context, path); + return this; + } + + public MessageCapturingFlowService unregisterPath(Class context, InstanceIdentifier path) { + registration.unregisterPath(context, path); + return this; + } + + public static MessageCapturingFlowService create() { + return new MessageCapturingFlowService(); + } + + public static MessageCapturingFlowService create(RpcProviderRegistry registry) { + MessageCapturingFlowService ret = new MessageCapturingFlowService(); + ret.registerTo(registry); + return ret; + } + + +} \ No newline at end of file diff --git a/opendaylight/md-sal/sal-common-api/src/main/java/org/opendaylight/controller/md/sal/common/api/routing/RouteChangePublisher.java b/opendaylight/md-sal/sal-common-api/src/main/java/org/opendaylight/controller/md/sal/common/api/routing/RouteChangePublisher.java index 89851c9393..bee29a1ad1 100644 --- a/opendaylight/md-sal/sal-common-api/src/main/java/org/opendaylight/controller/md/sal/common/api/routing/RouteChangePublisher.java +++ b/opendaylight/md-sal/sal-common-api/src/main/java/org/opendaylight/controller/md/sal/common/api/routing/RouteChangePublisher.java @@ -4,5 +4,5 @@ import org.opendaylight.yangtools.concepts.ListenerRegistration; public interface RouteChangePublisher { - ListenerRegistration> registerRouteChangeListener(RouteChangeListener listener); + > ListenerRegistration registerRouteChangeListener(L listener); } diff --git a/opendaylight/md-sal/sal-common-impl/src/main/java/org/opendaylight/controller/md/sal/common/impl/routing/RoutingUtils.java b/opendaylight/md-sal/sal-common-impl/src/main/java/org/opendaylight/controller/md/sal/common/impl/routing/RoutingUtils.java new file mode 100644 index 0000000000..60d0cdf766 --- /dev/null +++ b/opendaylight/md-sal/sal-common-impl/src/main/java/org/opendaylight/controller/md/sal/common/impl/routing/RoutingUtils.java @@ -0,0 +1,92 @@ +package org.opendaylight.controller.md.sal.common.impl.routing; + +import java.util.Map; +import java.util.Set; + +import org.opendaylight.controller.md.sal.common.api.routing.RouteChange; + +import com.google.common.collect.ImmutableMap; +import com.google.common.collect.ImmutableSet; + +public class RoutingUtils { + + public static RouteChange removalChange(C context,P path) { + final ImmutableMap> announcements = ImmutableMap.>of(); + final ImmutableMap> removals = ImmutableMap.>of(context, ImmutableSet.of(path)); + return new RouteChangeImpl(announcements, removals); + } + + public static RouteChange announcementChange(C context,P path) { + final ImmutableMap> announcements = ImmutableMap.>of(context, ImmutableSet.of(path)); + final ImmutableMap> removals = ImmutableMap.>of(); + return new RouteChangeImpl(announcements, removals); + } + + + public static RouteChange change(Map> announcements, + Map> removals) { + final ImmutableMap> immutableAnnouncements = ImmutableMap.>copyOf(announcements); + final ImmutableMap> immutableRemovals = ImmutableMap.>copyOf(removals); + return new RouteChangeImpl(immutableAnnouncements, immutableRemovals); + } + + + private static class RouteChangeImpl implements RouteChange { + private final Map> removal; + private final Map> announcement; + + public RouteChangeImpl(ImmutableMap> removal, ImmutableMap> announcement) { + super(); + this.removal = removal; + this.announcement = announcement; + } + + @Override + public Map> getAnnouncements() { + return announcement; + } + + @Override + public Map> getRemovals() { + return removal; + } + + @Override + public int hashCode() { + final int prime = 31; + int result = 1; + result = prime * result + ((announcement == null) ? 0 : announcement.hashCode()); + result = prime * result + ((removal == null) ? 0 : removal.hashCode()); + return result; + } + + @Override + public boolean equals(Object obj) { + if (this == obj) { + return true; + } + if (obj == null) { + return false; + } + if (getClass() != obj.getClass()) { + return false; + } + RouteChangeImpl other = (RouteChangeImpl) obj; + if (announcement == null) { + if (other.announcement != null) + return false; + } else if (!announcement.equals(other.announcement)) + return false; + if (removal == null) { + if (other.removal != null) { + return false; + } + } else if (!removal.equals(other.removal)) + return false; + return true; + } + } + + + +} diff --git a/opendaylight/md-sal/sal-common-util/pom.xml b/opendaylight/md-sal/sal-common-util/pom.xml index 7e8069a9b3..ff15e72ba6 100644 --- a/opendaylight/md-sal/sal-common-util/pom.xml +++ b/opendaylight/md-sal/sal-common-util/pom.xml @@ -23,6 +23,10 @@ concepts 0.1.1-SNAPSHOT + + com.google.guava + guava + bundle diff --git a/opendaylight/md-sal/sal-common-util/src/main/java/org/opendaylight/controller/sal/common/util/Rpcs.java b/opendaylight/md-sal/sal-common-util/src/main/java/org/opendaylight/controller/sal/common/util/Rpcs.java index 54e1a065f4..356ec8ff7c 100644 --- a/opendaylight/md-sal/sal-common-util/src/main/java/org/opendaylight/controller/sal/common/util/Rpcs.java +++ b/opendaylight/md-sal/sal-common-util/src/main/java/org/opendaylight/controller/sal/common/util/Rpcs.java @@ -11,17 +11,31 @@ import java.io.Serializable; import java.util.ArrayList; import java.util.Collection; import java.util.Collections; + +import org.opendaylight.yangtools.concepts.Immutable; import org.opendaylight.yangtools.yang.common.RpcError; import org.opendaylight.yangtools.yang.common.RpcResult; +import com.google.common.collect.ImmutableList; + public class Rpcs { + + public static RpcResult getRpcResult(boolean successful) { + RpcResult ret = new RpcResultTO(successful, null, ImmutableList.of()); + return ret; + } + public static RpcResult getRpcResult(boolean successful, T result, Collection errors) { RpcResult ret = new RpcResultTO(successful, result, errors); return ret; } - private static class RpcResultTO implements RpcResult, Serializable { + public static RpcResult getRpcResult(boolean successful, Collection errors) { + return new RpcResultTO(successful, null, errors); + } + + private static class RpcResultTO implements RpcResult, Serializable, Immutable { private final Collection errors; private final T result; @@ -31,8 +45,7 @@ public class Rpcs { Collection errors) { this.successful = successful; this.result = result; - this.errors = Collections.unmodifiableList(new ArrayList( - errors)); + this.errors = ImmutableList.copyOf(errors); } @Override diff --git a/opendaylight/md-sal/sal-dom-broker/src/main/java/org/opendaylight/controller/sal/dom/broker/BrokerImpl.xtend b/opendaylight/md-sal/sal-dom-broker/src/main/java/org/opendaylight/controller/sal/dom/broker/BrokerImpl.xtend index 7ef594bad9..8f179987b9 100644 --- a/opendaylight/md-sal/sal-dom-broker/src/main/java/org/opendaylight/controller/sal/dom/broker/BrokerImpl.xtend +++ b/opendaylight/md-sal/sal-dom-broker/src/main/java/org/opendaylight/controller/sal/dom/broker/BrokerImpl.xtend @@ -29,8 +29,10 @@ import org.slf4j.LoggerFactory import org.opendaylight.controller.sal.dom.broker.spi.RpcRouter import org.opendaylight.yangtools.concepts.ListenerRegistration import org.opendaylight.controller.sal.core.api.RpcRegistrationListener +import org.opendaylight.controller.sal.core.api.RpcProvisionRegistry +import org.opendaylight.controller.sal.core.api.RpcImplementation -public class BrokerImpl implements Broker, AutoCloseable { +public class BrokerImpl implements Broker, RpcProvisionRegistry, AutoCloseable { private static val log = LoggerFactory.getLogger(BrokerImpl); // Broker Generic Context @@ -115,4 +117,12 @@ public class BrokerImpl implements Broker, AutoCloseable { deactivator?.close(); } + override addRpcImplementation(QName rpcType, RpcImplementation implementation) throws IllegalArgumentException { + router.addRpcImplementation(rpcType,implementation); + } + + override addRoutedRpcImplementation(QName rpcType, RpcImplementation implementation) { + router.addRoutedRpcImplementation(rpcType,implementation); + } + } diff --git a/opendaylight/md-sal/sal-dom-broker/src/main/java/org/opendaylight/controller/sal/dom/broker/impl/RpcRouterImpl.xtend b/opendaylight/md-sal/sal-dom-broker/src/main/java/org/opendaylight/controller/sal/dom/broker/impl/RpcRouterImpl.xtend index d8680ce3b4..5ee19a0e8f 100644 --- a/opendaylight/md-sal/sal-dom-broker/src/main/java/org/opendaylight/controller/sal/dom/broker/impl/RpcRouterImpl.xtend +++ b/opendaylight/md-sal/sal-dom-broker/src/main/java/org/opendaylight/controller/sal/dom/broker/impl/RpcRouterImpl.xtend @@ -15,6 +15,8 @@ import org.opendaylight.yangtools.concepts.AbstractObjectRegistration import org.opendaylight.controller.sal.core.api.RpcRegistrationListener import org.slf4j.LoggerFactory import org.opendaylight.yangtools.concepts.util.ListenerRegistry +import org.opendaylight.controller.sal.core.api.Broker.RoutedRpcRegistration +import org.opendaylight.yangtools.yang.data.api.InstanceIdentifier class RpcRouterImpl implements RpcRouter, Identifiable { @@ -35,6 +37,20 @@ class RpcRouterImpl implements RpcRouter, Identifiable { } override addRoutedRpcImplementation(QName rpcType, RpcImplementation implementation) { + checkNotNull(rpcType, "Rpc Type should not be null"); + checkNotNull(implementation, "Implementation should not be null."); + val reg = new RoutedRpcRegistrationImpl(rpcType, implementation, this); + implementations.put(rpcType, reg) + + for (listener : rpcRegistrationListeners.listeners) { + try { + listener.instance.onRpcImplementationAdded(rpcType); + } catch (Exception e) { + log.error("Unhandled exception during invoking listener", e); + } + } + + return reg; } override addRpcImplementation(QName rpcType, RpcImplementation implementation) throws IllegalArgumentException { @@ -102,5 +118,23 @@ class RpcRegistrationImpl extends AbstractObjectRegistration override protected removeRegistration() { router.remove(this); } +} +class RoutedRpcRegistrationImpl extends RpcRegistrationImpl implements RoutedRpcRegistration { + + + new(QName type, RpcImplementation instance, RpcRouterImpl router) { + super(type,instance,router) + } + override protected removeRegistration() { + router.remove(this); + } + override registerPath(QName context, InstanceIdentifier path) { + // + + } + + override unregisterPath(QName context, InstanceIdentifier path) { + // + } } diff --git a/opendaylight/md-sal/sal-dom-broker/src/main/java/org/opendaylight/controller/sal/dom/broker/impl/SchemaAwareDataStoreAdapter.java b/opendaylight/md-sal/sal-dom-broker/src/main/java/org/opendaylight/controller/sal/dom/broker/impl/SchemaAwareDataStoreAdapter.java index 4f4fadcc44..75e96491b6 100644 --- a/opendaylight/md-sal/sal-dom-broker/src/main/java/org/opendaylight/controller/sal/dom/broker/impl/SchemaAwareDataStoreAdapter.java +++ b/opendaylight/md-sal/sal-dom-broker/src/main/java/org/opendaylight/controller/sal/dom/broker/impl/SchemaAwareDataStoreAdapter.java @@ -151,19 +151,20 @@ public class SchemaAwareDataStoreAdapter extends AbstractLockableDelegator original) { // NOOP for now NormalizedDataModification normalized = new NormalizedDataModification(original); - for (Entry entry : original.getUpdatedConfigurationData().entrySet()) { + for (Entry entry : original.getUpdatedConfigurationData().entrySet()) { normalized.putConfigurationData(entry.getKey(), entry.getValue()); } - for (Entry entry : original.getUpdatedOperationalData().entrySet()) { + for (Entry entry : original.getUpdatedOperationalData().entrySet()) { normalized.putOperationalData(entry.getKey(), entry.getValue()); } for (InstanceIdentifier entry : original.getRemovedConfigurationData()) { normalized.removeConfigurationData(entry); } - for(InstanceIdentifier entry : original.getRemovedOperationalData()) { + for (InstanceIdentifier entry : original.getRemovedOperationalData()) { normalized.removeOperationalData(entry); } return normalized; @@ -284,7 +285,7 @@ public class SchemaAwareDataStoreAdapter extends AbstractLockableDelegator { private Object identifier; @@ -295,12 +296,12 @@ public class SchemaAwareDataStoreAdapter extends AbstractLockableDelegator> commit() { throw new UnsupportedOperationException("Commit should not be invoked on this"); } - + @Override - protected CompositeNode mergeConfigurationData(InstanceIdentifier path,CompositeNode stored, CompositeNode modified) { - return mergeData(path,stored, modified,true); + protected CompositeNode mergeConfigurationData(InstanceIdentifier path, CompositeNode stored, + CompositeNode modified) { + return mergeData(path, stored, modified, true); } - + @Override - protected CompositeNode mergeOperationalData(InstanceIdentifier path,CompositeNode stored, CompositeNode modified) { + protected CompositeNode mergeOperationalData(InstanceIdentifier path, CompositeNode stored, + CompositeNode modified) { // TODO Auto-generated method stub - return mergeData(path,stored,modified,false); + return mergeData(path, stored, modified, false); } - } } diff --git a/opendaylight/md-sal/sal-dom-broker/src/main/java/org/opendaylight/yangtools/yang/util/YangSchemaUtils.java b/opendaylight/md-sal/sal-dom-broker/src/main/java/org/opendaylight/yangtools/yang/util/YangSchemaUtils.java index 44ee2a31b0..3ff1d1d6cb 100644 --- a/opendaylight/md-sal/sal-dom-broker/src/main/java/org/opendaylight/yangtools/yang/util/YangSchemaUtils.java +++ b/opendaylight/md-sal/sal-dom-broker/src/main/java/org/opendaylight/yangtools/yang/util/YangSchemaUtils.java @@ -80,10 +80,11 @@ public class YangSchemaUtils { checkArgument(!iterator.hasNext(), "Path nests inside leaf node, which is not allowed."); return currentNode; } + checkState(currentNode != null, "Current node should not be null for %s",path); } + checkState(previous instanceof DataSchemaNode, "Schema node for %s should be instance of DataSchemaNode. Found %s",path,previous); return (DataSchemaNode) previous; } - private static DataSchemaNode searchInChoices(DataNodeContainer node, QName arg) { Set children = node.getChildNodes(); diff --git a/opendaylight/md-sal/statistics-manager/src/main/java/org/opendaylight/controller/md/statistics/manager/MultipartMessageManager.java b/opendaylight/md-sal/statistics-manager/src/main/java/org/opendaylight/controller/md/statistics/manager/MultipartMessageManager.java new file mode 100644 index 0000000000..11cce72ef1 --- /dev/null +++ b/opendaylight/md-sal/statistics-manager/src/main/java/org/opendaylight/controller/md/statistics/manager/MultipartMessageManager.java @@ -0,0 +1,37 @@ +/* + * Copyright IBM Corporation, 2013. All rights reserved. + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License v1.0 which accompanies this distribution, + * and is available at http://www.eclipse.org/legal/epl-v10.html + */ +package org.opendaylight.controller.md.statistics.manager; + +import java.util.Map; +import java.util.concurrent.ConcurrentHashMap; + +import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.transaction.rev131103.TransactionId; + +/** + * Main responsibility of the class is to manage multipart response + * for multipart request. It also handles the flow aggregate request + * and response mapping. + * @author avishnoi@in.ibm.com + * + */ +public class MultipartMessageManager { + + private static Map txIdTotableIdMap = new ConcurrentHashMap(); + + public MultipartMessageManager(){} + + public Short getTableIdForTxId(TransactionId id){ + + return txIdTotableIdMap.get(id); + + } + + public void setTxIdAndTableIdMapEntry(TransactionId id,Short tableId){ + txIdTotableIdMap.put(id, tableId); + } +} diff --git a/opendaylight/md-sal/statistics-manager/src/main/java/org/opendaylight/controller/md/statistics/manager/NodeStatistics.java b/opendaylight/md-sal/statistics-manager/src/main/java/org/opendaylight/controller/md/statistics/manager/NodeStatistics.java index c48ac311ab..a659a40886 100644 --- a/opendaylight/md-sal/statistics-manager/src/main/java/org/opendaylight/controller/md/statistics/manager/NodeStatistics.java +++ b/opendaylight/md-sal/statistics-manager/src/main/java/org/opendaylight/controller/md/statistics/manager/NodeStatistics.java @@ -7,15 +7,24 @@ */ package org.opendaylight.controller.md.statistics.manager; +import java.util.HashMap; import java.util.List; +import java.util.Map; +import java.util.concurrent.ConcurrentHashMap; +import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.tables.table.Flow; +import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.statistics.rev130819.aggregate.flow.statistics.AggregateFlowStatistics; import org.opendaylight.yang.gen.v1.urn.opendaylight.group.statistics.rev131111.group.features.GroupFeatures; import org.opendaylight.yang.gen.v1.urn.opendaylight.group.types.rev131018.group.desc.stats.reply.GroupDescStats; import org.opendaylight.yang.gen.v1.urn.opendaylight.group.types.rev131018.group.statistics.reply.GroupStats; +import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.NodeConnectorId; import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.NodeRef; import org.opendaylight.yang.gen.v1.urn.opendaylight.meter.statistics.rev131111.nodes.node.MeterFeatures; import org.opendaylight.yang.gen.v1.urn.opendaylight.meter.types.rev130918.meter.config.stats.reply.MeterConfigStats; import org.opendaylight.yang.gen.v1.urn.opendaylight.meter.types.rev130918.meter.statistics.reply.MeterStats; +import org.opendaylight.yang.gen.v1.urn.opendaylight.model.statistics.types.rev130925.GenericStatistics; +import org.opendaylight.yang.gen.v1.urn.opendaylight.model.statistics.types.rev130925.GenericTableStatistics; +import org.opendaylight.yang.gen.v1.urn.opendaylight.model.statistics.types.rev130925.NodeConnectorStatistics; public class NodeStatistics { @@ -33,6 +42,18 @@ public class NodeStatistics { private MeterFeatures meterFeatures; + private final Map> flowAndStatsMap= + new HashMap>(); + + private final Map tableAndAggregateFlowStatsMap = + new HashMap(); + + private final Map nodeConnectorStats = + new ConcurrentHashMap(); + + private final Map flowTableAndStatisticsMap = + new HashMap(); + public NodeStatistics(){ } @@ -92,5 +113,19 @@ public class NodeStatistics { public void setMeterFeatures(MeterFeatures meterFeatures) { this.meterFeatures = meterFeatures; } - + + public Map> getFlowAndStatsMap() { + return flowAndStatsMap; + } + + public Map getFlowTableAndStatisticsMap() { + return flowTableAndStatisticsMap; + } + + public Map getTableAndAggregateFlowStatsMap() { + return tableAndAggregateFlowStatsMap; + } + public Map getNodeConnectorStats() { + return nodeConnectorStats; + } } diff --git a/opendaylight/md-sal/statistics-manager/src/main/java/org/opendaylight/controller/md/statistics/manager/StatisticsProvider.java b/opendaylight/md-sal/statistics-manager/src/main/java/org/opendaylight/controller/md/statistics/manager/StatisticsProvider.java index f22ca00b2a..b7b4082118 100644 --- a/opendaylight/md-sal/statistics-manager/src/main/java/org/opendaylight/controller/md/statistics/manager/StatisticsProvider.java +++ b/opendaylight/md-sal/statistics-manager/src/main/java/org/opendaylight/controller/md/statistics/manager/StatisticsProvider.java @@ -7,9 +7,11 @@ */ package org.opendaylight.controller.md.statistics.manager; +import java.util.ArrayList; import java.util.List; import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.ConcurrentMap; +import java.util.concurrent.ExecutionException; import java.util.concurrent.Future; import org.eclipse.xtext.xbase.lib.Exceptions; @@ -17,6 +19,15 @@ import org.opendaylight.controller.sal.binding.api.NotificationProviderService; import org.opendaylight.controller.sal.binding.api.data.DataModificationTransaction; import org.opendaylight.controller.sal.binding.api.data.DataProviderService; import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.FlowCapableNode; +import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.tables.Table; +import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.statistics.rev130819.GetAggregateFlowStatisticsFromFlowTableForAllFlowsInputBuilder; +import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.statistics.rev130819.GetAggregateFlowStatisticsFromFlowTableForAllFlowsOutput; +import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.statistics.rev130819.GetAllFlowsStatisticsFromAllFlowTablesInputBuilder; +import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.statistics.rev130819.GetAllFlowsStatisticsFromAllFlowTablesOutput; +import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.statistics.rev130819.OpendaylightFlowStatisticsService; +import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.table.statistics.rev131215.GetFlowTablesStatisticsInputBuilder; +import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.table.statistics.rev131215.GetFlowTablesStatisticsOutput; +import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.table.statistics.rev131215.OpendaylightFlowTableStatisticsService; import org.opendaylight.yang.gen.v1.urn.opendaylight.group.statistics.rev131111.GetAllGroupStatisticsInputBuilder; import org.opendaylight.yang.gen.v1.urn.opendaylight.group.statistics.rev131111.GetAllGroupStatisticsOutput; import org.opendaylight.yang.gen.v1.urn.opendaylight.group.statistics.rev131111.GetGroupDescriptionInputBuilder; @@ -26,11 +37,15 @@ import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.NodeId; import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.NodeRef; import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.Nodes; import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.nodes.Node; +import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.nodes.NodeKey; import org.opendaylight.yang.gen.v1.urn.opendaylight.meter.statistics.rev131111.GetAllMeterConfigStatisticsInputBuilder; import org.opendaylight.yang.gen.v1.urn.opendaylight.meter.statistics.rev131111.GetAllMeterConfigStatisticsOutput; import org.opendaylight.yang.gen.v1.urn.opendaylight.meter.statistics.rev131111.GetAllMeterStatisticsInputBuilder; import org.opendaylight.yang.gen.v1.urn.opendaylight.meter.statistics.rev131111.GetAllMeterStatisticsOutput; import org.opendaylight.yang.gen.v1.urn.opendaylight.meter.statistics.rev131111.OpendaylightMeterStatisticsService; +import org.opendaylight.yang.gen.v1.urn.opendaylight.port.statistics.rev131214.GetAllPortsStatisticsInputBuilder; +import org.opendaylight.yang.gen.v1.urn.opendaylight.port.statistics.rev131214.GetAllPortsStatisticsOutput; +import org.opendaylight.yang.gen.v1.urn.opendaylight.port.statistics.rev131214.OpendaylightPortStatisticsService; import org.opendaylight.yangtools.concepts.Registration; import org.opendaylight.yangtools.yang.binding.InstanceIdentifier; import org.opendaylight.yangtools.yang.binding.NotificationListener; @@ -50,6 +65,14 @@ public class StatisticsProvider implements AutoCloseable { private OpendaylightMeterStatisticsService meterStatsService; + private OpendaylightFlowStatisticsService flowStatsService; + + private OpendaylightPortStatisticsService portStatsService; + + private OpendaylightFlowTableStatisticsService flowTableStatsService; + + private final MultipartMessageManager multipartMessageManager = new MultipartMessageManager(); + private Thread statisticsRequesterThread; private final InstanceIdentifier nodesIdentifier = InstanceIdentifier.builder(Nodes.class).toInstance(); @@ -76,6 +99,10 @@ public class StatisticsProvider implements AutoCloseable { this.nps = notificationService; } + public MultipartMessageManager getMultipartMessageManager() { + return multipartMessageManager; + } + private final StatisticsUpdateCommiter updateCommiter = new StatisticsUpdateCommiter(StatisticsProvider.this); private Registration listenerRegistration; @@ -92,7 +119,16 @@ public class StatisticsProvider implements AutoCloseable { meterStatsService = StatisticsManagerActivator.getProviderContext(). getRpcService(OpendaylightMeterStatisticsService.class); + + flowStatsService = StatisticsManagerActivator.getProviderContext(). + getRpcService(OpendaylightFlowStatisticsService.class); + + portStatsService = StatisticsManagerActivator.getProviderContext(). + getRpcService(OpendaylightPortStatisticsService.class); + flowTableStatsService = StatisticsManagerActivator.getProviderContext(). + getRpcService(OpendaylightFlowTableStatisticsService.class); + statisticsRequesterThread = new Thread( new Runnable(){ @Override @@ -124,21 +160,35 @@ public class StatisticsProvider implements AutoCloseable { private void statsRequestSender(){ - //Need to call API to receive all the nodes connected to controller. List targetNodes = getAllConnectedNodes(); if(targetNodes == null) return; + for (Node targetNode : targetNodes){ + + InstanceIdentifier targetInstanceId = InstanceIdentifier.builder(Nodes.class).child(Node.class,targetNode.getKey()).toInstance(); + NodeRef targetNodeRef = new NodeRef(targetInstanceId); + + try { + + sendAggregateFlowsStatsFromAllTablesRequest(targetNode.getKey()); + + sendAllFlowsStatsFromAllTablesRequest(targetNodeRef); + + sendAllPortStatisticsRequest(targetNodeRef); + + sendAllFlowTablesStatisticsRequest(targetNodeRef); + + }catch(Exception e){ + spLogger.error("Exception occured while sending statistics requests : {}",e); + } if(targetNode.getAugmentation(FlowCapableNode.class) != null){ spLogger.info("Send request for stats collection to node : {})",targetNode.getId()); - - InstanceIdentifier targetInstanceId = InstanceIdentifier.builder(Nodes.class).child(Node.class,targetNode.getKey()).toInstance(); - NodeRef targetNodeRef = new NodeRef(targetInstanceId); - + try{ sendAllGroupStatisticsRequest(targetNodeRef); Thread.sleep(1000); @@ -149,17 +199,85 @@ public class StatisticsProvider implements AutoCloseable { sendMeterConfigStatisticsRequest(targetNodeRef); Thread.sleep(1000); }catch(Exception e){ - spLogger.error("Exception occured while sending statistics request : {}", e); + spLogger.error("Exception occured while sending statistics requests : {}", e); } } } } + + private void sendAllFlowTablesStatisticsRequest(NodeRef targetNodeRef) { + final GetFlowTablesStatisticsInputBuilder input = + new GetFlowTablesStatisticsInputBuilder(); + + input.setNode(targetNodeRef); + + @SuppressWarnings("unused") + Future> response = + flowTableStatsService.getFlowTablesStatistics(input.build()); + } + + private void sendAllFlowsStatsFromAllTablesRequest(NodeRef targetNode){ + final GetAllFlowsStatisticsFromAllFlowTablesInputBuilder input = + new GetAllFlowsStatisticsFromAllFlowTablesInputBuilder(); + + input.setNode(targetNode); + + @SuppressWarnings("unused") + Future> response = + flowStatsService.getAllFlowsStatisticsFromAllFlowTables(input.build()); + + } + private void sendAggregateFlowsStatsFromAllTablesRequest(NodeKey targetNodeKey) throws InterruptedException, ExecutionException{ + + List tablesId = getTablesFromNode(targetNodeKey); + + if(tablesId.size() != 0){ + for(Short id : tablesId){ + + spLogger.info("Send aggregate stats request for flow table {} to node {}",id,targetNodeKey); + GetAggregateFlowStatisticsFromFlowTableForAllFlowsInputBuilder input = + new GetAggregateFlowStatisticsFromFlowTableForAllFlowsInputBuilder(); + + input.setNode(new NodeRef(InstanceIdentifier.builder(Nodes.class).child(Node.class, targetNodeKey).toInstance())); + input.setTableId(new org.opendaylight.yang.gen.v1.urn.opendaylight.table.types.rev131026.TableId(id)); + Future> response = + flowStatsService.getAggregateFlowStatisticsFromFlowTableForAllFlows(input.build()); + + multipartMessageManager.setTxIdAndTableIdMapEntry(response.get().getResult().getTransactionId(), id); + } + } + + //Note: Just for testing, because i am not able to fetch table list from datastore + // Bug-225 is raised for investigation. + +// spLogger.info("Send aggregate stats request for flow table {} to node {}",1,targetNodeKey); +// GetAggregateFlowStatisticsFromFlowTableForAllFlowsInputBuilder input = +// new GetAggregateFlowStatisticsFromFlowTableForAllFlowsInputBuilder(); +// +// input.setNode(new NodeRef(InstanceIdentifier.builder(Nodes.class).child(Node.class, targetNodeKey).toInstance())); +// input.setTableId(new TableId((short)1)); +// Future> response = +// flowStatsService.getAggregateFlowStatisticsFromFlowTableForAllFlows(input.build());` +// +// multipartMessageManager.setTxIdAndTableIdMapEntry(response.get().getResult().getTransactionId(), (short)1); + } + + private void sendAllPortStatisticsRequest(NodeRef targetNode){ + + final GetAllPortsStatisticsInputBuilder input = new GetAllPortsStatisticsInputBuilder(); + + input.setNode(targetNode); + + @SuppressWarnings("unused") + Future> response = + portStatsService.getAllPortsStatistics(input.build()); + } + private void sendAllGroupStatisticsRequest(NodeRef targetNode){ final GetAllGroupStatisticsInputBuilder input = new GetAllGroupStatisticsInputBuilder(); - input.setNode(targetNode); input.setNode(targetNode); @SuppressWarnings("unused") @@ -213,6 +331,20 @@ public class StatisticsProvider implements AutoCloseable { spLogger.info("Number of connected nodes : {}",nodes.getNode().size()); return nodes.getNode(); } + + private List getTablesFromNode(NodeKey nodeKey){ + InstanceIdentifier nodesIdentifier = InstanceIdentifier.builder(Nodes.class).child(Node.class,nodeKey).augmentation(FlowCapableNode.class).toInstance(); + + FlowCapableNode node = (FlowCapableNode)dps.readConfigurationData(nodesIdentifier); + List tablesId = new ArrayList(); + if(node != null && node.getTable()!=null){ + spLogger.info("Number of tables {} supported by node {}",node.getTable().size(),nodeKey); + for(Table table: node.getTable()){ + tablesId.add(table.getId()); + } + } + return tablesId; + } @SuppressWarnings("deprecation") @Override diff --git a/opendaylight/md-sal/statistics-manager/src/main/java/org/opendaylight/controller/md/statistics/manager/StatisticsUpdateCommiter.java b/opendaylight/md-sal/statistics-manager/src/main/java/org/opendaylight/controller/md/statistics/manager/StatisticsUpdateCommiter.java index 86e6114b5f..a4a7e1e661 100644 --- a/opendaylight/md-sal/statistics-manager/src/main/java/org/opendaylight/controller/md/statistics/manager/StatisticsUpdateCommiter.java +++ b/opendaylight/md-sal/statistics-manager/src/main/java/org/opendaylight/controller/md/statistics/manager/StatisticsUpdateCommiter.java @@ -7,9 +7,39 @@ */ package org.opendaylight.controller.md.statistics.manager; +import java.util.HashMap; +import java.util.List; import java.util.concurrent.ConcurrentMap; import org.opendaylight.controller.sal.binding.api.data.DataModificationTransaction; +import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.FlowCapableNode; +import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.FlowId; +import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.tables.Table; +import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.tables.TableBuilder; +import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.tables.TableKey; +import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.tables.table.Flow; +import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.tables.table.FlowBuilder; +import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.tables.table.FlowKey; +import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.statistics.rev130819.AggregateFlowStatisticsData; +import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.statistics.rev130819.AggregateFlowStatisticsDataBuilder; +import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.statistics.rev130819.AggregateFlowStatisticsUpdate; +import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.statistics.rev130819.FlowStatisticsData; +import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.statistics.rev130819.FlowStatisticsDataBuilder; +import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.statistics.rev130819.FlowStatisticsUpdated; +import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.statistics.rev130819.FlowTableStatisticsUpdated; +import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.statistics.rev130819.FlowsStatisticsUpdate; +import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.statistics.rev130819.NodeConnectorStatisticsUpdated; +import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.statistics.rev130819.OpendaylightFlowStatisticsListener; +import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.statistics.rev130819.aggregate.flow.statistics.AggregateFlowStatisticsBuilder; +import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.statistics.rev130819.flow.and.statistics.map.list.FlowAndStatisticsMapList; +import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.statistics.rev130819.flow.and.statistics.map.list.FlowAndStatisticsMapListBuilder; +import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.statistics.rev130819.flow.statistics.FlowStatisticsBuilder; +import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.table.statistics.rev131215.FlowTableStatisticsData; +import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.table.statistics.rev131215.FlowTableStatisticsDataBuilder; +import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.table.statistics.rev131215.FlowTableStatisticsUpdate; +import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.table.statistics.rev131215.OpendaylightFlowTableStatisticsListener; +import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.table.statistics.rev131215.flow.table.and.statistics.map.FlowTableAndStatisticsMap; +import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.table.statistics.rev131215.flow.table.statistics.FlowTableStatisticsBuilder; import org.opendaylight.yang.gen.v1.urn.opendaylight.group.statistics.rev131111.GroupDescStatsUpdated; import org.opendaylight.yang.gen.v1.urn.opendaylight.group.statistics.rev131111.GroupFeaturesUpdated; import org.opendaylight.yang.gen.v1.urn.opendaylight.group.statistics.rev131111.GroupStatisticsUpdated; @@ -26,6 +56,9 @@ import org.opendaylight.yang.gen.v1.urn.opendaylight.group.statistics.rev131111. import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.NodeId; import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.NodeRef; import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.Nodes; +import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.node.NodeConnector; +import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.node.NodeConnectorBuilder; +import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.node.NodeConnectorKey; import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.nodes.Node; import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.nodes.NodeBuilder; import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.nodes.NodeKey; @@ -42,13 +75,29 @@ import org.opendaylight.yang.gen.v1.urn.opendaylight.meter.statistics.rev131111. import org.opendaylight.yang.gen.v1.urn.opendaylight.meter.statistics.rev131111.nodes.node.MeterConfigStatsBuilder; import org.opendaylight.yang.gen.v1.urn.opendaylight.meter.statistics.rev131111.nodes.node.MeterFeaturesBuilder; import org.opendaylight.yang.gen.v1.urn.opendaylight.meter.statistics.rev131111.nodes.node.MeterStatisticsBuilder; +import org.opendaylight.yang.gen.v1.urn.opendaylight.model.statistics.types.rev130925.GenericStatistics; +import org.opendaylight.yang.gen.v1.urn.opendaylight.port.statistics.rev131214.FlowCapableNodeConnectorStatisticsData; +import org.opendaylight.yang.gen.v1.urn.opendaylight.port.statistics.rev131214.FlowCapableNodeConnectorStatisticsDataBuilder; +import org.opendaylight.yang.gen.v1.urn.opendaylight.port.statistics.rev131214.OpendaylightPortStatisticsListener; +import org.opendaylight.yang.gen.v1.urn.opendaylight.port.statistics.rev131214.PortStatisticsUpdate; +import org.opendaylight.yang.gen.v1.urn.opendaylight.port.statistics.rev131214.flow.capable.node.connector.statistics.FlowCapableNodeConnectorStatisticsBuilder; +import org.opendaylight.yang.gen.v1.urn.opendaylight.port.statistics.rev131214.node.connector.statistics.and.port.number.map.NodeConnectorStatisticsAndPortNumberMap; import org.opendaylight.yangtools.yang.binding.InstanceIdentifier; import org.opendaylight.yangtools.yang.binding.InstanceIdentifier.InstanceIdentifierBuilder; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; public class StatisticsUpdateCommiter implements OpendaylightGroupStatisticsListener, - OpendaylightMeterStatisticsListener { + OpendaylightMeterStatisticsListener, + OpendaylightFlowStatisticsListener, + OpendaylightPortStatisticsListener, + OpendaylightFlowTableStatisticsListener{ + public final static Logger sucLogger = LoggerFactory.getLogger(StatisticsUpdateCommiter.class); + private final StatisticsProvider statisticsManager; + + private final int unaccountedFlowsCounter = 1; public StatisticsUpdateCommiter(final StatisticsProvider manager){ @@ -264,9 +313,360 @@ public class StatisticsUpdateCommiter implements OpendaylightGroupStatisticsList it.commit(); } + @Override + public void onFlowsStatisticsUpdate(FlowsStatisticsUpdate notification) { + NodeKey key = new NodeKey(notification.getId()); + sucLogger.info("Received flow stats update : {}",notification.toString()); + + for(FlowAndStatisticsMapList map: notification.getFlowAndStatisticsMapList()){ + short tableId = map.getTableId(); + + DataModificationTransaction it = this.statisticsManager.startChange(); + + boolean foundOriginalFlow = false; + + FlowBuilder flowBuilder = new FlowBuilder(); + + FlowStatisticsDataBuilder flowStatisticsData = new FlowStatisticsDataBuilder(); + + FlowBuilder flow = new FlowBuilder(); + flow.setContainerName(map.getContainerName()); + flow.setBufferId(map.getBufferId()); + flow.setCookie(map.getCookie()); + flow.setCookieMask(map.getCookieMask()); + flow.setFlags(map.getFlags()); + flow.setFlowName(map.getFlowName()); + flow.setHardTimeout(map.getHardTimeout()); + if(map.getFlowId() != null) + flow.setId(new FlowId(map.getFlowId().getValue())); + flow.setIdleTimeout(map.getIdleTimeout()); + flow.setInstallHw(map.isInstallHw()); + flow.setInstructions(map.getInstructions()); + if(map.getFlowId()!= null) + flow.setKey(new FlowKey(new FlowId(map.getKey().getFlowId().getValue()))); + flow.setMatch(map.getMatch()); + flow.setOutGroup(map.getOutGroup()); + flow.setOutPort(map.getOutPort()); + flow.setPriority(map.getPriority()); + flow.setStrict(map.isStrict()); + flow.setTableId(tableId); + + Flow flowRule = flow.build(); + + FlowAndStatisticsMapListBuilder stats = new FlowAndStatisticsMapListBuilder(); + stats.setByteCount(map.getByteCount()); + stats.setPacketCount(map.getPacketCount()); + stats.setDuration(map.getDuration()); + + GenericStatistics flowStats = stats.build(); + + //Add statistics to local cache + ConcurrentMap cache = this.statisticsManager.getStatisticsCache(); + if(!cache.containsKey(notification.getId())){ + cache.put(notification.getId(), new NodeStatistics()); + } + if(!cache.get(notification.getId()).getFlowAndStatsMap().containsKey(tableId)){ + cache.get(notification.getId()).getFlowAndStatsMap().put(tableId, new HashMap()); + } + cache.get(notification.getId()).getFlowAndStatsMap().get(tableId).put(flowRule,flowStats); + + //Augment the data to the flow node + + FlowStatisticsBuilder flowStatistics = new FlowStatisticsBuilder(); + flowStatistics.setByteCount(flowStats.getByteCount()); + flowStatistics.setPacketCount(flowStats.getPacketCount()); + flowStatistics.setDuration(flowStats.getDuration()); + flowStatistics.setContainerName(map.getContainerName()); + flowStatistics.setBufferId(map.getBufferId()); + flowStatistics.setCookie(map.getCookie()); + flowStatistics.setCookieMask(map.getCookieMask()); + flowStatistics.setFlags(map.getFlags()); + flowStatistics.setFlowName(map.getFlowName()); + flowStatistics.setHardTimeout(map.getHardTimeout()); + flowStatistics.setIdleTimeout(map.getIdleTimeout()); + flowStatistics.setInstallHw(map.isInstallHw()); + flowStatistics.setInstructions(map.getInstructions()); + flowStatistics.setMatch(map.getMatch()); + flowStatistics.setOutGroup(map.getOutGroup()); + flowStatistics.setOutPort(map.getOutPort()); + flowStatistics.setPriority(map.getPriority()); + flowStatistics.setStrict(map.isStrict()); + flowStatistics.setTableId(tableId); + + flowStatisticsData.setFlowStatistics(flowStatistics.build()); + + sucLogger.info("Flow : {}",flowRule.toString()); + sucLogger.info("Statistics to augment : {}",flowStatistics.build().toString()); + + InstanceIdentifier tableRef = InstanceIdentifier.builder(Nodes.class).child(Node.class, key) + .augmentation(FlowCapableNode.class).child(Table.class, new TableKey(tableId)).toInstance(); + + Table table= (Table)it.readConfigurationData(tableRef); + + //TODO: Not a good way to do it, need to figure out better way. + //TODO: major issue in any alternate approach is that flow key is incrementally assigned + //to the flows stored in data store. + if(table != null){ + + for(Flow existingFlow : table.getFlow()){ + sucLogger.debug("Existing flow in data store : {}",existingFlow.toString()); + if(flowEquals(flowRule,existingFlow)){ + InstanceIdentifier flowRef = InstanceIdentifier.builder(Nodes.class).child(Node.class, key) + .augmentation(FlowCapableNode.class) + .child(Table.class, new TableKey(tableId)) + .child(Flow.class,existingFlow.getKey()).toInstance(); + flowBuilder.setKey(existingFlow.getKey()); + flowBuilder.addAugmentation(FlowStatisticsData.class, flowStatisticsData.build()); + sucLogger.debug("Found matching flow in the datastore, augmenting statistics"); + foundOriginalFlow = true; + it.putOperationalData(flowRef, flowBuilder.build()); + it.commit(); + break; + } + } + } + + if(!foundOriginalFlow){ + sucLogger.info("Associated original flow is not found in data store. Augmenting flow in operational data st"); + //TODO: Temporary fix: format [ 0+tableid+0+unaccounted flow counter] + long flowKey = Long.getLong(new String("0"+Short.toString(tableId)+"0"+Integer.toString(this.unaccountedFlowsCounter))); + FlowKey newFlowKey = new FlowKey(new FlowId(flowKey)); + InstanceIdentifier flowRef = InstanceIdentifier.builder(Nodes.class).child(Node.class, key) + .augmentation(FlowCapableNode.class) + .child(Table.class, new TableKey(tableId)) + .child(Flow.class,newFlowKey).toInstance(); + flowBuilder.setKey(newFlowKey); + flowBuilder.addAugmentation(FlowStatisticsData.class, flowStatisticsData.build()); + sucLogger.debug("Flow was no present in data store, augmenting statistics as an unaccounted flow"); + it.putOperationalData(flowRef, flowBuilder.build()); + it.commit(); + } + } + } + + @Override + public void onAggregateFlowStatisticsUpdate(AggregateFlowStatisticsUpdate notification) { + NodeKey key = new NodeKey(notification.getId()); + sucLogger.debug("Received aggregate flow statistics update : {}",notification.toString()); + + Short tableId = this.statisticsManager.getMultipartMessageManager().getTableIdForTxId(notification.getTransactionId()); + if(tableId != null){ + + DataModificationTransaction it = this.statisticsManager.startChange(); + + InstanceIdentifier
tableRef = InstanceIdentifier.builder(Nodes.class).child(Node.class, key) + .augmentation(FlowCapableNode.class).child(Table.class, new TableKey(tableId)).toInstance(); + + AggregateFlowStatisticsDataBuilder aggregateFlowStatisticsDataBuilder = new AggregateFlowStatisticsDataBuilder(); + AggregateFlowStatisticsBuilder aggregateFlowStatisticsBuilder = new AggregateFlowStatisticsBuilder(); + aggregateFlowStatisticsBuilder.setByteCount(notification.getByteCount()); + aggregateFlowStatisticsBuilder.setFlowCount(notification.getFlowCount()); + aggregateFlowStatisticsBuilder.setPacketCount(notification.getPacketCount()); + aggregateFlowStatisticsDataBuilder.setAggregateFlowStatistics(aggregateFlowStatisticsBuilder.build()); + + ConcurrentMap cache = this.statisticsManager.getStatisticsCache(); + if(!cache.containsKey(notification.getId())){ + cache.put(notification.getId(), new NodeStatistics()); + } + cache.get(notification.getId()).getTableAndAggregateFlowStatsMap().put(tableId,aggregateFlowStatisticsBuilder.build()); + + sucLogger.debug("Augment aggregate statistics: {} for table {} on Node {}",aggregateFlowStatisticsBuilder.build().toString(),tableId,key); + + TableBuilder tableBuilder = new TableBuilder(); + tableBuilder.setKey(new TableKey(tableId)); + tableBuilder.addAugmentation(AggregateFlowStatisticsData.class, aggregateFlowStatisticsDataBuilder.build()); + it.putOperationalData(tableRef, tableBuilder.build()); + it.commit(); + + } + } + + @Override + public void onPortStatisticsUpdate(PortStatisticsUpdate notification) { + NodeKey key = new NodeKey(notification.getId()); + sucLogger.info("Received port stats update : {}",notification.toString()); + + //Add statistics to local cache + ConcurrentMap cache = this.statisticsManager.getStatisticsCache(); + if(!cache.containsKey(notification.getId())){ + cache.put(notification.getId(), new NodeStatistics()); + } + + + List portsStats = notification.getNodeConnectorStatisticsAndPortNumberMap(); + for(NodeConnectorStatisticsAndPortNumberMap portStats : portsStats){ + + DataModificationTransaction it = this.statisticsManager.startChange(); + + FlowCapableNodeConnectorStatisticsBuilder statisticsBuilder + = new FlowCapableNodeConnectorStatisticsBuilder(); + statisticsBuilder.setBytes(portStats.getBytes()); + statisticsBuilder.setCollisionCount(portStats.getCollisionCount()); + statisticsBuilder.setDuration(portStats.getDuration()); + statisticsBuilder.setPackets(portStats.getPackets()); + statisticsBuilder.setReceiveCrcError(portStats.getReceiveCrcError()); + statisticsBuilder.setReceiveDrops(portStats.getReceiveDrops()); + statisticsBuilder.setReceiveErrors(portStats.getReceiveErrors()); + statisticsBuilder.setReceiveFrameError(portStats.getReceiveFrameError()); + statisticsBuilder.setReceiveOverRunError(portStats.getReceiveOverRunError()); + statisticsBuilder.setTransmitDrops(portStats.getTransmitDrops()); + statisticsBuilder.setTransmitErrors(portStats.getTransmitErrors()); + + //Update data in the cache + cache.get(notification.getId()).getNodeConnectorStats().put(portStats.getNodeConnectorId(), statisticsBuilder.build()); + + //Augment data to the node-connector + FlowCapableNodeConnectorStatisticsDataBuilder statisticsDataBuilder = + new FlowCapableNodeConnectorStatisticsDataBuilder(); + + statisticsDataBuilder.setFlowCapableNodeConnectorStatistics(statisticsBuilder.build()); + + InstanceIdentifier nodeConnectorRef = InstanceIdentifier.builder(Nodes.class).child(Node.class, key).child(NodeConnector.class, new NodeConnectorKey(portStats.getNodeConnectorId())).toInstance(); + + NodeConnector nodeConnector = (NodeConnector)it.readOperationalData(nodeConnectorRef); + + if(nodeConnector != null){ + sucLogger.debug("Augmenting port statistics {} to port {}",statisticsDataBuilder.build().toString(),nodeConnectorRef.toString()); + NodeConnectorBuilder nodeConnectorBuilder = new NodeConnectorBuilder(); + nodeConnectorBuilder.addAugmentation(FlowCapableNodeConnectorStatisticsData.class, statisticsDataBuilder.build()); + it.putOperationalData(nodeConnectorRef, nodeConnectorBuilder.build()); + it.commit(); + } + } + } + + @Override + public void onFlowTableStatisticsUpdate(FlowTableStatisticsUpdate notification) { + NodeKey key = new NodeKey(notification.getId()); + sucLogger.debug("Received flow table statistics update : {}",notification.toString()); + + List flowTablesStatsList = notification.getFlowTableAndStatisticsMap(); + for (FlowTableAndStatisticsMap ftStats : flowTablesStatsList){ + + DataModificationTransaction it = this.statisticsManager.startChange(); + + InstanceIdentifier
tableRef = InstanceIdentifier.builder(Nodes.class).child(Node.class, key) + .augmentation(FlowCapableNode.class).child(Table.class, new TableKey(ftStats.getTableId().getValue())).toInstance(); + + FlowTableStatisticsDataBuilder statisticsDataBuilder = new FlowTableStatisticsDataBuilder(); + + FlowTableStatisticsBuilder statisticsBuilder = new FlowTableStatisticsBuilder(); + statisticsBuilder.setActiveFlows(ftStats.getActiveFlows()); + statisticsBuilder.setPacketsLookedUp(ftStats.getPacketsLookedUp()); + statisticsBuilder.setPacketsMatched(ftStats.getPacketsMatched()); + + statisticsDataBuilder.setFlowTableStatistics(statisticsBuilder.build()); + + ConcurrentMap cache = this.statisticsManager.getStatisticsCache(); + if(!cache.containsKey(notification.getId())){ + cache.put(notification.getId(), new NodeStatistics()); + } + cache.get(notification.getId()).getFlowTableAndStatisticsMap().put(ftStats.getTableId().getValue(),statisticsBuilder.build()); + + sucLogger.debug("Augment flow table statistics: {} for table {} on Node {}",statisticsBuilder.build().toString(),ftStats.getTableId(),key); + + TableBuilder tableBuilder = new TableBuilder(); + tableBuilder.setKey(new TableKey(ftStats.getTableId().getValue())); + tableBuilder.addAugmentation(FlowTableStatisticsData.class, statisticsDataBuilder.build()); + it.putOperationalData(tableRef, tableBuilder.build()); + it.commit(); + } + } + + @Override + public void onFlowStatisticsUpdated(FlowStatisticsUpdated notification) { + // TODO Auto-generated method stub + //TODO: Depricated, will clean it up once sal-compatibility is fixed. + //Sal-Compatibility code usage this notification event. + + } + + @Override + public void onFlowTableStatisticsUpdated(FlowTableStatisticsUpdated notification) { + // TODO Auto-generated method stub + //TODO: Need to implement it yet + + } + + @Override + public void onNodeConnectorStatisticsUpdated(NodeConnectorStatisticsUpdated notification) { + // TODO Auto-generated method stub + //TODO: Need to implement it yet + + } + private NodeRef getNodeRef(NodeKey nodeKey){ InstanceIdentifierBuilder builder = InstanceIdentifier.builder(Nodes.class).child(Node.class, nodeKey); return new NodeRef(builder.toInstance()); } - + + public boolean flowEquals(Flow statsFlow, Flow storedFlow) { + if (statsFlow.getClass() != storedFlow.getClass()) { + return false; + } + if (statsFlow.getBufferId()== null) { + if (storedFlow.getBufferId() != null) { + return false; + } + } else if(!statsFlow.getBufferId().equals(storedFlow.getBufferId())) { + return false; + } + if (statsFlow.getContainerName()== null) { + if (storedFlow.getContainerName()!= null) { + return false; + } + } else if(!statsFlow.getContainerName().equals(storedFlow.getContainerName())) { + return false; + } + if (statsFlow.getCookie()== null) { + if (storedFlow.getCookie()!= null) { + return false; + } + } else if(!statsFlow.getCookie().equals(storedFlow.getCookie())) { + return false; + } + if (statsFlow.getMatch()== null) { + if (storedFlow.getMatch() != null) { + return false; + } + } else if(!statsFlow.getMatch().equals(storedFlow.getMatch())) { + return false; + } + if (statsFlow.getCookie()== null) { + if (storedFlow.getCookie()!= null) { + return false; + } + } else if(!statsFlow.getCookie().equals(storedFlow.getCookie())) { + return false; + } + if (statsFlow.getHardTimeout() == null) { + if (storedFlow.getHardTimeout() != null) { + return false; + } + } else if(!statsFlow.getHardTimeout().equals(storedFlow.getHardTimeout() )) { + return false; + } + if (statsFlow.getIdleTimeout()== null) { + if (storedFlow.getIdleTimeout() != null) { + return false; + } + } else if(!statsFlow.getIdleTimeout().equals(storedFlow.getIdleTimeout())) { + return false; + } + if (statsFlow.getPriority() == null) { + if (storedFlow.getPriority() != null) { + return false; + } + } else if(!statsFlow.getPriority().equals(storedFlow.getPriority())) { + return false; + } + if (statsFlow.getTableId() == null) { + if (storedFlow.getTableId() != null) { + return false; + } + } else if(!statsFlow.getTableId().equals(storedFlow.getTableId())) { + return false; + } + return true; + } } diff --git a/opendaylight/netconf/config-netconf-connector/src/main/java/org/opendaylight/controller/netconf/confignetconfconnector/mapping/attributes/AttributeIfcSwitchStatement.java b/opendaylight/netconf/config-netconf-connector/src/main/java/org/opendaylight/controller/netconf/confignetconfconnector/mapping/attributes/AttributeIfcSwitchStatement.java index 697b811d51..cf0e71e67a 100644 --- a/opendaylight/netconf/config-netconf-connector/src/main/java/org/opendaylight/controller/netconf/confignetconfconnector/mapping/attributes/AttributeIfcSwitchStatement.java +++ b/opendaylight/netconf/config-netconf-connector/src/main/java/org/opendaylight/controller/netconf/confignetconfconnector/mapping/attributes/AttributeIfcSwitchStatement.java @@ -29,12 +29,16 @@ public abstract class AttributeIfcSwitchStatement { this.lastAttribute = attributeIfc; + OpenType openType = attributeIfc.getOpenType(); + if (attributeIfc instanceof JavaAttribute) { try { if(((JavaAttribute)attributeIfc).getTypeDefinition() instanceof BinaryTypeDefinition) { - return caseJavaBinaryAttribute(attributeIfc.getOpenType()); + return caseJavaBinaryAttribute(openType); + } else if(((JavaAttribute)attributeIfc).isUnion()) { + return caseJavaUnionAttribute(openType); } else - return caseJavaAttribute(attributeIfc.getOpenType()); + return caseJavaAttribute(openType); } catch (UnknownOpenTypeException e) { throw getIllegalArgumentException(attributeIfc); } @@ -42,9 +46,9 @@ public abstract class AttributeIfcSwitchStatement { } else if (attributeIfc instanceof DependencyAttribute) { return caseDependencyAttribute(((DependencyAttribute) attributeIfc).getOpenType()); } else if (attributeIfc instanceof ListAttribute) { - return caseListAttribute((ArrayType) attributeIfc.getOpenType()); + return caseListAttribute((ArrayType) openType); } else if (attributeIfc instanceof ListDependenciesAttribute) { - return caseListDependeciesAttribute((ArrayType) attributeIfc.getOpenType()); + return caseListDependeciesAttribute((ArrayType) openType); } else if (attributeIfc instanceof TOAttribute) { return caseTOAttribute(((TOAttribute) attributeIfc).getOpenType()); } @@ -52,6 +56,10 @@ public abstract class AttributeIfcSwitchStatement { throw getIllegalArgumentException(attributeIfc); } + protected T caseJavaUnionAttribute(OpenType openType) { + return caseJavaAttribute(openType); + } + protected T caseJavaBinaryAttribute(OpenType openType) { return caseJavaAttribute(openType); } diff --git a/opendaylight/netconf/config-netconf-connector/src/main/java/org/opendaylight/controller/netconf/confignetconfconnector/mapping/attributes/AttributesConstants.java b/opendaylight/netconf/config-netconf-connector/src/main/java/org/opendaylight/controller/netconf/confignetconfconnector/mapping/attributes/AttributesConstants.java index 4f9e1fe087..23cdabf69f 100644 --- a/opendaylight/netconf/config-netconf-connector/src/main/java/org/opendaylight/controller/netconf/confignetconfconnector/mapping/attributes/AttributesConstants.java +++ b/opendaylight/netconf/config-netconf-connector/src/main/java/org/opendaylight/controller/netconf/confignetconfconnector/mapping/attributes/AttributesConstants.java @@ -1,10 +1,9 @@ -/** - * @author Maros Marsalek +/* + * Copyright (c) 2013 Cisco Systems, Inc. and others. All rights reserved. * - * 12 2013 - * - * Copyright (c) 2012 by Cisco Systems, Inc. - * All rights reserved. + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License v1.0 which accompanies this distribution, + * and is available at http://www.eclipse.org/legal/epl-v10.html */ package org.opendaylight.controller.netconf.confignetconfconnector.mapping.attributes; diff --git a/opendaylight/netconf/config-netconf-connector/src/main/java/org/opendaylight/controller/netconf/confignetconfconnector/mapping/attributes/fromxml/ObjectXmlReader.java b/opendaylight/netconf/config-netconf-connector/src/main/java/org/opendaylight/controller/netconf/confignetconfconnector/mapping/attributes/fromxml/ObjectXmlReader.java index a2691f241c..97c0f4d834 100644 --- a/opendaylight/netconf/config-netconf-connector/src/main/java/org/opendaylight/controller/netconf/confignetconfconnector/mapping/attributes/fromxml/ObjectXmlReader.java +++ b/opendaylight/netconf/config-netconf-connector/src/main/java/org/opendaylight/controller/netconf/confignetconfconnector/mapping/attributes/fromxml/ObjectXmlReader.java @@ -11,6 +11,7 @@ package org.opendaylight.controller.netconf.confignetconfconnector.mapping.attri import com.google.common.base.Preconditions; import com.google.common.collect.Maps; import org.opendaylight.controller.config.yangjmxgenerator.attribute.AttributeIfc; +import org.opendaylight.controller.config.yangjmxgenerator.attribute.JavaAttribute; import org.opendaylight.controller.config.yangjmxgenerator.attribute.ListAttribute; import org.opendaylight.controller.config.yangjmxgenerator.attribute.ListDependenciesAttribute; import org.opendaylight.controller.config.yangjmxgenerator.attribute.TOAttribute; @@ -47,6 +48,12 @@ public class ObjectXmlReader extends AttributeIfcSwitchStatement openType) { + String mappingKey = JavaAttribute.DESCRIPTION_OF_VALUE_ATTRIBUTE_FOR_UNION; + return new SimpleUnionAttributeReadingStrategy(lastAttribute.getNullableDefault(), mappingKey); + } + @Override public AttributeReadingStrategy caseJavaSimpleAttribute(SimpleType openType) { return new SimpleAttributeReadingStrategy(lastAttribute.getNullableDefault()); diff --git a/opendaylight/netconf/config-netconf-connector/src/main/java/org/opendaylight/controller/netconf/confignetconfconnector/mapping/attributes/fromxml/SimpleUnionAttributeReadingStrategy.java b/opendaylight/netconf/config-netconf-connector/src/main/java/org/opendaylight/controller/netconf/confignetconfconnector/mapping/attributes/fromxml/SimpleUnionAttributeReadingStrategy.java new file mode 100644 index 0000000000..2e8b459b70 --- /dev/null +++ b/opendaylight/netconf/config-netconf-connector/src/main/java/org/opendaylight/controller/netconf/confignetconfconnector/mapping/attributes/fromxml/SimpleUnionAttributeReadingStrategy.java @@ -0,0 +1,43 @@ +/* + * Copyright (c) 2013 Cisco Systems, Inc. and others. All rights reserved. + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License v1.0 which accompanies this distribution, + * and is available at http://www.eclipse.org/legal/epl-v10.html + */ + +package org.opendaylight.controller.netconf.confignetconfconnector.mapping.attributes.fromxml; + +import com.google.common.collect.Lists; +import com.google.common.collect.Maps; + +import java.util.List; +import java.util.Map; + +public class SimpleUnionAttributeReadingStrategy extends SimpleAttributeReadingStrategy { + + private final String key; + + public SimpleUnionAttributeReadingStrategy(String nullableDefault, String key) { + super(nullableDefault); + this.key = key; + } + + protected Object postprocessParsedValue(String textContent) { + char[] charArray = textContent.toCharArray(); + List chars = Lists.newArrayListWithCapacity(charArray.length); + + for (char c : charArray) { + chars.add(Character.toString(c)); + } + + Map map = Maps.newHashMap(); + map.put(key, chars); + return map; + } + + @Override + protected Object postprocessNullableDefault(String nullableDefault) { + return nullableDefault == null ? null : postprocessParsedValue(nullableDefault); + } +} diff --git a/opendaylight/netconf/config-netconf-connector/src/main/java/org/opendaylight/controller/netconf/confignetconfconnector/mapping/attributes/mapping/CompositeAttributeMappingStrategy.java b/opendaylight/netconf/config-netconf-connector/src/main/java/org/opendaylight/controller/netconf/confignetconfconnector/mapping/attributes/mapping/CompositeAttributeMappingStrategy.java index 252b13bf68..368e1f12a6 100644 --- a/opendaylight/netconf/config-netconf-connector/src/main/java/org/opendaylight/controller/netconf/confignetconfconnector/mapping/attributes/mapping/CompositeAttributeMappingStrategy.java +++ b/opendaylight/netconf/config-netconf-connector/src/main/java/org/opendaylight/controller/netconf/confignetconfconnector/mapping/attributes/mapping/CompositeAttributeMappingStrategy.java @@ -53,17 +53,21 @@ public class CompositeAttributeMappingStrategy extends Map retVal = Maps.newHashMap(); for (String jmxName : jmxToJavaNameMapping.keySet()) { - String innerAttrJmxName = jmxName; - Object innerValue = compositeData.get(innerAttrJmxName); - - AttributeMappingStrategy> attributeMappingStrategy = innerStrategies - .get(innerAttrJmxName); - Optional mapAttribute = attributeMappingStrategy.mapAttribute(innerValue); - if (mapAttribute.isPresent()) - retVal.put(jmxToJavaNameMapping.get(innerAttrJmxName), mapAttribute.get()); + Optional mapped = mapInnerAttribute(compositeData, jmxName, expectedType.getDescription(jmxName)); + if(mapped.isPresent()) + retVal.put(jmxToJavaNameMapping.get(jmxName), mapped.get()); } return Optional.of(retVal); } + protected Optional mapInnerAttribute(CompositeDataSupport compositeData, String jmxName, String description) { + Object innerValue = compositeData.get(jmxName); + + AttributeMappingStrategy> attributeMappingStrategy = innerStrategies + .get(jmxName); + Optional mapAttribute = attributeMappingStrategy.mapAttribute(innerValue); + return mapAttribute; + } + } diff --git a/opendaylight/netconf/config-netconf-connector/src/main/java/org/opendaylight/controller/netconf/confignetconfconnector/mapping/attributes/mapping/ObjectMapper.java b/opendaylight/netconf/config-netconf-connector/src/main/java/org/opendaylight/controller/netconf/confignetconfconnector/mapping/attributes/mapping/ObjectMapper.java index 6e5bd0d3fe..fb385221c8 100644 --- a/opendaylight/netconf/config-netconf-connector/src/main/java/org/opendaylight/controller/netconf/confignetconfconnector/mapping/attributes/mapping/ObjectMapper.java +++ b/opendaylight/netconf/config-netconf-connector/src/main/java/org/opendaylight/controller/netconf/confignetconfconnector/mapping/attributes/mapping/ObjectMapper.java @@ -90,6 +90,22 @@ public class ObjectMapper extends AttributeIfcSwitchStatement> caseJavaUnionAttribute(OpenType openType) { + Map>> innerStrategies = Maps.newHashMap(); + + Map attributeMapping = Maps.newHashMap(); + + CompositeType compositeType = (CompositeType) openType; + for (String innerAttributeKey : compositeType.keySet()) { + + innerStrategies.put(innerAttributeKey, caseJavaAttribute(compositeType.getType(innerAttributeKey))); + attributeMapping.put(innerAttributeKey, innerAttributeKey); + } + + return new UnionCompositeAttributeMappingStrategy(compositeType, innerStrategies, attributeMapping); + } + private String serviceNameOfDepAttr; private String namespaceOfDepAttr; diff --git a/opendaylight/netconf/config-netconf-connector/src/main/java/org/opendaylight/controller/netconf/confignetconfconnector/mapping/attributes/mapping/UnionCompositeAttributeMappingStrategy.java b/opendaylight/netconf/config-netconf-connector/src/main/java/org/opendaylight/controller/netconf/confignetconfconnector/mapping/attributes/mapping/UnionCompositeAttributeMappingStrategy.java new file mode 100644 index 0000000000..81a1e53598 --- /dev/null +++ b/opendaylight/netconf/config-netconf-connector/src/main/java/org/opendaylight/controller/netconf/confignetconfconnector/mapping/attributes/mapping/UnionCompositeAttributeMappingStrategy.java @@ -0,0 +1,34 @@ +/* + * Copyright (c) 2013 Cisco Systems, Inc. and others. All rights reserved. + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License v1.0 which accompanies this distribution, + * and is available at http://www.eclipse.org/legal/epl-v10.html + */ + +package org.opendaylight.controller.netconf.confignetconfconnector.mapping.attributes.mapping; + +import com.google.common.base.Optional; +import org.opendaylight.controller.config.yangjmxgenerator.attribute.JavaAttribute; + +import javax.management.openmbean.CompositeDataSupport; +import javax.management.openmbean.CompositeType; +import javax.management.openmbean.OpenType; +import java.util.Map; + +public class UnionCompositeAttributeMappingStrategy extends + CompositeAttributeMappingStrategy { + + + public UnionCompositeAttributeMappingStrategy(CompositeType compositeType, Map>> innerStrategies, Map jmxToJavaNameMapping) { + super(compositeType, innerStrategies, jmxToJavaNameMapping); + } + + @Override + protected Optional mapInnerAttribute(CompositeDataSupport compositeData, String jmxName, String description) { + if(description.equals(JavaAttribute.DESCRIPTION_OF_VALUE_ATTRIBUTE_FOR_UNION) == false) + return Optional.absent(); + + return super.mapInnerAttribute(compositeData, jmxName, description); + } +} diff --git a/opendaylight/netconf/config-netconf-connector/src/main/java/org/opendaylight/controller/netconf/confignetconfconnector/mapping/attributes/resolving/CompositeAttributeResolvingStrategy.java b/opendaylight/netconf/config-netconf-connector/src/main/java/org/opendaylight/controller/netconf/confignetconfconnector/mapping/attributes/resolving/CompositeAttributeResolvingStrategy.java index c477821051..e8e97f990f 100644 --- a/opendaylight/netconf/config-netconf-connector/src/main/java/org/opendaylight/controller/netconf/confignetconfconnector/mapping/attributes/resolving/CompositeAttributeResolvingStrategy.java +++ b/opendaylight/netconf/config-netconf-connector/src/main/java/org/opendaylight/controller/netconf/confignetconfconnector/mapping/attributes/resolving/CompositeAttributeResolvingStrategy.java @@ -21,7 +21,7 @@ import javax.management.openmbean.OpenDataException; import javax.management.openmbean.OpenType; import java.util.Map; -final class CompositeAttributeResolvingStrategy extends +class CompositeAttributeResolvingStrategy extends AbstractAttributeResolvingStrategy { private final Map>> innerTypes; private final Map yangToJavaAttrMapping; @@ -49,6 +49,7 @@ final class CompositeAttributeResolvingStrategy extends Util.checkType(value, Map.class); Map valueMap = (Map) value; + valueMap = preprocessValueMap(valueMap); Map items = Maps.newHashMap(); Map> openTypes = Maps.newHashMap(); @@ -82,4 +83,8 @@ final class CompositeAttributeResolvingStrategy extends return Optional.of(parsedValue); } + + protected Map preprocessValueMap(Map valueMap) { + return valueMap; + } } diff --git a/opendaylight/netconf/config-netconf-connector/src/main/java/org/opendaylight/controller/netconf/confignetconfconnector/mapping/attributes/resolving/ObjectResolver.java b/opendaylight/netconf/config-netconf-connector/src/main/java/org/opendaylight/controller/netconf/confignetconfconnector/mapping/attributes/resolving/ObjectResolver.java index f5a2511260..a3e2813fa0 100644 --- a/opendaylight/netconf/config-netconf-connector/src/main/java/org/opendaylight/controller/netconf/confignetconfconnector/mapping/attributes/resolving/ObjectResolver.java +++ b/opendaylight/netconf/config-netconf-connector/src/main/java/org/opendaylight/controller/netconf/confignetconfconnector/mapping/attributes/resolving/ObjectResolver.java @@ -72,13 +72,30 @@ public class ObjectResolver extends AttributeIfcSwitchStatement> caseJavaCompositeAttribute(CompositeType openType) { Map>> innerMap = Maps.newHashMap(); - Map yangToJmxMapping = Maps.newHashMap(); + + fillMappingForComposite(openType, innerMap, yangToJmxMapping); + return new CompositeAttributeResolvingStrategy(innerMap, openType, yangToJmxMapping); + } + + private void fillMappingForComposite(CompositeType openType, Map>> innerMap, Map yangToJmxMapping) { for (String innerAttributeKey : openType.keySet()) { innerMap.put(innerAttributeKey, caseJavaAttribute(openType.getType(innerAttributeKey))); yangToJmxMapping.put(innerAttributeKey, innerAttributeKey); } - return new CompositeAttributeResolvingStrategy(innerMap, openType, yangToJmxMapping); + } + + @Override + protected AttributeResolvingStrategy> caseJavaUnionAttribute(OpenType openType) { + + Preconditions.checkState(openType instanceof CompositeType, "Unexpected open type, expected %s but was %s"); + CompositeType compositeType = (CompositeType) openType; + + Map>> innerMap = Maps.newHashMap(); + Map yangToJmxMapping = Maps.newHashMap(); + fillMappingForComposite(compositeType, innerMap, yangToJmxMapping); + + return new UnionCompositeAttributeResolvingStrategy(innerMap, compositeType, yangToJmxMapping); } @Override diff --git a/opendaylight/netconf/config-netconf-connector/src/main/java/org/opendaylight/controller/netconf/confignetconfconnector/mapping/attributes/resolving/UnionCompositeAttributeResolvingStrategy.java b/opendaylight/netconf/config-netconf-connector/src/main/java/org/opendaylight/controller/netconf/confignetconfconnector/mapping/attributes/resolving/UnionCompositeAttributeResolvingStrategy.java new file mode 100644 index 0000000000..bc99ecf09a --- /dev/null +++ b/opendaylight/netconf/config-netconf-connector/src/main/java/org/opendaylight/controller/netconf/confignetconfconnector/mapping/attributes/resolving/UnionCompositeAttributeResolvingStrategy.java @@ -0,0 +1,44 @@ +/* + * Copyright (c) 2013 Cisco Systems, Inc. and others. All rights reserved. + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License v1.0 which accompanies this distribution, + * and is available at http://www.eclipse.org/legal/epl-v10.html + */ + +package org.opendaylight.controller.netconf.confignetconfconnector.mapping.attributes.resolving; + +import com.google.common.base.Preconditions; +import com.google.common.collect.Maps; +import org.opendaylight.controller.config.yangjmxgenerator.attribute.JavaAttribute; + +import javax.management.openmbean.CompositeType; +import javax.management.openmbean.OpenType; +import java.util.Map; + +final class UnionCompositeAttributeResolvingStrategy extends CompositeAttributeResolvingStrategy { + + UnionCompositeAttributeResolvingStrategy(Map>> innerTypes, + CompositeType openType, Map yangToJavaAttrMapping) { + super(innerTypes, openType, yangToJavaAttrMapping); + } + + protected Map preprocessValueMap(Map valueMap) { + CompositeType openType = getOpenType(); + + Preconditions.checkArgument( + valueMap.size() == 1 && valueMap.containsKey(JavaAttribute.DESCRIPTION_OF_VALUE_ATTRIBUTE_FOR_UNION), + "Unexpected structure of incoming map, expecting one element under %s, but was %s", + JavaAttribute.DESCRIPTION_OF_VALUE_ATTRIBUTE_FOR_UNION, valueMap); + + Map newMap = Maps.newHashMap(); + + for (String key : openType.keySet()) { + if (openType.getDescription(key).equals(JavaAttribute.DESCRIPTION_OF_VALUE_ATTRIBUTE_FOR_UNION)) + newMap.put(key, valueMap.get(JavaAttribute.DESCRIPTION_OF_VALUE_ATTRIBUTE_FOR_UNION)); + else + newMap.put(key, null); + } + return newMap; + } +} diff --git a/opendaylight/netconf/config-netconf-connector/src/main/java/org/opendaylight/controller/netconf/confignetconfconnector/mapping/attributes/toxml/ObjectXmlWriter.java b/opendaylight/netconf/config-netconf-connector/src/main/java/org/opendaylight/controller/netconf/confignetconfconnector/mapping/attributes/toxml/ObjectXmlWriter.java index a174e9a251..4e870f042d 100644 --- a/opendaylight/netconf/config-netconf-connector/src/main/java/org/opendaylight/controller/netconf/confignetconfconnector/mapping/attributes/toxml/ObjectXmlWriter.java +++ b/opendaylight/netconf/config-netconf-connector/src/main/java/org/opendaylight/controller/netconf/confignetconfconnector/mapping/attributes/toxml/ObjectXmlWriter.java @@ -73,6 +73,11 @@ public class ObjectXmlWriter extends AttributeIfcSwitchStatement openType) { + return new SimpleUnionAttributeWritingStrategy(document, key); + } + @Override protected AttributeWritingStrategy caseDependencyAttribute(SimpleType openType) { return new ObjectNameAttributeWritingStrategy(document, key); diff --git a/opendaylight/netconf/config-netconf-connector/src/main/java/org/opendaylight/controller/netconf/confignetconfconnector/mapping/attributes/toxml/SimpleUnionAttributeWritingStrategy.java b/opendaylight/netconf/config-netconf-connector/src/main/java/org/opendaylight/controller/netconf/confignetconfconnector/mapping/attributes/toxml/SimpleUnionAttributeWritingStrategy.java new file mode 100644 index 0000000000..d75feb273e --- /dev/null +++ b/opendaylight/netconf/config-netconf-connector/src/main/java/org/opendaylight/controller/netconf/confignetconfconnector/mapping/attributes/toxml/SimpleUnionAttributeWritingStrategy.java @@ -0,0 +1,43 @@ +/* + * Copyright (c) 2013 Cisco Systems, Inc. and others. All rights reserved. + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License v1.0 which accompanies this distribution, + * and is available at http://www.eclipse.org/legal/epl-v10.html + */ + +package org.opendaylight.controller.netconf.confignetconfconnector.mapping.attributes.toxml; + +import com.google.common.base.Preconditions; +import org.opendaylight.controller.netconf.confignetconfconnector.util.Util; +import org.w3c.dom.Document; + +import java.util.List; +import java.util.Map; + +public class SimpleUnionAttributeWritingStrategy extends SimpleAttributeWritingStrategy { + + /** + * @param document + * @param key + */ + public SimpleUnionAttributeWritingStrategy(Document document, String key) { + super(document, key); + } + + protected Object preprocess(Object value) { + Util.checkType(value, Map.class); + Preconditions.checkArgument(((Map)value).size() == 1, "Unexpected number of values in %s, expected 1", value); + Object listOfStrings = ((Map) value).values().iterator().next(); + Util.checkType(listOfStrings, List.class); + + StringBuilder b = new StringBuilder(); + for (Object character: (List)listOfStrings) { + Util.checkType(character, String.class); + b.append(character); + } + + return b.toString(); + } + +} diff --git a/opendaylight/netconf/config-netconf-connector/src/main/java/org/opendaylight/controller/netconf/confignetconfconnector/mapping/config/Services.java b/opendaylight/netconf/config-netconf-connector/src/main/java/org/opendaylight/controller/netconf/confignetconfconnector/mapping/config/Services.java index a4f5e4999c..77f3cf283f 100644 --- a/opendaylight/netconf/config-netconf-connector/src/main/java/org/opendaylight/controller/netconf/confignetconfconnector/mapping/config/Services.java +++ b/opendaylight/netconf/config-netconf-connector/src/main/java/org/opendaylight/controller/netconf/confignetconfconnector/mapping/config/Services.java @@ -97,7 +97,11 @@ public final class Services { Preconditions.checkArgument(refNameToInstance != null, "No serviceInstances mapped to " + serviceName + " , " + serviceNameToRefNameToInstance.keySet()); - ServiceInstance serviceInstance = ServiceInstance.fromString(refNameToInstance.get(refName)); + String instanceId = refNameToInstance.get(refName); + Preconditions.checkArgument(instanceId != null, "No serviceInstances mapped to " + serviceName + ":" + + refName + ", " + serviceNameToRefNameToInstance.keySet()); + + ServiceInstance serviceInstance = ServiceInstance.fromString(instanceId); Preconditions.checkArgument(serviceInstance != null, "No serviceInstance mapped to " + refName + " under service name " + serviceName + " , " + refNameToInstance.keySet()); return serviceInstance; diff --git a/opendaylight/netconf/config-netconf-connector/src/main/java/org/opendaylight/controller/netconf/confignetconfconnector/util/Util.java b/opendaylight/netconf/config-netconf-connector/src/main/java/org/opendaylight/controller/netconf/confignetconfconnector/util/Util.java index 26719592bb..1c806742e9 100644 --- a/opendaylight/netconf/config-netconf-connector/src/main/java/org/opendaylight/controller/netconf/confignetconfconnector/util/Util.java +++ b/opendaylight/netconf/config-netconf-connector/src/main/java/org/opendaylight/controller/netconf/confignetconfconnector/util/Util.java @@ -38,7 +38,7 @@ public final class Util { public static void checkType(final Object value, final Class clazz) { Preconditions.checkArgument(clazz.isAssignableFrom(value.getClass()), "Unexpected type " + value.getClass() - + " should be " + clazz); + + " should be " + clazz + " of " + value); } // TODO: add message and proper error types diff --git a/opendaylight/netconf/config-netconf-connector/src/test/java/org/opendaylight/controller/netconf/confignetconfconnector/NetconfMappingTest.java b/opendaylight/netconf/config-netconf-connector/src/test/java/org/opendaylight/controller/netconf/confignetconfconnector/NetconfMappingTest.java index ccb793149c..11cf1aae6a 100644 --- a/opendaylight/netconf/config-netconf-connector/src/test/java/org/opendaylight/controller/netconf/confignetconfconnector/NetconfMappingTest.java +++ b/opendaylight/netconf/config-netconf-connector/src/test/java/org/opendaylight/controller/netconf/confignetconfconnector/NetconfMappingTest.java @@ -12,6 +12,7 @@ import com.google.common.base.Optional; import com.google.common.base.Preconditions; import com.google.common.collect.Lists; import com.google.common.collect.Maps; +import com.google.common.collect.Sets; import org.apache.commons.lang3.StringUtils; import org.junit.Before; import org.junit.Ignore; @@ -75,9 +76,11 @@ import java.util.Arrays; import java.util.Collection; import java.util.List; import java.util.Map; +import java.util.Set; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertThat; +import static org.junit.Assert.assertTrue; import static org.junit.Assert.fail; import static org.mockito.Mockito.doNothing; import static org.mockito.Mockito.doReturn; @@ -141,7 +144,7 @@ public class NetconfMappingTest extends AbstractConfigTest { "ref_from_code_to_instance-from-code_1"); edit("netconfMessages/editConfig_addServiceName.xml"); - config = getConfigCandidate(); + config = getConfigCandidate(); assertCorrectServiceNames(config, 7, "ref_test2", "user_to_instance_from_code", "ref_dep_user", "ref_dep_user_two", "ref_from_code_to_instance-from-code_dep_1", "ref_from_code_to_instance-from-code_1", "ref_dep_user_another"); @@ -196,6 +199,29 @@ public class NetconfMappingTest extends AbstractConfigTest { } } + @Test + public void testConfigNetconfUnionTypes() throws Exception { + + createModule(INSTANCE_NAME); + + edit("netconfMessages/editConfig.xml"); + commit(); + Element response = getConfigRunning(); + String trimmedResponse = XmlUtil.toString(response).replaceAll("\\s", ""); + assertContainsString(trimmedResponse, "0:0:0:0:0:0:0:1"); + assertContainsString(trimmedResponse, "456"); + + + edit("netconfMessages/editConfig_setUnions.xml"); + commit(); + response = getConfigRunning(); + + trimmedResponse = XmlUtil.toString(response).replaceAll("\\s", ""); + assertContainsString(trimmedResponse, "127.1.2.3"); + assertContainsString(trimmedResponse, "randomStringForUnion"); + + } + @Test public void testConfigNetconf() throws Exception { @@ -497,17 +523,20 @@ public class NetconfMappingTest extends AbstractConfigTest { XmlElement modulesElement = XmlElement.fromDomElement(response).getOnlyChildElement("data") .getOnlyChildElement("modules"); - XmlElement configAttributeType = null; + List expectedValues = Lists.newArrayList("default-string", "configAttributeType"); + Set configAttributeType = Sets.newHashSet(); + for (XmlElement moduleElement : modulesElement.getChildElements("module")) { for (XmlElement type : moduleElement.getChildElements("type")) { if (type.getAttribute(XmlUtil.XMLNS_ATTRIBUTE_KEY).equals("") == false) { - configAttributeType = type; + configAttributeType.add(type.getTextContent()); } } } - // TODO verify if should be default value - assertEquals("default-string", configAttributeType.getTextContent()); + for (String expectedValue : expectedValues) { + assertTrue(configAttributeType.contains(expectedValue)); + } } private Map> getMbes() throws Exception { diff --git a/opendaylight/netconf/config-persister-impl/pom.xml b/opendaylight/netconf/config-persister-impl/pom.xml index 915667028d..20bd386063 100644 --- a/opendaylight/netconf/config-persister-impl/pom.xml +++ b/opendaylight/netconf/config-persister-impl/pom.xml @@ -43,7 +43,9 @@ org.opendaylight.controller - config-persister-file-adapter + config-persister-file-xml-adapter + test + ${config.version} @@ -60,8 +62,8 @@ org.opendaylight.controller - config-persister-directory-adapter - ${parent.version} + config-persister-directory-xml-adapter + ${config.version} test diff --git a/opendaylight/netconf/config-persister-impl/src/main/java/org/opendaylight/controller/netconf/persist/impl/PersisterAggregator.java b/opendaylight/netconf/config-persister-impl/src/main/java/org/opendaylight/controller/netconf/persist/impl/PersisterAggregator.java index 7e9dce67bd..f168bb3634 100644 --- a/opendaylight/netconf/config-persister-impl/src/main/java/org/opendaylight/controller/netconf/persist/impl/PersisterAggregator.java +++ b/opendaylight/netconf/config-persister-impl/src/main/java/org/opendaylight/controller/netconf/persist/impl/PersisterAggregator.java @@ -34,7 +34,7 @@ import java.util.ListIterator; * Example configuration:
  netconf.config.persister.active=2,3
  # read startup configuration
- netconf.config.persister.1.storageAdapterClass=org.opendaylight.controller.config.persist.storage.directory.DirectoryStorageAdapter
+ netconf.config.persister.1.storageAdapterClass=org.opendaylight.controller.config.persist.storage.directory.xml.XmlDirectoryStorageAdapter
  netconf.config.persister.1.properties.fileStorage=configuration/initial/
 
  netconf.config.persister.2.storageAdapterClass=org.opendaylight.controller.config.persist.storage.file.FileStorageAdapter
diff --git a/opendaylight/netconf/config-persister-impl/src/main/java/org/opendaylight/controller/netconf/persist/impl/PropertiesProviderAdapterImpl.java b/opendaylight/netconf/config-persister-impl/src/main/java/org/opendaylight/controller/netconf/persist/impl/PropertiesProviderAdapterImpl.java
index 981be827b7..d9466ff00b 100644
--- a/opendaylight/netconf/config-persister-impl/src/main/java/org/opendaylight/controller/netconf/persist/impl/PropertiesProviderAdapterImpl.java
+++ b/opendaylight/netconf/config-persister-impl/src/main/java/org/opendaylight/controller/netconf/persist/impl/PropertiesProviderAdapterImpl.java
@@ -1,10 +1,9 @@
-/**
- * @author Tomas Olvecky
+/*
+ * Copyright (c) 2013 Cisco Systems, Inc. and others.  All rights reserved.
  *
- * 11 2013
- *
- * Copyright (c) 2013 by Cisco Systems, Inc.
- * All rights reserved.
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
  */
 package org.opendaylight.controller.netconf.persist.impl;
 
diff --git a/opendaylight/netconf/config-persister-impl/src/test/java/org/opendaylight/controller/netconf/persist/impl/PersisterAggregatorTest.java b/opendaylight/netconf/config-persister-impl/src/test/java/org/opendaylight/controller/netconf/persist/impl/PersisterAggregatorTest.java
index 227018bf5b..acea75a743 100644
--- a/opendaylight/netconf/config-persister-impl/src/test/java/org/opendaylight/controller/netconf/persist/impl/PersisterAggregatorTest.java
+++ b/opendaylight/netconf/config-persister-impl/src/test/java/org/opendaylight/controller/netconf/persist/impl/PersisterAggregatorTest.java
@@ -11,7 +11,7 @@ package org.opendaylight.controller.netconf.persist.impl;
 import org.junit.Test;
 import org.opendaylight.controller.config.persist.api.ConfigSnapshotHolder;
 import org.opendaylight.controller.config.persist.api.Persister;
-import org.opendaylight.controller.config.persist.storage.file.FileStorageAdapter;
+import org.opendaylight.controller.config.persist.storage.file.xml.XmlFileStorageAdapter;
 import org.opendaylight.controller.netconf.persist.impl.osgi.ConfigPersisterActivator;
 import org.opendaylight.controller.netconf.persist.impl.osgi.PropertiesProviderBaseImpl;
 
@@ -93,7 +93,7 @@ public class PersisterAggregatorTest {
         List persisters = persisterAggregator.getPersisterWithConfigurations();
         assertEquals(1, persisters.size());
         PersisterWithConfiguration persister = persisters.get(0);
-        assertEquals(FileStorageAdapter.class.getName() ,persister.getStorage().getClass().getName());
+        assertEquals(XmlFileStorageAdapter.class.getName() ,persister.getStorage().getClass().getName());
         assertFalse(persister.isReadOnly());
     }
 
diff --git a/opendaylight/netconf/config-persister-impl/src/test/resources/test2.properties b/opendaylight/netconf/config-persister-impl/src/test/resources/test2.properties
index 222e7cef47..729c67d6c5 100644
--- a/opendaylight/netconf/config-persister-impl/src/test/resources/test2.properties
+++ b/opendaylight/netconf/config-persister-impl/src/test/resources/test2.properties
@@ -1,9 +1,9 @@
 netconf.config.persister.active=2
 # read startup configuration
-netconf.config.persister.1.storageAdapterClass=org.opendaylight.controller.config.persist.storage.directory.DirectoryStorageAdapter
+netconf.config.persister.1.storageAdapterClass=org.opendaylight.controller.config.persist.storage.directory.xml.XmlDirectoryStorageAdapter
 netconf.config.persister.1.properties.directoryStorage=target/configuration/initial/
 netconf.config.persister.1.readonly=true
 
-netconf.config.persister.2.storageAdapterClass=org.opendaylight.controller.config.persist.storage.file.FileStorageAdapter
+netconf.config.persister.2.storageAdapterClass=org.opendaylight.controller.config.persist.storage.file.xml.XmlFileStorageAdapter
 netconf.config.persister.2.properties.fileStorage=target/configuration/current/controller.config.2.txt
 netconf.config.persister.2.properties.numberOfBackups=3
diff --git a/opendaylight/netconf/config-persister-impl/src/test/resources/test3.properties b/opendaylight/netconf/config-persister-impl/src/test/resources/test3.properties
index a1645ad8c4..90ba77273b 100644
--- a/opendaylight/netconf/config-persister-impl/src/test/resources/test3.properties
+++ b/opendaylight/netconf/config-persister-impl/src/test/resources/test3.properties
@@ -1,4 +1,4 @@
 netconf.config.persister.active=3
-netconf.config.persister.3.storageAdapterClass=org.opendaylight.controller.config.persist.storage.file.FileStorageAdapter
+netconf.config.persister.3.storageAdapterClass=org.opendaylight.controller.config.persist.storage.file.xml.XmlFileStorageAdapter
 netconf.config.persister.3.properties.fileStorage=target/configuration/current/controller.config.2.txt
 netconf.config.persister.3.properties.numberOfBackups=0
diff --git a/opendaylight/netconf/ietf-netconf-monitoring/src/main/java/org/opendaylight/yang/gen/v1/urn/ietf/params/xml/ns/yang/ietf/netconf/monitoring/rev101004/netconf/state/schemas/LocationBuilder.java b/opendaylight/netconf/ietf-netconf-monitoring/src/main/java/org/opendaylight/yang/gen/v1/urn/ietf/params/xml/ns/yang/ietf/netconf/monitoring/rev101004/netconf/state/schemas/LocationBuilder.java
new file mode 100644
index 0000000000..0a084b0ff6
--- /dev/null
+++ b/opendaylight/netconf/ietf-netconf-monitoring/src/main/java/org/opendaylight/yang/gen/v1/urn/ietf/params/xml/ns/yang/ietf/netconf/monitoring/rev101004/netconf/state/schemas/LocationBuilder.java
@@ -0,0 +1,23 @@
+/*
+ * Copyright (c) 2013 Cisco Systems, Inc. and others.  All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+
+package org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.netconf.monitoring.rev101004.netconf.state.schemas;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev100924.Uri;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.netconf.monitoring.rev101004.netconf.state.schemas.Schema.Location;
+
+
+/**
+**/
+public class LocationBuilder {
+
+    public static Location getDefaultInstance(String defaultValue) {
+        return defaultValue.equals("NETCONF") ? new Location(Location.Enumeration.NETCONF) : new Location(new Uri(
+                defaultValue));
+    }
+
+}
diff --git a/opendaylight/netconf/netconf-util/src/test/resources/netconfMessages/editConfig_setUnions.xml b/opendaylight/netconf/netconf-util/src/test/resources/netconfMessages/editConfig_setUnions.xml
new file mode 100644
index 0000000000..21db4b8e42
--- /dev/null
+++ b/opendaylight/netconf/netconf-util/src/test/resources/netconfMessages/editConfig_setUnions.xml
@@ -0,0 +1,30 @@
+
+    
+        
+            
+        
+        
+            set
+        
+        merge
+        
+            
+                
+                    
+                        test-impl:impl-netconf
+                    
+
+                    instance-from-code
+
+                    127.1.2.3
+                    randomStringForUnion
+
+                
+            
+
+            
+
+            
+        
+    
+
diff --git a/opendaylight/protocol_plugins/openflow/src/main/java/org/opendaylight/controller/protocol_plugin/openflow/internal/DiscoveryService.java b/opendaylight/protocol_plugins/openflow/src/main/java/org/opendaylight/controller/protocol_plugin/openflow/internal/DiscoveryService.java
index 012807eee9..811135252d 100644
--- a/opendaylight/protocol_plugins/openflow/src/main/java/org/opendaylight/controller/protocol_plugin/openflow/internal/DiscoveryService.java
+++ b/opendaylight/protocol_plugins/openflow/src/main/java/org/opendaylight/controller/protocol_plugin/openflow/internal/DiscoveryService.java
@@ -125,7 +125,7 @@ public class DiscoveryService implements IInventoryShimExternalListener, IDataPa
     private Boolean throttling = false; // if true, no more batching.
     private volatile Boolean shuttingDown = false;
 
-    private LLDPTLV chassisIdTlv, portIdTlv, ttlTlv, customTlv;
+    private LLDPTLV chassisIdTlv, systemNameTlv, portIdTlv, ttlTlv, customTlv;
     private IPluginOutConnectionService connectionOutService;
 
     class DiscoveryTransmit implements Runnable {
@@ -217,6 +217,11 @@ public class DiscoveryService implements IInventoryShimExternalListener, IDataPa
         chassisIdTlv.setType(LLDPTLV.TLVType.ChassisID.getValue()).setLength((short) cidValue.length)
                 .setValue(cidValue);
 
+        // Create LLDP SystemName TLV
+        byte[] snValue = LLDPTLV.createSystemNameTLVValue(nodeConnector.getNode().toString());
+        systemNameTlv.setType(LLDPTLV.TLVType.SystemName.getValue()).setLength((short) snValue.length)
+                .setValue(snValue);
+
         // Create LLDP PortID TLV
         String portId = nodeConnector.getNodeConnectorIDString();
         byte[] pidValue = LLDPTLV.createPortIDTLVValue(portId);
@@ -233,7 +238,8 @@ public class DiscoveryService implements IInventoryShimExternalListener, IDataPa
 
         // Create discovery pkt
         LLDP discoveryPkt = new LLDP();
-        discoveryPkt.setChassisId(chassisIdTlv).setPortId(portIdTlv).setTtl(ttlTlv).setOptionalTLVList(customList);
+        discoveryPkt.setChassisId(chassisIdTlv).setPortId(portIdTlv).setTtl(ttlTlv).setSystemNameId(systemNameTlv)
+                .setOptionalTLVList(customList);
 
         RawPacket rawPkt = null;
         try {
@@ -1462,6 +1468,10 @@ public class DiscoveryService implements IInventoryShimExternalListener, IDataPa
         chassisIdTlv = new LLDPTLV();
         chassisIdTlv.setType(LLDPTLV.TLVType.ChassisID.getValue());
 
+        // Create LLDP SystemName TLV
+        systemNameTlv = new LLDPTLV();
+        systemNameTlv.setType(LLDPTLV.TLVType.SystemName.getValue());
+
         // Create LLDP PortID TLV
         portIdTlv = new LLDPTLV();
         portIdTlv.setType(LLDPTLV.TLVType.PortID.getValue());
diff --git a/opendaylight/sal/api/src/main/java/org/opendaylight/controller/sal/packet/LLDP.java b/opendaylight/sal/api/src/main/java/org/opendaylight/controller/sal/packet/LLDP.java
index 6a896c6c71..95edca943b 100644
--- a/opendaylight/sal/api/src/main/java/org/opendaylight/controller/sal/packet/LLDP.java
+++ b/opendaylight/sal/api/src/main/java/org/opendaylight/controller/sal/packet/LLDP.java
@@ -21,9 +21,10 @@ import org.opendaylight.controller.sal.utils.NetUtils;
 
 public class LLDP extends Packet {
     private static final String CHASSISID = "ChassisId";
+    private static final String SYSTEMNAMEID = "SystemNameID";
     private static final String PORTID = "PortId";
     private static final String TTL = "TTL";
-    private static final int LLDPDefaultTlvs = 3;
+    private static final int LLDPDefaultTlvs = 4;
     private static LLDPTLV emptyTLV = new LLDPTLV().setLength((short) 0)
             .setType((byte) 0);
     public static final byte[] LLDPMulticastMac = { 1, (byte) 0x80,
@@ -101,6 +102,22 @@ public class LLDP extends Packet {
         return this;
     }
 
+    /**
+     * @return the SystemName TLV
+     */
+    public LLDPTLV getSystemNameId() {
+        return getTLV(SYSTEMNAMEID);
+    }
+
+    /**
+     * @param LLDPTLV
+     *            - the chassisId to set
+     */
+    public LLDP setSystemNameId(LLDPTLV systemNameId) {
+        tlvList.put(getType(SYSTEMNAMEID), systemNameId);
+        return this;
+    }
+
     /**
      * @return LLDPTLV - the portId TLV
      */
diff --git a/opendaylight/sal/api/src/main/java/org/opendaylight/controller/sal/packet/LLDPTLV.java b/opendaylight/sal/api/src/main/java/org/opendaylight/controller/sal/packet/LLDPTLV.java
index bf67402259..27660221ce 100644
--- a/opendaylight/sal/api/src/main/java/org/opendaylight/controller/sal/packet/LLDPTLV.java
+++ b/opendaylight/sal/api/src/main/java/org/opendaylight/controller/sal/packet/LLDPTLV.java
@@ -187,6 +187,18 @@ public class LLDPTLV extends Packet {
                 getfieldnumBits(VALUE)); // variable
     }
 
+    /**
+     * Creates the SystemName TLV value
+     *
+     * @param nodeId
+     *            node identifier string
+     * @return the SystemName TLV value in byte array
+     */
+    static public byte[] createSystemNameTLVValue(String nodeId) {
+        byte[] nid = nodeId.getBytes();
+        return nid;
+    }
+
     /**
      * Creates the ChassisID TLV value including the subtype and ChassisID
      * string
diff --git a/opendaylight/sal/api/src/main/java/org/opendaylight/controller/sal/utils/NodeConnectorCreator.java b/opendaylight/sal/api/src/main/java/org/opendaylight/controller/sal/utils/NodeConnectorCreator.java
index da4cd53883..9cd551664c 100644
--- a/opendaylight/sal/api/src/main/java/org/opendaylight/controller/sal/utils/NodeConnectorCreator.java
+++ b/opendaylight/sal/api/src/main/java/org/opendaylight/controller/sal/utils/NodeConnectorCreator.java
@@ -73,7 +73,11 @@ public abstract class NodeConnectorCreator {
     public static NodeConnector createNodeConnector(
             String nodeConnectorType, Object portId, Node node) {
         try {
-            return new NodeConnector(nodeConnectorType, portId, node);
+            if (nodeConnectorType.equals(Node.NodeIDType.OPENFLOW) && (portId.getClass() == String.class)) {
+                return new NodeConnector(nodeConnectorType, Short.parseShort((String) portId), node);
+            } else {
+                return new NodeConnector(nodeConnectorType, portId, node);
+            }
         } catch (ConstructionException e1) {
             logger.error("",e1);
             return null;
diff --git a/opendaylight/switchmanager/implementation/src/main/java/org/opendaylight/controller/switchmanager/internal/SwitchManager.java b/opendaylight/switchmanager/implementation/src/main/java/org/opendaylight/controller/switchmanager/internal/SwitchManager.java
index 217b8d4690..41c783618d 100644
--- a/opendaylight/switchmanager/implementation/src/main/java/org/opendaylight/controller/switchmanager/internal/SwitchManager.java
+++ b/opendaylight/switchmanager/implementation/src/main/java/org/opendaylight/controller/switchmanager/internal/SwitchManager.java
@@ -475,6 +475,16 @@ public class SwitchManager implements ISwitchManager, IConfigurationContainerAwa
             status = updateConfig(conf, isAdding);
             if(!status.isSuccess()) {
                 updateDatabase(conf, (!isAdding));
+            } else {
+                // update the listeners
+                Subnet subnetCurr = subnets.get(conf.getIPAddress());
+                Subnet subnet;
+                if (subnetCurr == null) {
+                    subnet = new Subnet(conf);
+                } else {
+                    subnet = subnetCurr.clone();
+                }
+                notifySubnetChange(subnet, isAdding);
             }
         }
 
diff --git a/opendaylight/topologymanager/integrationtest/pom.xml b/opendaylight/topologymanager/integrationtest/pom.xml
index d4d3d1c857..5dfa1632f7 100644
--- a/opendaylight/topologymanager/integrationtest/pom.xml
+++ b/opendaylight/topologymanager/integrationtest/pom.xml
@@ -18,6 +18,12 @@
   topologymanager.integrationtest
   0.4.0-SNAPSHOT
   
+    
+      org.ops4j.pax.exam
+      pax-exam-container-native
+      ${exam.version}
+      test
+    
     
       org.opendaylight.controller
       protocol_plugins.stub
diff --git a/pom.xml b/pom.xml
index 6ece420d5a..f7f9bc2256 100644
--- a/pom.xml
+++ b/pom.xml
@@ -129,7 +129,6 @@
     opendaylight/commons/opendaylight
     opendaylight/commons/parent
     opendaylight/commons/logback_settings
-    opendaylight/commons/controller-maven-plugin
   
 
     
@@ -150,6 +149,7 @@
                 opendaylight/statisticsmanager/integrationtest
                 opendaylight/commons/integrationtest
                 opendaylight/containermanager/it.implementation
+                opendaylight/distribution/sanitytest/