--- /dev/null
+<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+ xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+ <modelVersion>4.0.0</modelVersion>
+
+ <parent>
+ <groupId>org.opendaylight.controller</groupId>
+ <artifactId>commons.opendaylight</artifactId>
+ <version>1.4.1-SNAPSHOT</version>
+ <relativePath>../../commons/opendaylight</relativePath>
+ </parent>
+
+ <artifactId>controller-maven-plugin</artifactId>
+ <version>0.1.0-SNAPSHOT</version>
+ <packaging>maven-plugin</packaging>
+
+ <name>controller-maven-plugin</name>
+ <description>Maven Plugin for controlling the launch of the controller.</description>
+ <url>http://maven.apache.org</url>
+
+ <properties>
+ <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
+ </properties>
+
+ <dependencies>
+ <dependency>
+ <!-- controller mojos depend on the api module -->
+ <groupId>org.apache.maven</groupId>
+ <artifactId>maven-plugin-api</artifactId>
+ <version>2.0</version>
+ </dependency>
+ <dependency>
+ <!-- controller mojos use the annotations defined in this module -->
+ <groupId>org.apache.maven.plugin-tools</groupId>
+ <artifactId>maven-plugin-annotations</artifactId>
+ <version>3.2</version>
+ <scope>provided</scope>
+ </dependency>
+ <dependency>
+ <!-- needed for handling processes -->
+ <groupId>com.sun</groupId>
+ <artifactId>tools</artifactId>
+ <scope>system</scope>
+ <version>7</version>
+ <systemPath>${java.home}/../lib/tools.jar</systemPath>
+ </dependency>
+ <dependency>
+ <groupId>junit</groupId>
+ <artifactId>junit</artifactId>
+ <version>4.8.1</version>
+ <scope>test</scope>
+ </dependency>
+ </dependencies>
+
+ <build>
+ <plugins>
+ <plugin>
+ <!-- plugin builder -->
+ <groupId>org.apache.maven.plugins</groupId>
+ <artifactId>maven-plugin-plugin</artifactId>
+ <version>3.2</version>
+ <configuration>
+ <goalPrefix>controller-maven-plugin</goalPrefix>
+ <skipErrorNoDescriptorsFound>true</skipErrorNoDescriptorsFound>
+ </configuration>
+ <executions>
+ <execution>
+ <id>mojo-descriptor</id>
+ <goals>
+ <goal>descriptor</goal>
+ </goals>
+ </execution>
+ <execution>
+ <id>help-goal</id>
+ <goals>
+ <goal>helpmojo</goal>
+ </goals>
+ </execution>
+ </executions>
+ </plugin>
+ </plugins>
+ </build>
+
+</project>
--- /dev/null
+/*
+ * Copyright (c) 2013 Cisco Systems, Inc. and others. All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+
+package org.opendaylight.controller.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<String> args, String log)
+ throws MojoFailureException, MojoExecutionException
+ {
+ ProcessBuilder pb = new ProcessBuilder();
+ List<String> cmd = new ArrayList<String>();
+ 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<String,String> 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<JavaProcess> 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();
+ }
+
+}
--- /dev/null
+/*
+ * Copyright (c) 2013 Cisco Systems, Inc. and others. All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+
+package org.opendaylight.controller.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<String> startArgs = new ArrayList<String>();
+
+ /**
+ * 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;
+ }
+}
--- /dev/null
+/*
+ * Copyright (c) 2013 Cisco Systems, Inc. and others. All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+
+package org.opendaylight.controller.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<String> args = new ArrayList<String>();
+ 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();
+ }
+
+}
--- /dev/null
+
+/*
+ * Copyright (c) 2013 Cisco Systems, Inc. and others. All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+package org.opendaylight.controller.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();
+ }
+}
--- /dev/null
+/*
+ * Copyright (c) 2013 Cisco Systems, Inc. and others. All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+
+package org.opendaylight.controller.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<JavaProcess> getProcesses() {
+ if (jpsTool == null) return super.getProcesses();
+ List<JavaProcess> jvms = new ArrayList<JavaProcess>();
+ 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<tokens.length; i++) {
+ if (tokens[i].startsWith("-D")) {
+ proc.setSystemProperty(tokens[i]);
+ }
+ }
+ return proc;
+ }
+
+}
--- /dev/null
+/*
+ * Copyright (c) 2013 Cisco Systems, Inc. and others. All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+
+package org.opendaylight.controller.maven.plugin.util;
+
+import java.io.File;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.List;
+
+public class ProcessMonitor {
+ public static final String SEP = File.pathSeparator;
+ public static final boolean WIN =
+ System.getProperty("os.name").toLowerCase().indexOf("windows") > -1;
+
+
+
+ public void log(String msg) {
+ System.out.println("" + msg);
+ }
+
+ public List<JavaProcess> getProcesses() {
+ return Collections.emptyList();
+ }
+
+ public List<JavaProcess> getProcesses(String mainClass, String systemPropertyKey) {
+ List<JavaProcess> result = new ArrayList<JavaProcess>();
+ 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());
+ }
+ }
+
+}
--- /dev/null
+/*
+ * Copyright (c) 2013 Cisco Systems, Inc. and others. All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+
+package org.opendaylight.controller.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<JavaProcess> getProcesses() {
+ Set<Integer> activeVmPids = null;
+ List<JavaProcess> result = new ArrayList<JavaProcess>();
+ 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;
+ }
+
+
+}
<jacoco.version>0.5.3.201107060350</jacoco.version>
<enforcer.version>1.3.1</enforcer.version>
<bundle.plugin.version>2.3.7</bundle.plugin.version>
+ <install.plugin.version>2.5</install.plugin.version>
+ <enforcer.plugin.version>1.3.1</enforcer.plugin.version>
<junit.version>4.8.1</junit.version>
<bgpcep.version>0.3.0-SNAPSHOT</bgpcep.version>
<yangtools.version>0.5.9-SNAPSHOT</yangtools.version>
* Provides functionality for working with configuration registry - mainly
* creating and committing config transactions.
*/
-public interface ConfigRegistry extends LookupRegistry {
+public interface ConfigRegistry extends LookupRegistry, ServiceReferenceReadableRegistry {
/**
* Only well-known ObjectName in configuration system, under which
/**
* Represents functionality provided by configuration transaction.
*/
-public interface ConfigTransactionController extends LookupRegistry {
+public interface ConfigTransactionController extends LookupRegistry, ServiceReferenceReadableRegistry, ServiceReferenceWritableRegistry {
/**
* Create new configuration bean.
*/
String getTransactionName();
+ /**
+ * @return all known module factory names as reported by {@link org.opendaylight.controller.config.spi.ModuleFactory#getImplementationName()}
+ */
Set<String> getAvailableModuleNames();
}
*/
package org.opendaylight.controller.config.api;
-import java.util.Set;
-
import javax.management.InstanceNotFoundException;
import javax.management.ObjectName;
+import java.util.Set;
public interface LookupRegistry {
ObjectName lookupConfigBean(String moduleName, String instanceName)
throws InstanceNotFoundException;
+ /**
+ * Check that object name corresponds with existing module.
+ *
+ * @throws InstanceNotFoundException
+ * if search did not find exactly one instance
+ */
+ void checkConfigBeanExists(ObjectName objectName) throws InstanceNotFoundException;
+
}
--- /dev/null
+/*
+ * Copyright (c) 2013 Cisco Systems, Inc. and others. All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+package org.opendaylight.controller.config.api;
+
+import javax.management.InstanceNotFoundException;
+import javax.management.ObjectName;
+import java.util.Map;
+import java.util.Set;
+
+public interface ServiceReferenceReadableRegistry {
+
+ /**
+ * Lookup object name by fully qualified service interface name and service reference name.
+ * @param serviceInterfaceName service interface name
+ * @param refName service reference name supplied in
+ * {@link org.opendaylight.controller.config.api.ConfigTransactionController#saveServiceReference(String, String, javax.management.ObjectName)}
+ * @throws java.lang.IllegalArgumentException if module not found
+ */
+ ObjectName lookupConfigBeanByServiceInterfaceName(String serviceInterfaceName, String refName);
+
+ /**
+ * Get mapping of services to reference names and module object names.
+ */
+ Map<String /* serviceInterfaceName */, Map<String/* refName */, ObjectName>> getServiceMapping();
+
+ /**
+ * Get current mapping between reference names and module object names for given service interface name.
+ * @param serviceInterfaceName service interface name
+ * @throws IllegalArgumentException if there is a mismatch between serviceInterfaceName and objectName
+ */
+ Map<String /* refName */, ObjectName> lookupServiceReferencesByServiceInterfaceName(String serviceInterfaceName);
+
+ /**
+ * Find all available service interface names of a module.
+ * @param objectName module object name
+ * @throws InstanceNotFoundException if search did not find exactly one instance
+ */
+ Set<String> lookupServiceInterfaceNames(ObjectName objectName) throws InstanceNotFoundException;
+
+ /**
+ * @param namespace service interface namespace
+ * @param localName service interface local name
+ * @return fully qualified name needed by all other service reference mapping methods.
+ * @throws java.lang.IllegalArgumentException if namespace or localName is not found
+ */
+ String getServiceInterfaceName(String namespace, String localName);
+
+}
--- /dev/null
+/*
+ * Copyright (c) 2013 Cisco Systems, Inc. and others. All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+package org.opendaylight.controller.config.api;
+
+import javax.management.InstanceNotFoundException;
+import javax.management.ObjectName;
+
+public interface ServiceReferenceWritableRegistry extends ServiceReferenceReadableRegistry {
+ /**
+ * Create or update reference name to objectName. Reference name is unique per service interface name.
+ * @throws IllegalArgumentException if there is a mismatch between serviceInterfaceName and objectName
+ * @throws InstanceNotFoundException if search did not find exactly one instance
+ */
+ void saveServiceReference(String serviceInterfaceName, String refName, ObjectName objectName) throws InstanceNotFoundException;
+
+ /**
+ * Remove service reference.
+ * @return true iif removed
+ * @throws IllegalArgumentException if service interface name is not advertised by any module
+ */
+ boolean removeServiceReference(String serviceInterfaceName, String refName);
+
+ /**
+ * Remove all service references.
+ */
+ void removeAllServiceReferences();
+
+ /**
+ * Remove all service references attached to given module.
+ * @return true iif at least one reference was removed
+ */
+ boolean removeServiceReferences(ObjectName objectName) throws InstanceNotFoundException;
+}
public @interface ServiceInterfaceAnnotation {
/**
- * Specifies human readable name of this service. Each service name should
- * be globally unique. Should not contain spaces.
+ * Fully qualified name of a service that must be globally unique.
+ * When generating service interfaces from yang, this will be QName of
+ * identity extending service-type.
*/
String value();
* is called.
*/
Class<?> osgiRegistrationType();
+
+ /**
+ * Get namespace of {@link #value()}
+ */
+ String namespace();
+
+ /**
+ * Get revision of {@link #value()}
+ */
+ String revision();
+
+ /**
+ * Get local name of {@link #value()}
+ */
+ String localName();
}
*/
package org.opendaylight.controller.config.api.jmx;
+import org.opendaylight.controller.config.api.ModuleIdentifier;
+import org.opendaylight.controller.config.api.jmx.constants.ConfigRegistryConstants;
+
+import javax.annotation.concurrent.ThreadSafe;
+import javax.management.ObjectName;
import java.util.Arrays;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Map.Entry;
import java.util.Set;
-import javax.annotation.concurrent.ThreadSafe;
-import javax.management.ObjectName;
-
-import org.opendaylight.controller.config.api.ModuleIdentifier;
-import org.opendaylight.controller.config.api.jmx.constants.ConfigRegistryConstants;
-
/**
* Provides ObjectName creation. Each created ObjectName consists of domain that
* is defined as {@link #ON_DOMAIN} and at least one key-value pair. The only
return objectName.getKeyProperty(TRANSACTION_NAME_KEY);
}
- public static ObjectName withoutTransactionName(ObjectName on) {
- if (getTransactionName(on) == null) {
+ /**
+ * Sanitize on: keep only mandatory attributes of module + metadata.
+ */
+ public static ObjectName withoutTransactionName(ObjectName inputON) {
+ if (getTransactionName(inputON) == null) {
throw new IllegalArgumentException(
- "Expected ObjectName with transaction:" + on);
+ "Expected ObjectName with transaction:" + inputON);
}
- if (ON_DOMAIN.equals(on.getDomain()) == false) {
+ if (ON_DOMAIN.equals(inputON.getDomain()) == false) {
throw new IllegalArgumentException("Expected different domain: "
- + on);
+ + inputON);
+ }
+ String moduleName = getFactoryName(inputON);
+ String instanceName = getInstanceName(inputON);
+
+
+ Map<String, String> allProperties = getAdditionalProperties(inputON);
+ Map<String, String> outputProperties = new HashMap<>(createModuleON(moduleName, instanceName));
+
+ for(Entry<String, String> entry: allProperties.entrySet()) {
+ if (entry.getKey().startsWith("X-")) {
+ outputProperties.put(entry.getKey(), entry.getValue());
+ }
}
- String moduleName = getFactoryName(on);
- String instanceName = getInstanceName(on);
- return createReadOnlyModuleON(moduleName, instanceName);
+ return createON(ON_DOMAIN, outputProperties);
}
private static void assertDoesNotContain(
boolean isModuleImplementingServiceInterface(
Class<? extends AbstractServiceInterface> serviceInterface);
+ Set<Class<? extends AbstractServiceInterface>> getImplementedServiceIntefaces();
+
/**
* Called when ModuleFactory is registered to config manager.
* Useful for populating the registry with pre-existing state. Since
import org.opendaylight.controller.config.api.ConflictingVersionException;
import org.opendaylight.controller.config.api.ModuleIdentifier;
import org.opendaylight.controller.config.api.RuntimeBeanRegistratorAwareModule;
+import org.opendaylight.controller.config.api.ServiceReferenceReadableRegistry;
+import org.opendaylight.controller.config.api.ServiceReferenceWritableRegistry;
import org.opendaylight.controller.config.api.ValidationException;
import org.opendaylight.controller.config.api.jmx.CommitStatus;
import org.opendaylight.controller.config.api.jmx.ObjectNameUtil;
@GuardedBy("this")
private List<ModuleFactory> lastListOfFactories = Collections.emptyList();
+ @GuardedBy("this") // switched in every 2ndPC
+ private ServiceReferenceReadableRegistry readableSRRegistry = ServiceReferenceRegistryImpl.createInitialSRLookupRegistry();
+
// constructor
public ConfigRegistryImpl(ModuleFactoriesResolver resolver,
BundleContext bundleContext, MBeanServer configMBeanServer) {
private synchronized ConfigTransactionControllerInternal beginConfigInternal(boolean blankTransaction) {
versionCounter++;
- String transactionName = "ConfigTransaction-" + version + "-" + versionCounter;
- TransactionJMXRegistrator transactionRegistrator = baseJMXRegistrator
- .createTransactionJMXRegistrator(transactionName);
- Map<String, Map.Entry<ModuleFactory, BundleContext>> allCurrentFactories = Collections.unmodifiableMap(resolver.getAllFactories());
+ final String transactionName = "ConfigTransaction-" + version + "-" + versionCounter;
+
+ TransactionJMXRegistratorFactory factory = new TransactionJMXRegistratorFactory() {
+ @Override
+ public TransactionJMXRegistrator create() {
+ return baseJMXRegistrator.createTransactionJMXRegistrator(transactionName);
+ }
+ };
+
+ ConfigTransactionLookupRegistry txLookupRegistry = new ConfigTransactionLookupRegistry(new TransactionIdentifier(
+ transactionName), factory);
+ Map<String, Map.Entry<ModuleFactory, BundleContext>> allCurrentFactories = Collections.unmodifiableMap(
+ resolver.getAllFactories());
+ ServiceReferenceWritableRegistry writableRegistry = ServiceReferenceRegistryImpl.createSRWritableRegistry(
+ readableSRRegistry, txLookupRegistry, allCurrentFactories);
+
ConfigTransactionControllerInternal transactionController = new ConfigTransactionControllerImpl(
- transactionName, transactionRegistrator, version,
- versionCounter, allCurrentFactories, transactionsMBeanServer, configMBeanServer, blankTransaction);
+ txLookupRegistry, version,
+ versionCounter, allCurrentFactories, transactionsMBeanServer,
+ configMBeanServer, blankTransaction, writableRegistry);
try {
- transactionRegistrator.registerMBean(transactionController, transactionController.getControllerObjectName());
+ txLookupRegistry.registerMBean(transactionController, transactionController.getControllerObjectName());
} catch (InstanceAlreadyExistsException e) {
throw new IllegalStateException(e);
}
-
transactionController.copyExistingModulesAndProcessFactoryDiff(currentConfig.getEntries(), lastListOfFactories);
-
transactionsHolder.add(transactionName, transactionController);
return transactionController;
}
// update version
version = configTransactionController.getVersion();
+
+ // switch readable Service Reference Registry
+ this.readableSRRegistry = ServiceReferenceRegistryImpl.createSRReadableRegistry(configTransactionController.getWritableRegistry(), this);
+
return new CommitStatus(newInstances, reusedInstances,
recreatedInstances);
}
return baseJMXRegistrator.queryNames(namePattern, null);
}
+ @Override
+ public void checkConfigBeanExists(ObjectName objectName) throws InstanceNotFoundException {
+ ObjectNameUtil.checkDomain(objectName);
+ ObjectNameUtil.checkType(objectName, ObjectNameUtil.TYPE_MODULE);
+ String transactionName = ObjectNameUtil.getTransactionName(objectName);
+ if (transactionName != null) {
+ throw new IllegalArgumentException("Transaction attribute not supported in registry, wrong ObjectName: " + objectName);
+ }
+ // make sure exactly one match is found:
+ LookupBeansUtil.lookupConfigBean(this, ObjectNameUtil.getFactoryName(objectName), ObjectNameUtil.getInstanceName(objectName));
+ }
+
+ // service reference functionality:
+ @Override
+ public synchronized ObjectName lookupConfigBeanByServiceInterfaceName(String serviceInterfaceName, String refName) {
+ return readableSRRegistry.lookupConfigBeanByServiceInterfaceName(serviceInterfaceName, refName);
+ }
+
+ @Override
+ public synchronized Map<String, Map<String, ObjectName>> getServiceMapping() {
+ return readableSRRegistry.getServiceMapping();
+ }
+
+ @Override
+ public synchronized Map<String, ObjectName> lookupServiceReferencesByServiceInterfaceName(String serviceInterfaceName) {
+ return readableSRRegistry.lookupServiceReferencesByServiceInterfaceName(serviceInterfaceName);
+ }
+
+ @Override
+ public synchronized Set<String> lookupServiceInterfaceNames(ObjectName objectName) throws InstanceNotFoundException {
+ return readableSRRegistry.lookupServiceInterfaceNames(objectName);
+ }
+
+ @Override
+ public synchronized String getServiceInterfaceName(String namespace, String localName) {
+ return readableSRRegistry.getServiceInterfaceName(namespace, localName);
+ }
}
/**
import org.opendaylight.controller.config.api.DependencyResolver;
import org.opendaylight.controller.config.api.ModuleIdentifier;
+import org.opendaylight.controller.config.api.ServiceReferenceWritableRegistry;
import org.opendaylight.controller.config.api.ValidationException;
import org.opendaylight.controller.config.api.jmx.ObjectNameUtil;
import org.opendaylight.controller.config.manager.impl.dependencyresolver.DependencyResolverManager;
import org.opendaylight.controller.config.manager.impl.dynamicmbean.ReadOnlyAtomicBoolean;
import org.opendaylight.controller.config.manager.impl.dynamicmbean.ReadOnlyAtomicBoolean.ReadOnlyAtomicBooleanImpl;
import org.opendaylight.controller.config.manager.impl.factoriesresolver.HierarchicalConfigMBeanFactoriesHolder;
-import org.opendaylight.controller.config.manager.impl.jmx.TransactionJMXRegistrator;
import org.opendaylight.controller.config.manager.impl.jmx.TransactionModuleJMXRegistrator;
import org.opendaylight.controller.config.manager.impl.jmx.TransactionModuleJMXRegistrator.TransactionModuleJMXRegistration;
-import org.opendaylight.controller.config.manager.impl.util.LookupBeansUtil;
import org.opendaylight.controller.config.spi.Module;
import org.opendaylight.controller.config.spi.ModuleFactory;
import org.opendaylight.yangtools.concepts.Identifiable;
/**
* This is a JMX bean representing current transaction. It contains
- * {@link #transactionIdentifier}, unique version and parent version for
+ * transaction identifier, unique version and parent version for
* optimistic locking.
*/
class ConfigTransactionControllerImpl implements
Identifiable<TransactionIdentifier>{
private static final Logger logger = LoggerFactory.getLogger(ConfigTransactionControllerImpl.class);
- private final TransactionIdentifier transactionIdentifier;
+ private final ConfigTransactionLookupRegistry txLookupRegistry;
private final ObjectName controllerON;
- private final TransactionJMXRegistrator transactionRegistrator;
- private final TransactionModuleJMXRegistrator txModuleJMXRegistrator;
+
private final long parentVersion, currentVersion;
private final HierarchicalConfigMBeanFactoriesHolder factoriesHolder;
private final DependencyResolverManager dependencyResolverManager;
private final boolean blankTransaction;
- public ConfigTransactionControllerImpl(String transactionName,
- TransactionJMXRegistrator transactionRegistrator,
+ @GuardedBy("this")
+ private final ServiceReferenceWritableRegistry writableSRRegistry;
+
+ public ConfigTransactionControllerImpl(ConfigTransactionLookupRegistry txLookupRegistry,
long parentVersion, long currentVersion,
Map<String, Map.Entry<ModuleFactory, BundleContext>> currentlyRegisteredFactories,
MBeanServer transactionsMBeanServer, MBeanServer configMBeanServer,
- boolean blankTransaction) {
-
- this.transactionIdentifier = new TransactionIdentifier(transactionName);
- this.controllerON = ObjectNameUtil
- .createTransactionControllerON(transactionName);
- this.transactionRegistrator = transactionRegistrator;
- txModuleJMXRegistrator = transactionRegistrator
- .createTransactionModuleJMXRegistrator();
+ boolean blankTransaction, ServiceReferenceWritableRegistry writableSRRegistry) {
+
+ this.txLookupRegistry = txLookupRegistry;
+ String transactionName = txLookupRegistry.getTransactionIdentifier().getName();
+ this.controllerON = ObjectNameUtil.createTransactionControllerON(transactionName);
this.parentVersion = parentVersion;
this.currentVersion = currentVersion;
this.currentlyRegisteredFactories = currentlyRegisteredFactories;
this.transactionsMBeanServer = transactionsMBeanServer;
this.configMBeanServer = configMBeanServer;
this.blankTransaction = blankTransaction;
+ this.writableSRRegistry = writableSRRegistry;
}
@Override
+ moduleIdentifier + ", got " + dependencyResolver.getIdentifier());
}
DynamicMBean writableDynamicWrapper = new DynamicWritableWrapper(
- module, moduleIdentifier, transactionIdentifier,
+ module, moduleIdentifier, getTransactionIdentifier(),
readOnlyAtomicBoolean, transactionsMBeanServer,
configMBeanServer);
ObjectName writableON = ObjectNameUtil.createTransactionModuleON(
- transactionIdentifier.getName(), moduleIdentifier);
+ getTransactionIdentifier().getName(), moduleIdentifier);
// put wrapper to jmx
- TransactionModuleJMXRegistration transactionModuleJMXRegistration = txModuleJMXRegistrator
+ TransactionModuleJMXRegistration transactionModuleJMXRegistration = getTxModuleJMXRegistrator()
.registerMBean(writableDynamicWrapper, writableON);
ModuleInternalTransactionalInfo moduleInternalTransactionalInfo = new ModuleInternalTransactionalInfo(
moduleIdentifier, module, moduleFactory,
}
@Override
- public synchronized void destroyModule(ObjectName objectName)
- throws InstanceNotFoundException {
+ public synchronized void destroyModule(ObjectName objectName) throws InstanceNotFoundException {
+ checkTransactionName(objectName);
+ ObjectNameUtil.checkDomain(objectName);
+ ModuleIdentifier moduleIdentifier = ObjectNameUtil.fromON(objectName,
+ ObjectNameUtil.TYPE_MODULE);
+ destroyModule(moduleIdentifier);
+ }
+
+ private void checkTransactionName(ObjectName objectName) {
String foundTransactionName = ObjectNameUtil
.getTransactionName(objectName);
- if (transactionIdentifier.getName().equals(foundTransactionName) == false) {
+ if (getTransactionIdentifier().getName().equals(foundTransactionName) == false) {
throw new IllegalArgumentException("Wrong transaction name "
+ objectName);
}
- ObjectNameUtil.checkDomain(objectName);
- ModuleIdentifier moduleIdentifier = ObjectNameUtil.fromON(objectName,
- ObjectNameUtil.TYPE_MODULE);
- destroyModule(moduleIdentifier);
}
private synchronized void destroyModule(ModuleIdentifier moduleIdentifier) {
logger.warn("Warning: removing default bean. This will be forbidden in next version of config-subsystem");
}
}
+ // first remove refNames, it checks for objectname existence
+ try {
+ writableSRRegistry.removeServiceReferences(
+ ObjectNameUtil.createTransactionModuleON(getTransactionName(),moduleIdentifier));
+ } catch (InstanceNotFoundException e) {
+ logger.error("Possible code error: cannot find {} in {}", moduleIdentifier, writableSRRegistry);
+ throw new IllegalStateException("Possible code error: cannot find " + moduleIdentifier, e);
+ }
+
ModuleInternalTransactionalInfo removedTInfo = dependencyResolverManager.destroyModule(moduleIdentifier);
// remove from jmx
removedTInfo.getTransactionModuleJMXRegistration().close();
private void validate_noLocks() throws ValidationException {
transactionStatus.checkNotAborted();
- logger.info("Validating transaction {}", transactionIdentifier);
+ logger.info("Validating transaction {}", getTransactionIdentifier());
// call validate()
List<ValidationException> collectedExceptions = new ArrayList<>();
for (Entry<ModuleIdentifier, Module> entry : dependencyResolverManager
throw ValidationException
.createFromCollectedValidationExceptions(collectedExceptions);
}
- logger.info("Validated transaction {}", transactionIdentifier);
+ logger.info("Validated transaction {}", getTransactionIdentifier());
}
/**
+ "to obtain a lock");
}
- logger.info("Committing transaction {}", transactionIdentifier);
+ logger.info("Committing transaction {}", getTransactionIdentifier());
// call getInstance()
for (Entry<ModuleIdentifier, Module> entry : dependencyResolverManager
ModuleIdentifier name = entry.getKey();
try {
logger.debug("About to commit {} in transaction {}",
- name, transactionIdentifier);
+ name, getTransactionIdentifier());
module.getInstance();
} catch (Exception e) {
logger.error("Commit failed on {} in transaction {}", name,
- transactionIdentifier, e);
+ getTransactionIdentifier(), e);
internalAbort();
throw new RuntimeException(
format("Error - getInstance() failed for %s in transaction %s",
- name, transactionIdentifier), e);
+ name, getTransactionIdentifier()), e);
}
}
// count dependency order
- logger.info("Committed configuration {}", transactionIdentifier);
+ logger.info("Committed configuration {}", getTransactionIdentifier());
transactionStatus.setCommitted();
// unregister this and all modules from jmx
close();
}
private void close() {
- transactionRegistrator.close();
+ //FIXME: should not close object that was retrieved in constructor, a wrapper object should do that perhaps
+ txLookupRegistry.close();
}
@Override
@Override
public String getTransactionName() {
- return transactionIdentifier.getName();
+ return getTransactionIdentifier().getName();
}
/**
*/
@Override
public Set<ObjectName> lookupConfigBeans() {
- return lookupConfigBeans("*", "*");
+ return txLookupRegistry.lookupConfigBeans();
}
/**
*/
@Override
public Set<ObjectName> lookupConfigBeans(String moduleName) {
- return lookupConfigBeans(moduleName, "*");
+ return txLookupRegistry.lookupConfigBeans(moduleName);
}
/**
@Override
public ObjectName lookupConfigBean(String moduleName, String instanceName)
throws InstanceNotFoundException {
- return LookupBeansUtil.lookupConfigBean(this, moduleName, instanceName);
+ return txLookupRegistry.lookupConfigBean(moduleName, instanceName);
}
/**
* {@inheritDoc}
*/
@Override
- public Set<ObjectName> lookupConfigBeans(String moduleName,
- String instanceName) {
- ObjectName namePattern = ObjectNameUtil.createModulePattern(moduleName,
- instanceName, transactionIdentifier.getName());
- return txModuleJMXRegistrator.queryNames(namePattern, null);
+ public Set<ObjectName> lookupConfigBeans(String moduleName, String instanceName) {
+ return txLookupRegistry.lookupConfigBeans(moduleName, instanceName);
}
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public void checkConfigBeanExists(ObjectName objectName) throws InstanceNotFoundException {
+ txLookupRegistry.checkConfigBeanExists(objectName);
+ }
+ // --
+
+ /**
+ * {@inheritDoc}
+ */
@Override
public Set<String> getAvailableModuleNames() {
return factoriesHolder.getModuleNames();
// @VisibleForTesting
TransactionModuleJMXRegistrator getTxModuleJMXRegistrator() {
- return txModuleJMXRegistrator;
+ return txLookupRegistry.getTxModuleJMXRegistrator();
}
public TransactionIdentifier getName() {
- return transactionIdentifier;
+ return getTransactionIdentifier();
}
@Override
@Override
public TransactionIdentifier getIdentifier() {
- return transactionIdentifier;
+ return getTransactionIdentifier();
}
@Override
}
return factoryBundleContextEntry.getValue();
}
+
+ // service reference functionality:
+
+
+ @Override
+ public synchronized ObjectName lookupConfigBeanByServiceInterfaceName(String serviceInterfaceName, String refName) {
+ return writableSRRegistry.lookupConfigBeanByServiceInterfaceName(serviceInterfaceName, refName);
+ }
+
+ @Override
+ public synchronized Map<String, Map<String, ObjectName>> getServiceMapping() {
+ return writableSRRegistry.getServiceMapping();
+ }
+
+ @Override
+ public synchronized Map<String, ObjectName> lookupServiceReferencesByServiceInterfaceName(String serviceInterfaceName) {
+ return writableSRRegistry.lookupServiceReferencesByServiceInterfaceName(serviceInterfaceName);
+ }
+
+ @Override
+ public synchronized Set<String> lookupServiceInterfaceNames(ObjectName objectName) throws InstanceNotFoundException {
+ return writableSRRegistry.lookupServiceInterfaceNames(objectName);
+ }
+
+ @Override
+ public synchronized String getServiceInterfaceName(String namespace, String localName) {
+ return writableSRRegistry.getServiceInterfaceName(namespace, localName);
+ }
+
+ @Override
+ public synchronized void saveServiceReference(String serviceInterfaceName, String refName, ObjectName objectName) throws InstanceNotFoundException {
+ writableSRRegistry.saveServiceReference(serviceInterfaceName, refName, objectName);
+ }
+
+ @Override
+ public synchronized boolean removeServiceReference(String serviceInterfaceName, String refName) {
+ return writableSRRegistry.removeServiceReference(serviceInterfaceName, refName);
+ }
+
+ @Override
+ public synchronized void removeAllServiceReferences() {
+ writableSRRegistry.removeAllServiceReferences();
+ }
+
+ @Override
+ public boolean removeServiceReferences(ObjectName objectName) throws InstanceNotFoundException {
+ return writableSRRegistry.removeServiceReferences(objectName);
+ }
+
+ @Override
+ public ServiceReferenceWritableRegistry getWritableRegistry() {
+ return writableSRRegistry;
+ }
+
+ public TransactionIdentifier getTransactionIdentifier() {
+ return txLookupRegistry.getTransactionIdentifier();
+ }
+
}
import javax.management.ObjectName;
import org.opendaylight.controller.config.api.ModuleIdentifier;
+import org.opendaylight.controller.config.api.ServiceReferenceWritableRegistry;
import org.opendaylight.controller.config.api.ValidationException;
import org.opendaylight.controller.config.spi.ModuleFactory;
import org.osgi.framework.BundleContext;
List<ModuleFactory> getCurrentlyRegisteredFactories();
BundleContext getModuleFactoryBundleContext(String factoryName);
+
+ ServiceReferenceWritableRegistry getWritableRegistry();
+
}
--- /dev/null
+/*
+ * Copyright (c) 2013 Cisco Systems, Inc. and others. All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+package org.opendaylight.controller.config.manager.impl;
+
+import org.opendaylight.controller.config.api.LookupRegistry;
+import org.opendaylight.controller.config.api.jmx.ObjectNameUtil;
+import org.opendaylight.controller.config.manager.impl.jmx.TransactionJMXRegistrator;
+import org.opendaylight.controller.config.manager.impl.jmx.TransactionModuleJMXRegistrator;
+import org.opendaylight.controller.config.manager.impl.util.LookupBeansUtil;
+
+import javax.management.InstanceAlreadyExistsException;
+import javax.management.InstanceNotFoundException;
+import javax.management.ObjectName;
+import java.io.Closeable;
+import java.util.Set;
+
+/**
+ * Responsible for creating TransactionJMXRegistrator, registering transaction and all its beans,
+ * lookup of beans, closing of TransactionJMXRegistrator.
+ */
+class ConfigTransactionLookupRegistry implements LookupRegistry, Closeable {
+ private final TransactionJMXRegistrator transactionJMXRegistrator;
+ private final TransactionIdentifier transactionIdentifier;
+ private final TransactionModuleJMXRegistrator txModuleJMXRegistrator;
+
+ ConfigTransactionLookupRegistry(TransactionIdentifier transactionIdentifier,
+ TransactionJMXRegistratorFactory factory) {
+ this.transactionIdentifier = transactionIdentifier;
+ this.transactionJMXRegistrator = factory.create();
+ this.txModuleJMXRegistrator = transactionJMXRegistrator.createTransactionModuleJMXRegistrator();
+ }
+
+ private void checkTransactionName(ObjectName objectName) {
+ String foundTransactionName = ObjectNameUtil
+ .getTransactionName(objectName);
+ if (transactionIdentifier.getName().equals(foundTransactionName) == false) {
+ throw new IllegalArgumentException("Wrong transaction name "
+ + objectName);
+ }
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public Set<ObjectName> lookupConfigBeans() {
+ return lookupConfigBeans("*", "*");
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public Set<ObjectName> lookupConfigBeans(String moduleName) {
+ return lookupConfigBeans(moduleName, "*");
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public ObjectName lookupConfigBean(String moduleName, String instanceName)
+ throws InstanceNotFoundException {
+ return LookupBeansUtil.lookupConfigBean(this, moduleName, instanceName);
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public Set<ObjectName> lookupConfigBeans(String moduleName,
+ String instanceName) {
+ ObjectName namePattern = ObjectNameUtil.createModulePattern(moduleName,
+ instanceName, transactionIdentifier.getName());
+ return txModuleJMXRegistrator.queryNames(namePattern, null);
+ }
+
+ @Override
+ public void checkConfigBeanExists(ObjectName objectName) throws InstanceNotFoundException {
+ ObjectNameUtil.checkDomain(objectName);
+ ObjectNameUtil.checkType(objectName, ObjectNameUtil.TYPE_MODULE);
+ checkTransactionName(objectName);
+ // make sure exactly one match is found:
+ LookupBeansUtil.lookupConfigBean(this, ObjectNameUtil.getFactoryName(objectName), ObjectNameUtil.getInstanceName(objectName));
+ }
+
+ TransactionIdentifier getTransactionIdentifier() {
+ return transactionIdentifier;
+ }
+
+ TransactionModuleJMXRegistrator getTxModuleJMXRegistrator() {
+ return txModuleJMXRegistrator;
+ }
+
+ public void close() {
+ transactionJMXRegistrator.close();
+ }
+
+ public void registerMBean(ConfigTransactionControllerInternal transactionController, ObjectName controllerObjectName) throws InstanceAlreadyExistsException {
+ transactionJMXRegistrator.registerMBean(transactionController, controllerObjectName);
+ }
+}
+
+interface TransactionJMXRegistratorFactory {
+ TransactionJMXRegistrator create();
+}
--- /dev/null
+/*
+ * Copyright (c) 2013 Cisco Systems, Inc. and others. All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+package org.opendaylight.controller.config.manager.impl;
+
+import org.opendaylight.controller.config.api.LookupRegistry;
+import org.opendaylight.controller.config.api.ModuleIdentifier;
+import org.opendaylight.controller.config.api.ServiceReferenceReadableRegistry;
+import org.opendaylight.controller.config.api.ServiceReferenceWritableRegistry;
+import org.opendaylight.controller.config.api.annotations.ServiceInterfaceAnnotation;
+import org.opendaylight.controller.config.api.jmx.ObjectNameUtil;
+import org.opendaylight.controller.config.manager.impl.util.InterfacesHelper;
+import org.opendaylight.controller.config.spi.ModuleFactory;
+import org.osgi.framework.BundleContext;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import javax.management.InstanceNotFoundException;
+import javax.management.ObjectName;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.Iterator;
+import java.util.Map;
+import java.util.Map.Entry;
+import java.util.Set;
+
+public class ServiceReferenceRegistryImpl implements ServiceReferenceReadableRegistry, ServiceReferenceWritableRegistry {
+ private static final Logger logger = LoggerFactory.getLogger(ServiceReferenceRegistryImpl.class);
+
+ private final Map<String, ModuleFactory> factories;
+ private final Map<String, Set<String>> factoryNamesToQNames;
+ // validator of incoming ObjectNames - throws InstanceNotFoundException if not found either in registry or transaction
+ private final LookupRegistry lookupRegistry;
+ // helper method for getting QName of SI from namespace + local name
+ private final Map<String /* namespace */, Map<String /* local name */, ServiceInterfaceAnnotation>> namespacesToAnnotations;
+ // all Service Interface qNames for sanity checking
+ private final Set<String /* qName */> allQNames;
+
+ // actual reference database
+ private final Map<String /* qName */, Map<String /* refName */, ModuleIdentifier>> refNames;
+
+ /**
+ * Static constructor for config registry. Since only transaction can write to this registry, it will
+ * return blank state.
+ */
+ public static ServiceReferenceReadableRegistry createInitialSRLookupRegistry() {
+ // since this is initial state, just throw exception:
+ LookupRegistry lookupRegistry = new LookupRegistry() {
+ @Override
+ public Set<ObjectName> lookupConfigBeans() {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public Set<ObjectName> lookupConfigBeans(String moduleName) {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public Set<ObjectName> lookupConfigBeans(String moduleName, String instanceName) {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public ObjectName lookupConfigBean(String moduleName, String instanceName) throws InstanceNotFoundException {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public void checkConfigBeanExists(ObjectName objectName) throws InstanceNotFoundException {
+ throw new InstanceNotFoundException("Cannot find " + objectName);
+ }
+ };
+ return new ServiceReferenceRegistryImpl(Collections.<String, ModuleFactory>emptyMap(), lookupRegistry,
+ Collections.<String /* qName */, Map<String /* refName */, ModuleIdentifier>>emptyMap());
+ }
+
+ /**
+ * Static constructor for transaction controller. Take current state as seen by config registry, allow writing new data.
+ */
+ public static ServiceReferenceWritableRegistry createSRWritableRegistry(ServiceReferenceReadableRegistry oldReadableRegistry,
+ LookupRegistry lookupRegistry, Map<String, Map.Entry<ModuleFactory, BundleContext>> currentlyRegisteredFactories) {
+
+ ServiceReferenceRegistryImpl old = (ServiceReferenceRegistryImpl) oldReadableRegistry;
+ Map<String, ModuleFactory> factories = extractFactoriesMap(currentlyRegisteredFactories);
+ return new ServiceReferenceRegistryImpl(factories, lookupRegistry, Collections.unmodifiableMap(old.refNames));
+ }
+
+ /**
+ * Copy back state to config registry after commit.
+ */
+ public static ServiceReferenceReadableRegistry createSRReadableRegistry(ServiceReferenceWritableRegistry oldWritableRegistry, LookupRegistry lookupRegistry) {
+ ServiceReferenceRegistryImpl old = (ServiceReferenceRegistryImpl) oldWritableRegistry;
+ // even if factories do change, nothing in the mapping can change between transactions
+ return new ServiceReferenceRegistryImpl(old.factories, lookupRegistry, Collections.unmodifiableMap(old.refNames));
+ }
+
+ private static Map<String, ModuleFactory> extractFactoriesMap(Map<String, Map.Entry<ModuleFactory, BundleContext>> currentlyRegisteredFactories) {
+ Map<String, ModuleFactory> result = new HashMap<>();
+ for (Entry<String, Entry<ModuleFactory, BundleContext>> entry : currentlyRegisteredFactories.entrySet()) {
+ result.put(entry.getKey(), entry.getValue().getKey());
+ }
+ return result;
+ }
+
+ private ServiceReferenceRegistryImpl(Map<String, ModuleFactory> factories, LookupRegistry lookupRegistry,
+ Map<String /* qName */, Map<String /* refName */, ModuleIdentifier>> refNamesToCopy) {
+ this.factories = factories;
+ this.lookupRegistry = lookupRegistry;
+ Map<String, Set<String /* QName */>> factoryNamesToQNames = new HashMap<>();
+ Set<ServiceInterfaceAnnotation> allAnnotations = new HashSet<>();
+ Set<String /* qName */> allQNames = new HashSet<>();
+ for (Entry<String, ModuleFactory> entry : factories.entrySet()) {
+ if (entry.getKey().equals(entry.getValue().getImplementationName()) == false) {
+ logger.error("Possible error in code: Mismatch between supplied and actual name of {}", entry);
+ throw new IllegalArgumentException("Possible error in code: Mismatch between supplied and actual name of " + entry);
+ }
+ Set<ServiceInterfaceAnnotation> siAnnotations = InterfacesHelper.getServiceInterfaceAnnotations(entry.getValue());
+ Set<String> qNames = new HashSet<>();
+ for (ServiceInterfaceAnnotation sia: siAnnotations) {
+ qNames.add(sia.value());
+ }
+ allAnnotations.addAll(siAnnotations);
+ allQNames.addAll(qNames);
+ factoryNamesToQNames.put(entry.getKey(), Collections.unmodifiableSet(qNames));
+ }
+ this.factoryNamesToQNames = Collections.unmodifiableMap(factoryNamesToQNames);
+ this.allQNames = Collections.unmodifiableSet(allQNames);
+ // fill namespacesToAnnotations
+ Map<String /* namespace */, Map<String /* localName */, ServiceInterfaceAnnotation>> namespacesToAnnotations =
+ new HashMap<>();
+ for (ServiceInterfaceAnnotation sia : allAnnotations) {
+ Map<String, ServiceInterfaceAnnotation> ofNamespace = namespacesToAnnotations.get(sia.namespace());
+ if (ofNamespace == null) {
+ ofNamespace = new HashMap<>();
+ namespacesToAnnotations.put(sia.namespace(), ofNamespace);
+ }
+ if (ofNamespace.containsKey(sia.localName())) {
+ logger.error("Cannot construct namespacesToAnnotations map, conflict between local names in {}, offending local name: {}, map so far {}",
+ sia.namespace(), sia.localName(), namespacesToAnnotations);
+ throw new IllegalArgumentException("Conflict between local names in " + sia.namespace() + " : " + sia.localName());
+ }
+ ofNamespace.put(sia.localName(), sia);
+ }
+ this.namespacesToAnnotations = Collections.unmodifiableMap(namespacesToAnnotations);
+ // copy refNames
+ Map<String /* qName */, Map<String /* refName */, ModuleIdentifier>> deepCopy = new HashMap<>();
+ for (Entry<String, Map<String, ModuleIdentifier>> outerROEntry: refNamesToCopy.entrySet()) {
+ Map<String /* refName */, ModuleIdentifier> innerWritableMap = new HashMap<>();
+ deepCopy.put(outerROEntry.getKey(), innerWritableMap);
+ for (Entry<String, ModuleIdentifier> innerROEntry: outerROEntry.getValue().entrySet()) {
+ innerWritableMap.put(innerROEntry.getKey(), innerROEntry.getValue());
+ }
+ }
+ this.refNames = deepCopy;
+ logger.trace("factoryNamesToQNames:{}", this.factoryNamesToQNames);
+ logger.trace("refNames:{}", refNames);
+ }
+
+
+ @Override
+ public Set<String> lookupServiceInterfaceNames(ObjectName objectName) throws InstanceNotFoundException {
+ lookupRegistry.checkConfigBeanExists(objectName);
+
+ String factoryName = ObjectNameUtil.getFactoryName(objectName);
+ Set<String> serviceInterfaceAnnotations = factoryNamesToQNames.get(factoryName);
+ if (serviceInterfaceAnnotations == null) {
+ logger.error("Possible error in code: cannot find factory annotations of '{}' extracted from ON {} in {}",
+ factoryName, objectName, factoryNamesToQNames);
+ throw new IllegalArgumentException("Cannot find factory with name " + factoryName);
+ }
+ return serviceInterfaceAnnotations;
+ }
+
+ @Override
+ public String getServiceInterfaceName(String namespace, String localName) {
+ Map<String /* localName */, ServiceInterfaceAnnotation> ofNamespace = namespacesToAnnotations.get(namespace);
+ if (ofNamespace == null) {
+ logger.error("Cannot find namespace {} in {}", namespace, namespacesToAnnotations);
+ throw new IllegalArgumentException("Cannot find namespace " + namespace);
+ }
+ ServiceInterfaceAnnotation sia = ofNamespace.get(localName);
+ if (sia == null) {
+ logger.error("Cannot find local name {} in namespace {}, found only {}", localName, namespace, ofNamespace);
+ throw new IllegalArgumentException("Cannot find local name " + localName + " in namespace " + namespace);
+ }
+ return sia.value();
+ }
+
+
+
+ // reading:
+
+ @Override
+ public Map<String /* serviceInterfaceName */, Map<String/* refName */, ObjectName>> getServiceMapping() {
+ Map<String /* serviceInterfaceName */, Map<String/* refName */, ObjectName>> result = new HashMap<>();
+ for (Entry<String /* qName */, Map<String, ModuleIdentifier>> outerEntry: refNames.entrySet()) {
+ String qName = outerEntry.getKey();
+ Map<String /* refName */, ObjectName> innerMap = new HashMap<>();
+ result.put(qName, innerMap);
+ for (Entry<String /* refName */, ModuleIdentifier> innerEntry: outerEntry.getValue().entrySet()) {
+ ModuleIdentifier moduleIdentifier = innerEntry.getValue();
+ ObjectName on;
+ on = getObjectName(moduleIdentifier);
+ innerMap.put(innerEntry.getKey(), on);
+ }
+ }
+ return result;
+ }
+
+ private ObjectName getObjectName(ModuleIdentifier moduleIdentifier) {
+ ObjectName on;
+ try {
+ on = lookupRegistry.lookupConfigBean(moduleIdentifier.getFactoryName(), moduleIdentifier.getInstanceName());
+ } catch (InstanceNotFoundException e) {
+ logger.error("Cannot find instance {}", moduleIdentifier);
+ throw new IllegalStateException("Cannot find instance " + moduleIdentifier, e);
+ }
+ return on;
+ }
+
+ @Override
+ public ObjectName lookupConfigBeanByServiceInterfaceName(String serviceInterfaceName, String refName) {
+ Map<String, ModuleIdentifier> innerMap = refNames.get(serviceInterfaceName);
+ if (innerMap == null) {
+ logger.error("Cannot find qname {} in {}", serviceInterfaceName, refName);
+ throw new IllegalArgumentException("Cannot find " + serviceInterfaceName);
+ }
+ ModuleIdentifier moduleIdentifier = innerMap.get(refName);
+ if (moduleIdentifier == null) {
+ logger.error("Cannot find refName {} in {}, using qname {}", refName, innerMap, serviceInterfaceName);
+ throw new IllegalArgumentException("Cannot find module based on service reference " + refName);
+ }
+ return getObjectName(moduleIdentifier);
+ }
+
+ @Override
+ public Map<String /* refName */, ObjectName> lookupServiceReferencesByServiceInterfaceName(String serviceInterfaceName) {
+ Map<String, ModuleIdentifier> innerMap = refNames.get(serviceInterfaceName);
+ if (innerMap == null) {
+ logger.error("Cannot find qname {} in {}", serviceInterfaceName, refNames);
+ throw new IllegalArgumentException("Cannot find " + serviceInterfaceName);
+ }
+ Map<String /* refName */, ObjectName> result = new HashMap<>();
+ for (Entry<String/* refName */, ModuleIdentifier> entry: innerMap.entrySet()) {
+ ObjectName on = getObjectName(entry.getValue());
+ result.put(entry.getKey(), on);
+ }
+ return result;
+ }
+
+ // writing:
+
+ @Override
+ public void saveServiceReference(String serviceInterfaceName, String refName, ObjectName objectName) throws InstanceNotFoundException {
+ // make sure it is found
+ lookupRegistry.checkConfigBeanExists(objectName);
+ String factoryName = ObjectNameUtil.getFactoryName(objectName);
+ // check that service interface name exist
+ Set<String> serviceInterfaceQNames = factoryNamesToQNames.get(factoryName);
+ if (serviceInterfaceQNames == null) {
+ logger.error("Possible error in code: cannot find factoryName {} in {}, object name {}", factoryName, factoryNamesToQNames, objectName);
+ throw new IllegalStateException("Possible error in code: cannot find annotations of existing factory " + factoryName);
+ }
+ // supplied serviceInterfaceName must exist in this collection
+ if (serviceInterfaceQNames.contains(serviceInterfaceName) == false) {
+ logger.error("Cannot find qname {} with factory name {}, found {}", serviceInterfaceName, factoryName, serviceInterfaceQNames);
+ throw new IllegalArgumentException("Cannot find service interface " + serviceInterfaceName + " within factory " + factoryName );
+ }
+ String instanceName = ObjectNameUtil.getInstanceName(objectName);
+ ModuleIdentifier moduleIdentifier = new ModuleIdentifier(factoryName, instanceName);
+ Map<String /* refName */, ModuleIdentifier> ofQName = refNames.get(serviceInterfaceName);
+ // might be null
+ if (ofQName == null) {
+ ofQName = new HashMap<>();
+ refNames.put(serviceInterfaceName, ofQName);
+ }
+ ofQName.put(refName, moduleIdentifier);
+ }
+
+ @Override
+ public boolean removeServiceReference(String serviceInterfaceName, String refName) {
+ // is the qname known?
+ if (allQNames.contains(serviceInterfaceName) == false) {
+ logger.error("Cannot find qname {} in {}", serviceInterfaceName, allQNames);
+ throw new IllegalArgumentException("Cannot find service interface " + serviceInterfaceName);
+ }
+ Map<String, ModuleIdentifier> ofQName = refNames.get(serviceInterfaceName);
+ if (ofQName == null) {
+ return false;
+ }
+ return ofQName.remove(refName) != null;
+ }
+
+ @Override
+ public void removeAllServiceReferences() {
+ refNames.clear();
+ }
+
+ @Override
+ public boolean removeServiceReferences(ObjectName objectName) throws InstanceNotFoundException {
+ lookupRegistry.checkConfigBeanExists(objectName);
+ String factoryName = ObjectNameUtil.getFactoryName(objectName);
+ // check that service interface name exist
+ Set<String> serviceInterfaceQNames = factoryNamesToQNames.get(factoryName);
+ if (serviceInterfaceQNames == null) {
+ logger.error("Possible error in code: cannot find factoryName {} in {}, object name {}", factoryName, factoryNamesToQNames, objectName);
+ throw new IllegalStateException("Possible error in code: cannot find annotations of existing factory " + factoryName);
+ }
+ String instanceName = ObjectNameUtil.getInstanceName(objectName);
+ ModuleIdentifier moduleIdentifier = new ModuleIdentifier(factoryName, instanceName);
+ boolean found = false;
+ for(String qName: serviceInterfaceQNames){
+ Map<String, ModuleIdentifier> ofQName = refNames.get(qName);
+ if (ofQName != null) {
+ for(Iterator<Entry<String, ModuleIdentifier>> it = ofQName.entrySet ().iterator(); it.hasNext();){
+ Entry<String, ModuleIdentifier> next = it.next();
+ if (next.getValue().equals(moduleIdentifier)) {
+ found = true;
+ it.remove();
+ }
+ }
+ }
+ }
+ return found;
+ }
+
+ @Override
+ public String toString() {
+ return "ServiceReferenceRegistryImpl{" +
+ "refNames=" + refNames +
+ ", factoryNamesToQNames=" + factoryNamesToQNames +
+ '}';
+ }
+}
/**
* {@inheritDoc}
*/
+ //TODO: check for cycles
@Override
public void validateDependency(
Class<? extends AbstractServiceInterface> expectedServiceInterface,
/**
* {@inheritDoc}
*/
+ //TODO: check for cycles
@Override
public <T> T resolveInstance(Class<T> expectedType, ObjectName dependentON,
JmxAttribute jmxAttribute) {
}
@Override
- public void close() {
+ public void close() { // closes also all child TransactionModuleJMXRegistrator instances
childJMXRegistrator.close();
}
}
*/
package org.opendaylight.controller.config.manager.impl.util;
+import org.opendaylight.controller.config.api.annotations.AbstractServiceInterface;
+import org.opendaylight.controller.config.api.annotations.ServiceInterfaceAnnotation;
+import org.opendaylight.controller.config.spi.Module;
+import org.opendaylight.controller.config.spi.ModuleFactory;
+
+import javax.management.JMX;
import java.util.Arrays;
+import java.util.Collections;
import java.util.HashSet;
import java.util.Iterator;
import java.util.Set;
-import javax.management.JMX;
-
-import org.opendaylight.controller.config.api.annotations.AbstractServiceInterface;
-import org.opendaylight.controller.config.api.annotations.ServiceInterfaceAnnotation;
-import org.opendaylight.controller.config.spi.Module;
-
public class InterfacesHelper {
public static Set<Class<?>> getAllInterfaces(Class<?> clazz) {
// get parent class
clazz = clazz.getSuperclass();
}
+ return getAllSuperInterfaces(toBeInspected);
+
+ }
+
+ private static Set<Class<?>> getAllSuperInterfaces(Set<Class<?>> ifcs) {
+ ifcs = new HashSet<>(ifcs); // create copy to modify
// each interface can extend other interfaces
- Set<Class<?>> inspected = new HashSet<>();
- while (toBeInspected.size() > 0) {
- Iterator<Class<?>> iterator = toBeInspected.iterator();
+ Set<Class<?>> result = new HashSet<>();
+ while (ifcs.size() > 0) {
+ Iterator<Class<?>> iterator = ifcs.iterator();
Class<?> ifc = iterator.next();
iterator.remove();
- toBeInspected.addAll(Arrays.asList(ifc.getInterfaces()));
- inspected.add(ifc);
+ if (ifc.isInterface() == false) {
+ throw new IllegalArgumentException(ifc + " should be an interface");
+ }
+ ifcs.addAll(Arrays.asList(ifc.getInterfaces()));
+ result.add(ifc);
}
- return inspected;
+ return result;
}
/**
return result;
}
+ public static Set<Class<? extends AbstractServiceInterface>> getAllAbstractServiceClasses(Class<? extends Module> configBeanClass) {
+
+ Set<Class<? extends AbstractServiceInterface>> foundGeneratedSIClasses = new HashSet<>();
+ for (Class<?> clazz : getAllInterfaces(configBeanClass)) {
+ if (AbstractServiceInterface.class.isAssignableFrom(clazz) && AbstractServiceInterface.class.equals(clazz) == false) {
+ foundGeneratedSIClasses.add((Class<? extends AbstractServiceInterface>) clazz);
+ }
+ }
+ return getAllAbstractServiceInterfaceClasses(foundGeneratedSIClasses);
+ }
+
+
/**
* Get OSGi registration types under which config bean instance should be
* registered. This is specified in
return result;
}
+
+ public static Set<ServiceInterfaceAnnotation> getServiceInterfaceAnnotations(ModuleFactory factory) {
+ Set<Class<? extends AbstractServiceInterface>> implementedServiceIntefaces = Collections.unmodifiableSet(factory.getImplementedServiceIntefaces());
+ return getServiceInterfaceAnnotations(implementedServiceIntefaces);
+ }
+
+ private static Set<ServiceInterfaceAnnotation> getServiceInterfaceAnnotations(Set<Class<? extends AbstractServiceInterface>> implementedServiceIntefaces) {
+ Set<Class<? extends AbstractServiceInterface>> inspected = getAllAbstractServiceInterfaceClasses(implementedServiceIntefaces);
+ Set<ServiceInterfaceAnnotation> result = new HashSet<>();
+ // SIs can form hierarchies, inspect superclass until it does not extend AbstractSI
+ for (Class<?> clazz : inspected) {
+ ServiceInterfaceAnnotation annotation = clazz.getAnnotation(ServiceInterfaceAnnotation.class);
+ if (annotation != null) {
+ result.add(annotation);
+ }
+ }
+ return result;
+ }
+
+ static Set<Class<? extends AbstractServiceInterface>> getAllAbstractServiceInterfaceClasses(
+ Set<Class<? extends AbstractServiceInterface>> directlyImplementedAbstractSIs) {
+
+ Set<Class<?>> allInterfaces = getAllSuperInterfaces((Set) directlyImplementedAbstractSIs);
+ Set<Class<? extends AbstractServiceInterface>> result = new HashSet<>();
+ for(Class<?> ifc: allInterfaces){
+ if (AbstractServiceInterface.class.isAssignableFrom(ifc) &&
+ ifc.equals(AbstractServiceInterface.class) == false) {
+ result.add((Class<? extends AbstractServiceInterface>) ifc);
+ }
+
+ }
+ return result;
+ }
}
+++ /dev/null
-/*
- * Copyright (c) 2013 Cisco Systems, Inc. and others. All rights reserved.
- *
- * This program and the accompanying materials are made available under the
- * terms of the Eclipse Public License v1.0 which accompanies this distribution,
- * and is available at http://www.eclipse.org/legal/epl-v10.html
- */
-package org.opendaylight.controller.config.manager.impl;
-
-import org.junit.After;
-import org.junit.Before;
-import org.opendaylight.controller.config.manager.impl.factoriesresolver.ModuleFactoriesResolver;
-import org.opendaylight.controller.config.util.JolokiaHelper;
-import org.opendaylight.controller.config.util.jolokia.ConfigRegistryJolokiaClient;
-
-public class AbstractConfigWithJolokiaTest extends AbstractConfigTest {
- protected String jolokiaURL;
- protected ConfigRegistryJolokiaClient configRegistryJolokiaClient;
-
- @Before
- public void initJolokia() {
- jolokiaURL = JolokiaHelper.startTestingJolokia();
- }
-
- // this method should be called in @Before
- @Override
- protected void initConfigTransactionManagerImpl(
- ModuleFactoriesResolver resolver) {
- super.initConfigTransactionManagerImpl(resolver);
- configRegistryJolokiaClient = new ConfigRegistryJolokiaClient(
- jolokiaURL);
- }
-
- @After
- public void cleanUpJolokia() {
- JolokiaHelper.stopJolokia();
- }
-}
import org.opendaylight.controller.config.api.DynamicMBeanWithInstance;
import org.opendaylight.controller.config.api.ModuleIdentifier;
import org.opendaylight.controller.config.api.annotations.AbstractServiceInterface;
+import org.opendaylight.controller.config.manager.impl.util.InterfacesHelper;
import org.opendaylight.controller.config.spi.Module;
import org.opendaylight.controller.config.spi.ModuleFactory;
import org.osgi.framework.BundleContext;
public Set<Module> getDefaultModules(DependencyResolverFactory dependencyResolverFactory, BundleContext bundleContext) {
return new HashSet<Module>();
}
+
+ @Override
+ public Set<Class<? extends AbstractServiceInterface>> getImplementedServiceIntefaces() {
+ return InterfacesHelper.getAllAbstractServiceClasses(configBeanClass);
+ }
}
import org.junit.After;
import org.junit.Before;
import org.junit.Test;
+import org.opendaylight.controller.config.api.ServiceReferenceWritableRegistry;
import org.opendaylight.controller.config.api.jmx.ObjectNameUtil;
import org.opendaylight.controller.config.manager.impl.jmx.BaseJMXRegistrator;
import org.opendaylight.controller.config.manager.impl.jmx.TransactionJMXRegistrator;
ManagementFactory.getPlatformMBeanServer());
transactionsMBeanServer = MBeanServerFactory.createMBeanServer();
Map<String, Map.Entry<ModuleFactory, BundleContext>> currentlyRegisteredFactories = new HashMap<>();
- TransactionJMXRegistrator jmxRegistrator123 = baseJMXRegistrator
- .createTransactionJMXRegistrator(transactionName123);
+
+ ConfigTransactionLookupRegistry txLookupRegistry = new ConfigTransactionLookupRegistry(new TransactionIdentifier(transactionName123), new TransactionJMXRegistratorFactory() {
+ @Override
+ public TransactionJMXRegistrator create() {
+ return baseJMXRegistrator.createTransactionJMXRegistrator(transactionName123);
+ }
+ });
+
+ ServiceReferenceWritableRegistry writableRegistry = ServiceReferenceRegistryImpl.createSRWritableRegistry(
+ ServiceReferenceRegistryImpl.createInitialSRLookupRegistry(), txLookupRegistry, currentlyRegisteredFactories);
+
testedTxController = new ConfigTransactionControllerImpl(
- transactionName123, jmxRegistrator123, 1, 1,
+ txLookupRegistry, 1, 1,
currentlyRegisteredFactories, transactionsMBeanServer,
- ManagementFactory.getPlatformMBeanServer(), false);
+ ManagementFactory.getPlatformMBeanServer(), false, writableRegistry);
TransactionModuleJMXRegistrator transactionModuleJMXRegistrator123 = testedTxController
.getTxModuleJMXRegistrator();
transactionModuleJMXRegistrator123.registerMBean(
*/
package org.opendaylight.controller.config.manager.impl;
-import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertTrue;
-import static org.junit.Assert.fail;
-import static org.mockito.Mockito.mock;
-
-import javax.management.InstanceAlreadyExistsException;
-
import org.junit.Before;
import org.junit.Test;
-import org.opendaylight.controller.config.api.jmx.ObjectNameUtil;
-import org.opendaylight.controller.config.api.jmx.constants.ConfigRegistryConstants;
import org.opendaylight.controller.config.manager.impl.factoriesresolver.HardcodedModuleFactoriesResolver;
import org.opendaylight.controller.config.util.ConfigTransactionJMXClient;
-import org.opendaylight.controller.config.util.jolokia.ConfigTransactionJolokiaClient;
+
+import javax.management.InstanceAlreadyExistsException;
+
+import static org.junit.Assert.assertTrue;
+import static org.junit.Assert.fail;
+import static org.mockito.Mockito.mock;
public class ConfigTransactionManagerImplTest extends
- AbstractConfigWithJolokiaTest {
+ AbstractConfigTest {
@Before
public void setUp() {
transaction.commit();
}
- @Test
- public void testRemoteCallsUsingJolokia() throws Exception {
-
- ConfigTransactionJolokiaClient transactionClient = configRegistryJolokiaClient
- .createTransaction();
-
- assertEquals("ConfigTransaction-0-1",
- ObjectNameUtil.getTransactionName(transactionClient
- .getTransactionON()));
-
- assertEquals(
- ConfigRegistryConstants.ON_DOMAIN
- + ":TransactionName=ConfigTransaction-0-1,type=ConfigTransaction",
- transactionClient.getTransactionON().getCanonicalName());
-
- // commit
- transactionClient.commit();
-
- }
}
static final String SIMPLE = "simple";
static final String SUBCLASS2 = "subclass2";
- @ServiceInterfaceAnnotation(value = SIMPLE, osgiRegistrationType = Executor.class)
+ @ServiceInterfaceAnnotation(value = SIMPLE, osgiRegistrationType = Executor.class,
+ namespace = "ns", revision = "rev", localName = SIMPLE)
static interface SimpleSI extends AbstractServiceInterface {
}
}
- @ServiceInterfaceAnnotation(value = SUBCLASS2, osgiRegistrationType = ExecutorService.class)
+ @ServiceInterfaceAnnotation(value = SUBCLASS2, osgiRegistrationType = ExecutorService.class,
+ namespace = "ns", revision = "rev", localName = SUBCLASS2)
+
static interface SubSI2 extends SubSI {
}
import static org.junit.Assert.assertEquals;
+import java.util.HashSet;
import java.util.Set;
import javax.management.MXBean;
import org.junit.Test;
+import org.opendaylight.controller.config.api.annotations.AbstractServiceInterface;
+import org.opendaylight.controller.config.manager.testingservices.seviceinterface.TestingScheduledThreadPoolServiceInterface;
+import org.opendaylight.controller.config.manager.testingservices.seviceinterface.TestingThreadPoolServiceInterface;
import org.opendaylight.controller.config.spi.Module;
import org.opendaylight.yangtools.concepts.Identifiable;
assertEquals(expected, InterfacesHelper.getMXInterfaces(SubClass.class));
}
+ @Test
+ public void testGetAllAbstractServiceInterfaceClasses(){
+ Class<? extends AbstractServiceInterface> clazz = TestingScheduledThreadPoolServiceInterface.class;
+ Set<Class<? extends AbstractServiceInterface>> input = new HashSet<>();
+ input.add(clazz);
+ Set<Class<? extends AbstractServiceInterface>> result = InterfacesHelper.getAllAbstractServiceInterfaceClasses(input);
+
+ Set<Class<?>> expected = Sets.newHashSet((Class<?>) TestingScheduledThreadPoolServiceInterface.class,
+ TestingThreadPoolServiceInterface.class
+ );
+ assertEquals(expected, result);
+ }
+
}
import org.opendaylight.controller.config.api.annotations.ServiceInterfaceAnnotation;
-@ServiceInterfaceAnnotation(value = TestingParallelAPSPConfigMXBean.NAME, osgiRegistrationType = TestingAPSP.class)
+@ServiceInterfaceAnnotation(value = TestingParallelAPSPConfigMXBean.NAME, osgiRegistrationType = TestingAPSP.class,
+namespace = "namespace", revision = "rev", localName = TestingParallelAPSPConfigMXBean.NAME)
public interface TestingParallelAPSPConfigMXBean {
static final String NAME = "apsp";
import javax.annotation.concurrent.ThreadSafe;
import javax.management.ObjectName;
+import java.util.Collections;
import java.util.HashSet;
import java.util.Set;
public Set<Module> getDefaultModules(DependencyResolverFactory dependencyResolverFactory, BundleContext context) {
return new HashSet<Module>();
}
+
+ @Override
+ public Set<Class<? extends AbstractServiceInterface>> getImplementedServiceIntefaces() {
+ return Collections.emptySet();
+ }
}
*/
package org.opendaylight.controller.config.manager.testingservices.parallelapsp.test;
-import javax.management.InstanceAlreadyExistsException;
-import javax.management.ObjectName;
-
-import org.opendaylight.controller.config.manager.impl.AbstractConfigWithJolokiaTest;
+import org.opendaylight.controller.config.manager.impl.AbstractConfigTest;
import org.opendaylight.controller.config.manager.testingservices.parallelapsp.TestingParallelAPSPConfigMXBean;
import org.opendaylight.controller.config.manager.testingservices.parallelapsp.TestingParallelAPSPModuleFactory;
import org.opendaylight.controller.config.manager.testingservices.threadpool.TestingFixedThreadPoolConfigMXBean;
import org.opendaylight.controller.config.util.ConfigTransactionJMXClient;
-abstract class AbstractParallelAPSPTest extends AbstractConfigWithJolokiaTest {
+import javax.management.InstanceAlreadyExistsException;
+import javax.management.ObjectName;
+
+abstract class AbstractParallelAPSPTest extends AbstractConfigTest {
protected final String fixed1 = "fixed1";
protected final String apsp1 = "apsp-parallel";
*/
package org.opendaylight.controller.config.manager.testingservices.parallelapsp.test;
-import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertThat;
-import static org.junit.Assert.assertTrue;
-import static org.junit.Assert.fail;
-import static org.junit.internal.matchers.StringContains.containsString;
-
-import java.util.Map;
-
-import javax.management.ObjectName;
-
-import org.json.simple.JSONObject;
import org.junit.After;
import org.junit.Before;
import org.junit.Test;
import org.opendaylight.controller.config.manager.testingservices.threadpool.TestingFixedThreadPoolConfigMXBean;
import org.opendaylight.controller.config.manager.testingservices.threadpool.TestingFixedThreadPoolModuleFactory;
import org.opendaylight.controller.config.util.ConfigTransactionJMXClient;
-import org.opendaylight.controller.config.util.jolokia.ConfigTransactionJolokiaClient;
+
+import javax.management.ObjectName;
+import java.util.Map;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertThat;
+import static org.junit.Assert.assertTrue;
+import static org.junit.Assert.fail;
+import static org.junit.internal.matchers.StringContains.containsString;
public class DependentWiringTest extends AbstractParallelAPSPTest {
private final String fixed1 = "fixed1";
parallelAPSPRuntimeProxy.getMaxNumberOfThreads());
}
-
- @Test
- public void testUsingJolokia() throws Exception {
-
- ConfigTransactionJolokiaClient transactionClient = configRegistryJolokiaClient
- .createTransaction();
- // fixed1
- ObjectName fixed1ON = transactionClient.createModule(
- getThreadPoolImplementationName(), fixed1);
- transactionClient.setAttribute(fixed1ON, "ThreadCount",
- TestingParallelAPSPImpl.MINIMAL_NUMBER_OF_THREADS);
-
- // apsp-parallel with syntetic attrib
- String threadPoolString = "ThreadPool";
- ObjectName apsp1ON = transactionClient.createModule(
- TestingParallelAPSPModuleFactory.NAME, apsp1);
- transactionClient.setAttribute(apsp1ON, threadPoolString, fixed1ON);
- // check
- assertEquals(ObjectNameUtil.withoutTransactionName(fixed1ON),
- transactionClient.getAttributeON(apsp1ON, threadPoolString));
- transactionClient.setAttribute(apsp1ON, "SomeParam", "ahoj");
-
- // commit
- transactionClient.commit();
- // check thread pool
- assertEquals(1, TestingFixedThreadPool.allExecutors.size());
- // check platform MBeanServer
- ObjectName apspReadOnlyON = ObjectNameUtil
- .withoutTransactionName(apsp1ON);
- JSONObject threadPoolONJson = (JSONObject) configRegistryJolokiaClient
- .getAttribute(apspReadOnlyON, threadPoolString);
- ObjectName fixed1ReadOnlyON = ObjectNameUtil
- .withoutTransactionName(fixed1ON);
- assertEquals(fixed1ReadOnlyON, ObjectNameUtil.createON(threadPoolONJson
- .get("objectName").toString()));
- assertEquals(fixed1ReadOnlyON,
- configRegistryJolokiaClient.getAttributeON(apspReadOnlyON,
- threadPoolString));
-
- }
}
*/
package org.opendaylight.controller.config.manager.testingservices.scheduledthreadpool;
+import com.google.common.collect.Sets;
import org.opendaylight.controller.config.api.DependencyResolver;
import org.opendaylight.controller.config.api.DependencyResolverFactory;
import org.opendaylight.controller.config.api.DynamicMBeanWithInstance;
import org.opendaylight.controller.config.spi.ModuleFactory;
import org.osgi.framework.BundleContext;
-import java.util.Arrays;
+import java.util.Collections;
import java.util.HashSet;
-import java.util.List;
import java.util.Set;
public class TestingScheduledThreadPoolModuleFactory implements ModuleFactory {
public static final String NAME = "scheduled";
- private static List<Class<? extends TestingThreadPoolServiceInterface>> ifc = Arrays
- .asList(TestingScheduledThreadPoolServiceInterface.class, TestingThreadPoolServiceInterface.class);
+ private static Set<Class<? extends AbstractServiceInterface>> ifc = Collections.unmodifiableSet(Sets.newHashSet(
+ (Class<? extends AbstractServiceInterface>) TestingScheduledThreadPoolServiceInterface.class,
+ TestingThreadPoolServiceInterface.class));
@Override
public boolean isModuleImplementingServiceInterface(
public Set<Module> getDefaultModules(DependencyResolverFactory dependencyResolverFactory, BundleContext bundleContext) {
return new HashSet<Module>();
}
+
+ @Override
+ public Set<Class<? extends AbstractServiceInterface>> getImplementedServiceIntefaces() {
+ return ifc;
+ }
+
+
}
import org.opendaylight.controller.config.api.annotations.ServiceInterfaceAnnotation;
import org.opendaylight.controller.config.manager.testingservices.threadpool.TestingModifiableThreadPoolIfc;
-@ServiceInterfaceAnnotation(value = "modifiable-threadpool", osgiRegistrationType = TestingModifiableThreadPoolIfc.class)
+@ServiceInterfaceAnnotation(value = "fqn:modifiable-threadpool", osgiRegistrationType = TestingModifiableThreadPoolIfc.class,
+ namespace = "foo", revision = "bar", localName = "modifiable-threadpool")
public interface ModifiableThreadPoolServiceInterface extends
TestingThreadPoolServiceInterface {
}
import org.opendaylight.controller.config.api.annotations.ServiceInterfaceAnnotation;
import org.opendaylight.controller.config.manager.testingservices.scheduledthreadpool.TestingScheduledThreadPoolIfc;
-@ServiceInterfaceAnnotation(value = "threadpool-scheduled", osgiRegistrationType = TestingScheduledThreadPoolIfc.class)
+@ServiceInterfaceAnnotation(value = "threadpool-scheduled", osgiRegistrationType = TestingScheduledThreadPoolIfc.class,
+ namespace = "ns", revision = "rev", localName = "threadpool-scheduled")
public interface TestingScheduledThreadPoolServiceInterface extends
TestingThreadPoolServiceInterface {
}
import org.opendaylight.controller.config.api.annotations.ServiceInterfaceAnnotation;
import org.opendaylight.controller.config.manager.testingservices.threadpool.TestingThreadPoolIfc;
-@ServiceInterfaceAnnotation(value = "testing-threadpool", osgiRegistrationType = TestingThreadPoolIfc.class)
+@ServiceInterfaceAnnotation(value = "testing-threadpool", osgiRegistrationType = TestingThreadPoolIfc.class,
+ namespace = "ns", revision = "foo", localName = "bar")
public interface TestingThreadPoolServiceInterface extends
AbstractServiceInterface {
}
*/
package org.opendaylight.controller.config.manager.testingservices.threadpool;
+import com.google.common.collect.Sets;
import org.opendaylight.controller.config.api.DependencyResolver;
import org.opendaylight.controller.config.api.DependencyResolverFactory;
import org.opendaylight.controller.config.api.DynamicMBeanWithInstance;
import org.opendaylight.controller.config.spi.ModuleFactory;
import org.osgi.framework.BundleContext;
-import java.util.Arrays;
+import java.util.Collections;
import java.util.HashSet;
-import java.util.List;
import java.util.Set;
public class TestingFixedThreadPoolModuleFactory implements ModuleFactory {
public static final String NAME = "fixed";
- private static List<Class<? extends TestingThreadPoolServiceInterface>> ifc = Arrays
- .asList(ModifiableThreadPoolServiceInterface.class, TestingThreadPoolServiceInterface.class);
+
+ private static Set<Class<? extends AbstractServiceInterface>> ifc = Collections.unmodifiableSet(Sets.newHashSet(
+ (Class<? extends AbstractServiceInterface>) ModifiableThreadPoolServiceInterface.class,
+ TestingThreadPoolServiceInterface.class));
@Override
public String getImplementationName() {
public Set<Module> getDefaultModules(DependencyResolverFactory dependencyResolverFactory, BundleContext bundleContext) {
return new HashSet<Module>();
}
+
+ @Override
+ public Set<Class<? extends AbstractServiceInterface>> getImplementedServiceIntefaces() {
+ return ifc;
+ }
}
*/
package org.opendaylight.controller.config.manager.testingservices.threadpool.test;
-import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertFalse;
-import static org.junit.Assert.assertNotNull;
-import static org.junit.Assert.assertThat;
-import static org.junit.Assert.assertTrue;
-import static org.junit.Assert.fail;
-import static org.junit.matchers.JUnitMatchers.containsString;
-
-import java.util.Arrays;
-import java.util.Collections;
-import java.util.List;
-import java.util.Map;
-import java.util.concurrent.ThreadPoolExecutor;
-
-import javax.management.DynamicMBean;
-import javax.management.InstanceAlreadyExistsException;
-import javax.management.InstanceNotFoundException;
-import javax.management.MBeanException;
-import javax.management.ObjectName;
-import javax.management.ReflectionException;
-import javax.management.RuntimeMBeanException;
-
import org.junit.After;
import org.junit.Before;
import org.junit.Test;
import org.opendaylight.controller.config.api.ValidationException.ExceptionMessageWithStackTrace;
import org.opendaylight.controller.config.api.jmx.CommitStatus;
import org.opendaylight.controller.config.api.jmx.ObjectNameUtil;
-import org.opendaylight.controller.config.manager.impl.AbstractConfigWithJolokiaTest;
+import org.opendaylight.controller.config.manager.impl.AbstractConfigTest;
import org.opendaylight.controller.config.manager.impl.factoriesresolver.HardcodedModuleFactoriesResolver;
import org.opendaylight.controller.config.manager.testingservices.threadpool.TestingFixedThreadPool;
import org.opendaylight.controller.config.manager.testingservices.threadpool.TestingFixedThreadPoolConfigMXBean;
import org.opendaylight.controller.config.manager.testingservices.threadpool.TestingFixedThreadPoolModuleFactory;
import org.opendaylight.controller.config.util.ConfigTransactionClient;
import org.opendaylight.controller.config.util.ConfigTransactionJMXClient;
-import org.opendaylight.controller.config.util.jolokia.ConfigTransactionJolokiaClient;
+
+import javax.management.DynamicMBean;
+import javax.management.InstanceAlreadyExistsException;
+import javax.management.InstanceNotFoundException;
+import javax.management.MBeanException;
+import javax.management.ObjectName;
+import javax.management.ReflectionException;
+import javax.management.RuntimeMBeanException;
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.List;
+import java.util.Map;
+import java.util.concurrent.ThreadPoolExecutor;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertTrue;
+import static org.junit.Assert.fail;
/**
* Tests basic functionality of configuration registry:
* Only one bean is being configured - {@link TestingThreadPoolIfc} which has no
* dependencies.
*/
-public class SimpleConfigurationTest extends AbstractConfigWithJolokiaTest {
+public class SimpleConfigurationTest extends AbstractConfigTest {
private final int numberOfThreads = 5;
private final int numberOfThreads2 = 10;
private static final String fixed1 = "fixed1";
testValidation(transaction);
}
- @Test
- public void testValidationUsingJolokiaClient() throws Exception {
- ConfigTransactionClient transaction = configRegistryJolokiaClient
- .createTransaction();
- testValidation(transaction);
- }
private void testValidation(ConfigTransactionClient transaction)
throws InstanceAlreadyExistsException, ReflectionException,
}
}
- @Test
- public void testOptimisticLock_ConfigTransactionJolokiaClient()
- throws Exception {
- ConfigTransactionJolokiaClient transaction1 = configRegistryJolokiaClient
- .createTransaction();
- ConfigTransactionJolokiaClient transaction2 = configRegistryJolokiaClient
- .createTransaction();
- transaction2.assertVersion(0, 2);
- transaction2.commit();
- try {
- transaction1.commit();
- fail();
- } catch (ConflictingVersionException e) {
- assertEquals(
- "Optimistic lock failed. Expected parent version 2, was 0",
- e.getMessage());
- }
- }
-
- @Test
- public void testOptimisticLock_ConfigRegistryJolokiaClient()
- throws Exception {
- ConfigTransactionJolokiaClient transaction1 = configRegistryJolokiaClient
- .createTransaction();
- ConfigTransactionJolokiaClient transaction2 = configRegistryJolokiaClient
- .createTransaction();
- transaction2.assertVersion(0, 2);
- transaction2.commit();
- try {
- configRegistryJolokiaClient.commitConfig(transaction1
- .getObjectName());
- fail();
- } catch (ConflictingVersionException e) {
- assertEquals(
- "Optimistic lock failed. Expected parent version 2, was 0",
- e.getMessage());
- }
- }
-
- @Test
- public void testUsingJolokia() throws Exception {
- ConfigTransactionJolokiaClient transactionClient = configRegistryJolokiaClient
- .createTransaction();
-
- ObjectName name = transactionClient.createModule(
- TestingFixedThreadPoolModuleFactory.NAME, fixed1);
-
- try {
- transactionClient.validateConfig();
- fail();
- } catch (ValidationException e) {
- assertThat(
- e.getMessage(),
- containsString("Parameter 'threadCount' must be greater than 0"));
- }
-
- transactionClient.setAttribute(name, "ThreadCount", numberOfThreads);
- // commit
- CommitStatus commitStatus = transactionClient.commit();
- CommitStatus expected = new CommitStatus(Arrays.asList(ObjectNameUtil
- .withoutTransactionName(name)), emptyONs, emptyONs);
- assertEquals(expected, commitStatus);
- }
}
<groupId>${project.groupId}</groupId>
<artifactId>config-api</artifactId>
</dependency>
- <dependency>
- <groupId>org.jolokia</groupId>
- <artifactId>jolokia-client-java</artifactId>
- </dependency>
- <dependency>
- <groupId>org.jolokia</groupId>
- <artifactId>jolokia-jvm</artifactId>
- <classifier>agent</classifier>
- </dependency>
-
<!-- test dependencies -->
<dependency>
<groupId>com.google.guava</groupId>
import java.util.Arrays;
import java.util.List;
+import java.util.Map;
import java.util.Set;
import javax.management.AttributeNotFoundException;
import org.opendaylight.controller.config.api.jmx.ObjectNameUtil;
public class ConfigRegistryJMXClient implements ConfigRegistryClient {
- private final ConfigRegistryMXBean configRegistryProxy;
+ private final ConfigRegistryMXBean configRegistryMXBeanProxy;
private final ObjectName configRegistryON;
private final MBeanServer configMBeanServer;
if (!(searchResult.size() == 1)) {
throw new IllegalStateException("Config registry not found");
}
- configRegistryProxy = JMX.newMXBeanProxy(configMBeanServer, configRegistryON, ConfigRegistryMXBean.class,
+ configRegistryMXBeanProxy = JMX.newMXBeanProxy(configMBeanServer, configRegistryON, ConfigRegistryMXBean.class,
false);
}
@Override
public ConfigTransactionJMXClient getConfigTransactionClient(
ObjectName objectName) {
- return new ConfigTransactionJMXClient(configRegistryProxy, objectName,
+ return new ConfigTransactionJMXClient(configRegistryMXBeanProxy, objectName,
configMBeanServer);
}
@Override
public ObjectName beginConfig() {
- return configRegistryProxy.beginConfig();
+ return configRegistryMXBeanProxy.beginConfig();
}
@Override
public CommitStatus commitConfig(ObjectName transactionControllerON)
throws ConflictingVersionException, ValidationException {
- return configRegistryProxy.commitConfig(transactionControllerON);
+ return configRegistryMXBeanProxy.commitConfig(transactionControllerON);
}
@Override
public List<ObjectName> getOpenConfigs() {
- return configRegistryProxy.getOpenConfigs();
+ return configRegistryMXBeanProxy.getOpenConfigs();
}
@Override
@Override
public Set<String> getAvailableModuleNames() {
- return configRegistryProxy.getAvailableModuleNames();
+ return configRegistryMXBeanProxy.getAvailableModuleNames();
}
@Override
public boolean isHealthy() {
- return configRegistryProxy.isHealthy();
+ return configRegistryMXBeanProxy.isHealthy();
}
@Override
public Set<ObjectName> lookupConfigBeans() {
- return configRegistryProxy.lookupConfigBeans();
+ return configRegistryMXBeanProxy.lookupConfigBeans();
}
@Override
public Set<ObjectName> lookupConfigBeans(String moduleName) {
- return configRegistryProxy.lookupConfigBeans(moduleName);
+ return configRegistryMXBeanProxy.lookupConfigBeans(moduleName);
}
@Override
public Set<ObjectName> lookupConfigBeans(String moduleName,
String instanceName) {
- return configRegistryProxy.lookupConfigBeans(moduleName, instanceName);
+ return configRegistryMXBeanProxy.lookupConfigBeans(moduleName, instanceName);
}
@Override
public ObjectName lookupConfigBean(String moduleName, String instanceName)
throws InstanceNotFoundException {
- return configRegistryProxy.lookupConfigBean(moduleName, instanceName);
+ return configRegistryMXBeanProxy.lookupConfigBean(moduleName, instanceName);
}
@Override
public Set<ObjectName> lookupRuntimeBeans() {
- return configRegistryProxy.lookupRuntimeBeans();
+ return configRegistryMXBeanProxy.lookupRuntimeBeans();
}
@Override
public Set<ObjectName> lookupRuntimeBeans(String ifcName,
String instanceName) {
- return configRegistryProxy.lookupRuntimeBeans(ifcName, instanceName);
+ return configRegistryMXBeanProxy.lookupRuntimeBeans(ifcName, instanceName);
+ }
+
+ @Override
+ public void checkConfigBeanExists(ObjectName objectName) throws InstanceNotFoundException {
+ configRegistryMXBeanProxy.checkConfigBeanExists(objectName);
+ }
+
+ @Override
+ public ObjectName lookupConfigBeanByServiceInterfaceName(String serviceInterfaceName, String refName) {
+ return configRegistryMXBeanProxy.lookupConfigBeanByServiceInterfaceName(serviceInterfaceName, refName);
+ }
+
+ @Override
+ public Map<String, Map<String, ObjectName>> getServiceMapping() {
+ return configRegistryMXBeanProxy.getServiceMapping();
+ }
+
+ @Override
+ public Map<String, ObjectName> lookupServiceReferencesByServiceInterfaceName(String serviceInterfaceName) {
+ return configRegistryMXBeanProxy.lookupServiceReferencesByServiceInterfaceName(serviceInterfaceName);
+ }
+
+ @Override
+ public Set<String> lookupServiceInterfaceNames(ObjectName objectName) throws InstanceNotFoundException {
+ return configRegistryMXBeanProxy.lookupServiceInterfaceNames(objectName);
+ }
+
+ @Override
+ public String getServiceInterfaceName(String namespace, String localName) {
+ return configRegistryMXBeanProxy.getServiceInterfaceName(namespace, localName);
}
@Override
*/
package org.opendaylight.controller.config.util;
+import java.util.Map;
import java.util.Set;
import javax.management.Attribute;
import org.opendaylight.controller.config.api.jmx.ObjectNameUtil;
public class ConfigTransactionJMXClient implements ConfigTransactionClient {
- private final ConfigRegistryMXBean configTransactionManagerProxy;
+ private final ConfigRegistryMXBean configRegistryMXBeanProxy;
private final ObjectName configTransactionControllerON;
- private final ConfigTransactionControllerMXBean configControllerProxy;
+ private final ConfigTransactionControllerMXBean configTransactionControllerMXBeanProxy;
private final MBeanServer configMBeanServer;
public ConfigTransactionJMXClient(
- ConfigRegistryMXBean configTransactionManagerProxy,
+ ConfigRegistryMXBean configRegistryMXBeanProxy,
ObjectName configTransactionControllerON,
MBeanServer configMBeanServer) {
this.configMBeanServer = configMBeanServer;
- this.configTransactionManagerProxy = configTransactionManagerProxy;
+ this.configRegistryMXBeanProxy = configRegistryMXBeanProxy;
this.configTransactionControllerON = configTransactionControllerON;
- this.configControllerProxy = JMX.newMXBeanProxy(configMBeanServer,
+ this.configTransactionControllerMXBeanProxy = JMX.newMXBeanProxy(configMBeanServer,
configTransactionControllerON,
ConfigTransactionControllerMXBean.class);
}
@Override
public CommitStatus commit() throws ConflictingVersionException,
ValidationException {
- return configTransactionManagerProxy
+ return configRegistryMXBeanProxy
.commitConfig(configTransactionControllerON);
}
@Override
public ObjectName createModule(String moduleName, String instanceName)
throws InstanceAlreadyExistsException {
- return configControllerProxy.createModule(moduleName, instanceName);
+ return configTransactionControllerMXBeanProxy.createModule(moduleName, instanceName);
}
@Override
public void destroyModule(ObjectName objectName)
throws InstanceNotFoundException {
- configControllerProxy.destroyModule(objectName);
+ configTransactionControllerMXBeanProxy.destroyModule(objectName);
}
@Override
@Override
public void abortConfig() {
- configControllerProxy.abortConfig();
+ configTransactionControllerMXBeanProxy.abortConfig();
}
@Override
public void validateConfig() throws ValidationException {
- configControllerProxy.validateConfig();
+ configTransactionControllerMXBeanProxy.validateConfig();
}
@Override
@Override
public String getTransactionName() {
- return configControllerProxy.getTransactionName();
+ return configTransactionControllerMXBeanProxy.getTransactionName();
}
@Override
public Set<String> getAvailableModuleNames() {
- return configControllerProxy.getAvailableModuleNames();
+ return configTransactionControllerMXBeanProxy.getAvailableModuleNames();
}
@Override
@Override
public Set<ObjectName> lookupConfigBeans() {
- return configControllerProxy.lookupConfigBeans();
+ return configTransactionControllerMXBeanProxy.lookupConfigBeans();
}
@Override
public Set<ObjectName> lookupConfigBeans(String moduleName) {
- return configControllerProxy.lookupConfigBeans(moduleName);
+ return configTransactionControllerMXBeanProxy.lookupConfigBeans(moduleName);
}
@Override
public ObjectName lookupConfigBean(String moduleName, String instanceName)
throws InstanceNotFoundException {
- return configControllerProxy.lookupConfigBean(moduleName, instanceName);
+ return configTransactionControllerMXBeanProxy.lookupConfigBean(moduleName, instanceName);
}
@Override
public Set<ObjectName> lookupConfigBeans(String moduleName,
String instanceName) {
- return configControllerProxy
+ return configTransactionControllerMXBeanProxy
.lookupConfigBeans(moduleName, instanceName);
}
+ @Override
+ public void checkConfigBeanExists(ObjectName objectName) throws InstanceNotFoundException {
+ configTransactionControllerMXBeanProxy.checkConfigBeanExists(objectName);
+ }
+
+ @Override
+ public void saveServiceReference(String serviceInterfaceName, String refName, ObjectName objectName) throws InstanceNotFoundException {
+ configTransactionControllerMXBeanProxy.saveServiceReference(serviceInterfaceName,refName,objectName);
+ }
+
+ @Override
+ public boolean removeServiceReference(String serviceInterfaceName, String refName) {
+ return configTransactionControllerMXBeanProxy.removeServiceReference(serviceInterfaceName, refName);
+ }
+
+ @Override
+ public void removeAllServiceReferences() {
+ configTransactionControllerMXBeanProxy.removeAllServiceReferences();
+ }
+
+ @Override
+ public ObjectName lookupConfigBeanByServiceInterfaceName(String serviceInterfaceName, String refName) {
+ return configTransactionControllerMXBeanProxy.lookupConfigBeanByServiceInterfaceName(serviceInterfaceName, refName);
+ }
+
+ @Override
+ public Map<String, Map<String, ObjectName>> getServiceMapping() {
+ return configTransactionControllerMXBeanProxy.getServiceMapping();
+ }
+
+ @Override
+ public Map<String, ObjectName> lookupServiceReferencesByServiceInterfaceName(String serviceInterfaceName) {
+ return configTransactionControllerMXBeanProxy.lookupServiceReferencesByServiceInterfaceName(serviceInterfaceName);
+ }
+
+ @Override
+ public Set<String> lookupServiceInterfaceNames(ObjectName objectName) throws InstanceNotFoundException {
+ return configTransactionControllerMXBeanProxy.lookupServiceInterfaceNames(objectName);
+ }
+
+ @Override
+ public String getServiceInterfaceName(String namespace, String localName) {
+ return configTransactionControllerMXBeanProxy.getServiceInterfaceName(namespace, localName);
+ }
+
+ @Override
+ public boolean removeServiceReferences(ObjectName objectName) throws InstanceNotFoundException {
+ return configTransactionControllerMXBeanProxy.removeServiceReferences(objectName);
+ }
+
@Override
public void validateBean(ObjectName configBeanON)
throws ValidationException {
+++ /dev/null
-/*
- * Copyright (c) 2013 Cisco Systems, Inc. and others. All rights reserved.
- *
- * This program and the accompanying materials are made available under the
- * terms of the Eclipse Public License v1.0 which accompanies this distribution,
- * and is available at http://www.eclipse.org/legal/epl-v10.html
- */
-package org.opendaylight.controller.config.util.jolokia;
-
-import java.util.List;
-import java.util.Set;
-
-import javax.management.ObjectName;
-
-import org.jolokia.client.request.J4pExecRequest;
-import org.jolokia.client.request.J4pReadRequest;
-import org.jolokia.client.request.J4pResponse;
-import org.json.simple.JSONArray;
-import org.json.simple.JSONObject;
-import org.opendaylight.controller.config.api.ConflictingVersionException;
-import org.opendaylight.controller.config.api.ValidationException;
-import org.opendaylight.controller.config.api.jmx.CommitStatus;
-import org.opendaylight.controller.config.api.jmx.ConfigRegistryMXBean;
-import org.opendaylight.controller.config.api.jmx.ObjectNameUtil;
-import org.opendaylight.controller.config.util.ConfigRegistryClient;
-
-public class ConfigRegistryJolokiaClient extends ListableJolokiaClient
- implements ConfigRegistryClient {
-
- public ConfigRegistryJolokiaClient(String url) {
- super(url, ConfigRegistryMXBean.OBJECT_NAME);
- }
-
- @Override
- public ConfigTransactionJolokiaClient createTransaction() {
- // create transaction
- J4pExecRequest execReq = new J4pExecRequest(objectName, "beginConfig");
- J4pResponse<J4pExecRequest> resp = execute(execReq);
- ObjectName transactionControllerON = extractObjectName(resp);
- return getConfigTransactionClient(transactionControllerON);
- }
-
- @Override
- public ConfigTransactionJolokiaClient getConfigTransactionClient(
- String transactionName) {
- ObjectName objectName = ObjectNameUtil
- .createTransactionControllerON(transactionName);
- return getConfigTransactionClient(objectName);
- }
-
- @Override
- public ConfigTransactionJolokiaClient getConfigTransactionClient(
- ObjectName objectName) {
- return new ConfigTransactionJolokiaClient(url, objectName, this);
- }
-
- @Override
- public CommitStatus commitConfig(ObjectName transactionControllerON)
- throws ConflictingVersionException, ValidationException {
- J4pExecRequest execReq = new J4pExecRequest(objectName, "commitConfig",
- transactionControllerON);
- JSONObject jsonObject;
- jsonObject = execute(execReq).getValue();
- JSONArray newInstancesArray = (JSONArray) jsonObject
- .get("newInstances");
- List<ObjectName> newInstances = jsonArrayToObjectNames(newInstancesArray);
- JSONArray reusedInstancesArray = (JSONArray) jsonObject
- .get("reusedInstances");
- List<ObjectName> reusedInstances = jsonArrayToObjectNames(reusedInstancesArray);
- JSONArray recreatedInstancesArray = (JSONArray) jsonObject
- .get("recreatedInstances");
- List<ObjectName> recreatedInstances = jsonArrayToObjectNames(recreatedInstancesArray);
- return new CommitStatus(newInstances, reusedInstances,
- recreatedInstances);
- }
-
- public Object getAttribute(ObjectName configBeanTransactionON, String key) {
- J4pReadRequest req = new J4pReadRequest(configBeanTransactionON, key);
- return execute(req).getValue();
- }
-
- public ObjectName getAttributeON(ObjectName configBeanTransactionON,
- String key) {
- JSONObject jsonAttrib = (JSONObject) getAttribute(
- configBeanTransactionON, key);
- return extractObjectName(jsonAttrib);
- }
-
- // proxy around ConfigTransactionManagerMXBean
-
- @Override
- public ObjectName beginConfig() {
- ConfigTransactionJolokiaClient result = createTransaction();
- return result.getTransactionON();
- }
-
- @Override
- public List<ObjectName> getOpenConfigs() {
- J4pReadRequest req = new J4pReadRequest(objectName, "OpenConfigs");
- JSONArray jsonArray = execute(req).getValue();
- return jsonArrayToObjectNames(jsonArray);
- }
-
- @Override
- public long getVersion() {
- J4pReadRequest req = new J4pReadRequest(objectName, "Version");
- return (Long) execute(req).getValue();
- }
-
- @Override
- public boolean isHealthy() {
- J4pReadRequest req = new J4pReadRequest(objectName, "Healthy");
- return (Boolean) execute(req).getValue();
- }
-
- @Override
- public Set<ObjectName> lookupRuntimeBeans() {
- return lookupSomething("lookupRuntimeBeans()", new Object[0]);
- }
-
- @Override
- public Set<ObjectName> lookupRuntimeBeans(String moduleName,
- String instanceName) {
- return lookupSomething(
- "lookupRuntimeBeans(java.lang.String,java.lang.String)",
- new Object[] { moduleName, instanceName });
- }
-
- @Override
- public Object invokeMethod(ObjectName on, String name, Object[] params,
- String[] signature) {
- throw new UnsupportedOperationException();
- }
-
- @Override
- public Object getAttributeCurrentValue(ObjectName on, String attributeName) {
- throw new UnsupportedOperationException();
- }
-}
+++ /dev/null
-/*
- * Copyright (c) 2013 Cisco Systems, Inc. and others. All rights reserved.
- *
- * This program and the accompanying materials are made available under the
- * terms of the Eclipse Public License v1.0 which accompanies this distribution,
- * and is available at http://www.eclipse.org/legal/epl-v10.html
- */
-package org.opendaylight.controller.config.util.jolokia;
-
-import java.util.Map;
-
-import javax.management.Attribute;
-import javax.management.AttributeNotFoundException;
-import javax.management.InstanceAlreadyExistsException;
-import javax.management.InstanceNotFoundException;
-import javax.management.ObjectName;
-
-import org.jolokia.client.request.J4pExecRequest;
-import org.jolokia.client.request.J4pReadRequest;
-import org.jolokia.client.request.J4pWriteRequest;
-import org.opendaylight.controller.config.api.ConflictingVersionException;
-import org.opendaylight.controller.config.api.ValidationException;
-import org.opendaylight.controller.config.api.jmx.CommitStatus;
-import org.opendaylight.controller.config.api.jmx.ObjectNameUtil;
-import org.opendaylight.controller.config.util.AttributeEntry;
-import org.opendaylight.controller.config.util.ConfigTransactionClient;
-
-public class ConfigTransactionJolokiaClient extends ListableJolokiaClient
- implements ConfigTransactionClient {
-
- private final ConfigRegistryJolokiaClient configRegistryJolokiaClient;
-
- public ConfigTransactionJolokiaClient(String url,
- ObjectName transactionControllerON,
- ConfigRegistryJolokiaClient configRegistryJolokiaClient) {
- super(url, transactionControllerON);
- this.configRegistryJolokiaClient = configRegistryJolokiaClient;
- }
-
- public ObjectName getTransactionON() {
- return objectName;
- }
-
- @Override
- public CommitStatus commit() throws ConflictingVersionException,
- ValidationException {
- return configRegistryJolokiaClient.commitConfig(objectName);
- }
-
- @Override
- public ObjectName createModule(String moduleName, String instanceName)
- throws InstanceAlreadyExistsException {
- J4pExecRequest execReq = new J4pExecRequest(objectName, "createModule",
- moduleName, instanceName);
- try {
- return extractObjectName(execute(execReq));
- } catch (RuntimeException e) {
- if (e.getMessage() != null
- && e.getMessage().startsWith(
- InstanceAlreadyExistsException.class.getName()))
- throw new InstanceAlreadyExistsException();
- throw e;
- }
- }
-
- @Override
- public void destroyModule(ObjectName configBeanON) {
- J4pExecRequest execReq = new J4pExecRequest(objectName,
- "destroyModule(javax.management.ObjectName)", configBeanON);
- execute(execReq);
- }
-
- @Override
- public void destroyConfigBean(String moduleName, String instanceName)
- throws InstanceNotFoundException {
- destroyModule(ObjectNameUtil.createTransactionModuleON(
- getTransactionName(), moduleName, instanceName));
- }
-
- @Override
- public void abortConfig() {
- J4pExecRequest execReq = new J4pExecRequest(objectName, "abortConfig");
- execute(execReq);
- }
-
- @Override
- public void validateConfig() throws ValidationException {
- J4pExecRequest execReq = new J4pExecRequest(objectName,
- "validateConfig");
- execute(execReq);
- }
-
- @Override
- public long getParentVersion() {
- J4pReadRequest req = new J4pReadRequest(objectName, "ParentVersion");
- return (Long) execute(req).getValue();
- }
-
- @Override
- public long getVersion() {
- J4pReadRequest req = new J4pReadRequest(objectName, "Version");
- return (Long) execute(req).getValue();
- }
-
- public void setAttribute(ObjectName configBeanTransactionON, String key,
- Object value) {
- J4pWriteRequest req = new J4pWriteRequest(configBeanTransactionON, key,
- value);
- try {
- execute(req);
- } catch (RuntimeException e) {
- if (e.getMessage() != null
- && e.getMessage().startsWith(
- AttributeNotFoundException.class.getName())) {
- // try to fix wrong case
- Map<String, AttributeEntry> allAttributes = getAttributes(configBeanTransactionON);
- for (AttributeEntry attrib : allAttributes.values()) {
- if (attrib.getKey().equalsIgnoreCase(key)) {
- req = new J4pWriteRequest(configBeanTransactionON,
- attrib.getKey(), value);
- execute(req);
- return;
- }
- }
- }
- throw e;
- }
- }
-
- public Object getAttribute(ObjectName objectName, String key) {
- return configRegistryJolokiaClient.getAttribute(objectName, key);
- }
-
- public ObjectName getAttributeON(ObjectName objectName, String key) {
- return configRegistryJolokiaClient.getAttributeON(objectName, key);
- }
-
- @Override
- public String getTransactionName() {
- return ObjectNameUtil.getTransactionName(objectName);
- }
-
- @Override
- public void validateBean(ObjectName rwON) throws ValidationException {
- J4pExecRequest req = new J4pExecRequest(rwON, "validate", new Object[0]);
- execute(req);
- }
-
- @Override
- public void assertVersion(int expectedParentVersion,
- int expectedCurrentVersion) {
- if (expectedParentVersion != getParentVersion()) {
- throw new IllegalStateException();
- }
- if (expectedCurrentVersion != getVersion()) {
- throw new IllegalStateException();
- }
- }
-
- @Override
- public void setAttribute(ObjectName on, String jmxName, Attribute attribute) {
- throw new UnsupportedOperationException();
- }
-
-}
+++ /dev/null
-/*
- * Copyright (c) 2013 Cisco Systems, Inc. and others. All rights reserved.
- *
- * This program and the accompanying materials are made available under the
- * terms of the Eclipse Public License v1.0 which accompanies this distribution,
- * and is available at http://www.eclipse.org/legal/epl-v10.html
- */
-package org.opendaylight.controller.config.util.jolokia;
-
-import java.util.ArrayList;
-import java.util.Arrays;
-import java.util.Collections;
-import java.util.HashMap;
-import java.util.HashSet;
-import java.util.List;
-import java.util.Map;
-import java.util.Map.Entry;
-import java.util.Set;
-import java.util.regex.Pattern;
-
-import javax.management.InstanceNotFoundException;
-import javax.management.MalformedObjectNameException;
-import javax.management.ObjectName;
-
-import org.jolokia.client.J4pClient;
-import org.jolokia.client.exception.J4pException;
-import org.jolokia.client.exception.J4pRemoteException;
-import org.jolokia.client.request.J4pExecRequest;
-import org.jolokia.client.request.J4pListRequest;
-import org.jolokia.client.request.J4pQueryParameter;
-import org.jolokia.client.request.J4pReadRequest;
-import org.jolokia.client.request.J4pRequest;
-import org.jolokia.client.request.J4pResponse;
-import org.json.simple.JSONArray;
-import org.json.simple.JSONObject;
-import org.opendaylight.controller.config.api.ConflictingVersionException;
-import org.opendaylight.controller.config.api.ValidationException;
-import org.opendaylight.controller.config.api.ValidationException.ExceptionMessageWithStackTrace;
-import org.opendaylight.controller.config.api.jmx.ObjectNameUtil;
-import org.opendaylight.controller.config.util.AttributeEntry;
-
-abstract class ListableJolokiaClient {
- protected final J4pClient j4pClient;
- protected final String url;
- protected final ObjectName objectName;
-
- public ListableJolokiaClient(String url, ObjectName objectName) {
- if (url == null) {
- throw new NullPointerException("Parameter 'url' is null");
- }
- if (!url.endsWith("/")) {
- throw new IllegalArgumentException(
- "Parameter 'url' must end with '/'");
- }
-
- this.url = url;
- this.j4pClient = new J4pClient(url);
- this.objectName = objectName;
- }
-
- public ObjectName getObjectName() {
- return objectName;
- }
-
- protected <R extends J4pResponse<T>, T extends J4pRequest> R execute(
- T pRequest) {
- try {
- Map<J4pQueryParameter, String> pProcessingOptions = new HashMap<J4pQueryParameter, String>();
- pProcessingOptions
- .put(J4pQueryParameter.INCLUDE_STACKTRACE, "true");
- pProcessingOptions.put(J4pQueryParameter.SERIALIZE_EXCEPTION,
- "true");
- return j4pClient.execute(pRequest, "POST", pProcessingOptions);
- } catch (J4pRemoteException e) {
- tryToConvertException(e.getRemoteStackTrace(), e.getErrorValue());
- throw new RuntimeException(e.getRemoteStackTrace(), e);
- } catch (J4pException e) {
- throw new RuntimeException(e);
- }
- }
-
- protected void tryToConvertException(String remoteStackTrace,
- JSONObject errorValue) {
- String conflictPrefix = ConflictingVersionException.class.getName()
- + ": ";
- if (remoteStackTrace.startsWith(conflictPrefix)) {
- remoteStackTrace = remoteStackTrace.substring(conflictPrefix
- .length());
- Pattern p = Pattern.compile("\r?\n");
- remoteStackTrace = Arrays.asList(p.split(remoteStackTrace))
- .iterator().next();
- throw new ConflictingVersionException(remoteStackTrace);
- }
- String validationExceptionPrefix = ValidationException.class.getName();
- if (remoteStackTrace.startsWith(validationExceptionPrefix)) {
- throw createValidationExceptionFromJSONObject(errorValue);
- }
- }
-
- static ValidationException createValidationExceptionFromJSONObject(
- JSONObject errorValue) {
- String fValsKey = "failedValidations";
- JSONObject failedVals = (JSONObject) errorValue.get(fValsKey);
-
- checkArgument(
- !failedVals.isEmpty(),
- fValsKey + " was not present in received JSON: "
- + errorValue.toJSONString());
- Map<String, Map<String, ExceptionMessageWithStackTrace>> failedValsMap = new HashMap<String, Map<String, ExceptionMessageWithStackTrace>>();
-
- for (Object key : failedVals.keySet()) {
- checkArgument(key instanceof String, "Unexpected key " + key
- + ", expected instance of String");
- Map<String, ExceptionMessageWithStackTrace> innerMap = new HashMap<String, ValidationException.ExceptionMessageWithStackTrace>();
- for (Object innerKey : ((JSONObject) failedVals.get(key)).keySet()) {
- checkArgument(innerKey instanceof String, "Unexpected key "
- + innerKey + ", expected instance of String");
- JSONObject exWithStackTraceVal = (JSONObject) (((JSONObject) failedVals
- .get(key)).get(innerKey));
- Object mess = exWithStackTraceVal.get("message");
- Object stack = exWithStackTraceVal.get("trace");
- checkArgument(mess != null && stack != null,
- "\"Message\" and \"trace\" elements expected in received json: "
- + errorValue.toJSONString());
- innerMap.put(innerKey.toString(),
- new ExceptionMessageWithStackTrace((String) mess,
- (String) stack));
- }
- failedValsMap.put((String) key, innerMap);
- }
- return new ValidationException(failedValsMap);
- }
-
- private static void checkArgument(boolean b, String string) {
- if (b == false)
- throw new IllegalArgumentException(string);
- }
-
- public String getUrl() {
- return url;
- }
-
- public Map<String, AttributeEntry> getAttributes(ObjectName on) {
- J4pListRequest req = new J4pListRequest(on);
- J4pResponse<J4pListRequest> response = execute(req);
- JSONObject listJSONResponse = response.getValue();
- JSONObject attributes = (JSONObject) listJSONResponse.get("attr");
-
- // Empty attributes list
- if(attributes == null)
- return Collections.emptyMap();
-
- Map<String, JSONObject> listMap = new HashMap<>();
-
- for (Object entryObject : attributes.entrySet()) {
- Entry<String, Object> entry = (Entry<String, Object>) entryObject;
- JSONObject entryVal = (JSONObject) entry.getValue();
-
- // read value
- listMap.put(entry.getKey(), entryVal);
- }
- J4pReadRequest j4pReadRequest = new J4pReadRequest(on, listMap.keySet()
- .toArray(new String[0]));
- J4pResponse<J4pReadRequest> readResponse = execute(j4pReadRequest);
- Object readResponseValue = readResponse.getValue();
- // readResponseValue can be String if there is just one attribute or
- // JSONObject
- Map<String, Object> attribsToValues = new HashMap<String, Object>();
- if (readResponseValue instanceof JSONObject) {
- JSONObject readJSONResponse = (JSONObject) readResponseValue;
- for (Object entryObject : readJSONResponse.entrySet()) {
- Entry<String, Object> entry = (Entry<String, Object>) entryObject;
- String key = entry.getKey();
- Object value = entry.getValue();
- attribsToValues.put(key, value);
- }
- }
-
- Map<String, AttributeEntry> resultMap = new HashMap<String, AttributeEntry>();
- for (Entry<String, JSONObject> entry : listMap.entrySet()) {
- String key = entry.getKey();
- Object value = attribsToValues.size() > 0 ? attribsToValues
- .get(key) : readResponseValue;
- JSONObject listJSON = entry.getValue();
- String description = (String) listJSON.get("desc");
- String type = (String) listJSON.get("type");
- boolean rw = (Boolean) listJSON.get("rw");
- AttributeEntry attributeEntry = new AttributeEntry(key,
- description, value, type, rw);
- resultMap.put(key, attributeEntry);
- }
-
- return resultMap;
- }
-
- public String getConfigBeanDescripton(ObjectName on) {
- J4pListRequest req = new J4pListRequest(on);
- J4pResponse<J4pListRequest> response = execute(req);
- JSONObject jsonDesc = response.getValue();
- Object description = jsonDesc.get("desc");
- return description == null ? null : description.toString();
- }
-
- protected List<ObjectName> jsonArrayToObjectNames(JSONArray jsonArray) {
- List<ObjectName> result = new ArrayList<>(jsonArray.size());
- for (Object entry : jsonArray) {
- JSONObject jsonObject = (JSONObject) entry;
- String objectNameString = (String) jsonObject.get("objectName");
- try {
- result.add(new ObjectName(objectNameString));
- } catch (MalformedObjectNameException e) {
- throw new IllegalStateException("Cannot convert "
- + objectNameString + " to ObjectName", e);
- }
- }
- return result;
- }
-
- protected ObjectName extractObjectName(J4pResponse<J4pExecRequest> resp) {
- JSONObject jsonResponse = resp.getValue();
- return extractObjectName(jsonResponse);
- }
-
- protected ObjectName extractObjectName(JSONObject jsonResponse) {
- String result = jsonResponse.get("objectName").toString();
- return ObjectNameUtil.createON(result);
- }
-
- protected Set<ObjectName> lookupSomething(String signature,
- Object[] parameters) {
- J4pExecRequest req = new J4pExecRequest(objectName, signature,
- parameters);
- JSONArray jsonArray = execute(req).getValue();
- return new HashSet<>(jsonArrayToObjectNames(jsonArray));
- }
-
- public Set<ObjectName> lookupConfigBeans() {
- return lookupSomething("lookupConfigBeans()", new Object[0]);
- }
-
- public Set<ObjectName> lookupConfigBeans(String ifcName) {
- return lookupSomething("lookupConfigBeans(java.lang.String)",
- new Object[] { ifcName });
- }
-
- public Set<ObjectName> lookupConfigBeans(String ifcName, String instanceName) {
- return lookupSomething(
- "lookupConfigBeans(java.lang.String,java.lang.String)",
- new Object[] { ifcName, instanceName });
- }
-
- public ObjectName lookupConfigBean(String ifcName, String instanceName)
- throws InstanceNotFoundException {
- J4pExecRequest req = new J4pExecRequest(objectName,
- "lookupConfigBean(java.lang.String,java.lang.String)",
- new Object[] { ifcName, instanceName });
- try {
- J4pResponse<J4pExecRequest> resp = execute(req);
- return extractObjectName(resp);
- } catch (RuntimeException e) {
- if (e.getMessage() != null
- && e.getMessage().startsWith(
- InstanceNotFoundException.class.getName()))
- throw new InstanceNotFoundException();
- throw e;
- }
- }
-
- public Set<String> getAvailableModuleNames() {
- J4pReadRequest req = new J4pReadRequest(objectName,
- "AvailableModuleNames");
- List<String> value = execute(req).getValue();
- return new HashSet<>(value);
- }
-}
*/
package org.opendaylight.controller.config.util;
-import static org.hamcrest.core.Is.is;
-import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertThat;
-import static org.junit.Assert.fail;
-import static org.junit.matchers.JUnitMatchers.containsString;
-
-import java.lang.management.ManagementFactory;
-import java.util.Set;
+import com.google.common.collect.Sets;
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Test;
+import org.opendaylight.controller.config.api.ConfigRegistry;
import javax.management.InstanceNotFoundException;
import javax.management.MBeanServer;
import javax.management.ObjectName;
+import java.lang.management.ManagementFactory;
+import java.util.Set;
-import org.junit.After;
-import org.junit.Before;
-import org.junit.Test;
-import org.opendaylight.controller.config.api.ConfigRegistry;
-import org.opendaylight.controller.config.api.ValidationException;
-import org.opendaylight.controller.config.util.jolokia.ConfigRegistryJolokiaClient;
+import static org.junit.Assert.assertEquals;
public class ConfigRegistryClientsTest {
- private String jolokiaURL;
-
private TestingConfigRegistry testingRegistry;
private ObjectName testingRegistryON;
private final MBeanServer mbs = ManagementFactory.getPlatformMBeanServer();
- private ConfigRegistryClient jmxRegistryClient, jolokiaRegistryClient;
+ private ConfigRegistryClient jmxRegistryClient;
@Before
public void setUp() throws Exception {
- jolokiaURL = JolokiaHelper.startTestingJolokia();
testingRegistry = new TestingConfigRegistry();
testingRegistryON = ConfigRegistry.OBJECT_NAME;
mbs.registerMBean(testingRegistry, testingRegistryON);
jmxRegistryClient = new ConfigRegistryJMXClient(
ManagementFactory.getPlatformMBeanServer());
- jolokiaRegistryClient = new ConfigRegistryJolokiaClient(jolokiaURL);
}
@After
public void cleanUp() throws Exception {
- JolokiaHelper.stopJolokia();
if (testingRegistryON != null) {
mbs.unregisterMBean(testingRegistryON);
}
@Test
public void testLookupRuntimeBeans() throws Exception {
Set<ObjectName> jmxLookup = lookupRuntimeBeans(jmxRegistryClient);
- Set<ObjectName> jolokiaLookup = lookupRuntimeBeans(jolokiaRegistryClient);
- assertEquals(jmxLookup, jolokiaLookup);
+ assertEquals(Sets.newHashSet(testingRegistry.run2, testingRegistry.run1, testingRegistry.run3), jmxLookup);
}
private Set<ObjectName> lookupRuntimeBeans(ConfigRegistryClient client)
jmxRegistryClient, TestingConfigRegistry.moduleName1,
TestingConfigRegistry.instName1);
assertEquals(1, jmxLookup.size());
- Set<ObjectName> jolokiaLookup = clientLookupRuntimeBeansWithModuleAndInstance(
- jolokiaRegistryClient, TestingConfigRegistry.moduleName1,
- TestingConfigRegistry.instName1);
- assertEquals(jmxLookup, jolokiaLookup);
+ assertEquals(Sets.newHashSet(testingRegistry.run2), jmxLookup);
jmxLookup = clientLookupRuntimeBeansWithModuleAndInstance(
jmxRegistryClient, TestingConfigRegistry.moduleName2,
TestingConfigRegistry.instName2);
assertEquals(1, jmxLookup.size());
- jolokiaLookup = clientLookupRuntimeBeansWithModuleAndInstance(
- jolokiaRegistryClient, TestingConfigRegistry.moduleName2,
- TestingConfigRegistry.instName2);
- assertEquals(jmxLookup, jolokiaLookup);
+ assertEquals(Sets.newHashSet(testingRegistry.run3), jmxLookup);
jmxLookup = clientLookupRuntimeBeansWithModuleAndInstance(
jmxRegistryClient, TestingConfigRegistry.moduleName1,
TestingConfigRegistry.instName2);
assertEquals(0, jmxLookup.size());
- jolokiaLookup = clientLookupRuntimeBeansWithModuleAndInstance(
- jolokiaRegistryClient, TestingConfigRegistry.moduleName1,
- TestingConfigRegistry.instName2);
- assertEquals(jmxLookup, jolokiaLookup);
+ assertEquals(Sets.newHashSet(), jmxLookup);
}
private Set<ObjectName> clientLookupRuntimeBeansWithModuleAndInstance(
}
return beans;
}
-
- @Test
- public void testValidationExceptionDeserialization() {
- try {
- jolokiaRegistryClient.commitConfig(null);
- fail();
- } catch (ValidationException e) {
- String moduleName = "moduleName", instanceName = "instanceName";
- assertThat(e.getFailedValidations().containsKey(moduleName),
- is(true));
- assertThat(e.getFailedValidations().size(), is(1));
- assertThat(e.getFailedValidations().get(moduleName).size(), is(1));
- assertThat(
- e.getFailedValidations().get(moduleName)
- .containsKey(instanceName), is(true));
- assertThat(
- e.getFailedValidations().get(moduleName).get(instanceName)
- .getMessage(), is("message"));
- assertThat(
- e.getFailedValidations().get(moduleName).get(instanceName)
- .getTrace(),
- containsString("org.opendaylight.controller.config.util.TestingConfigRegistry.commitConfig"));
- }
- }
-
}
*/
package org.opendaylight.controller.config.util;
-import static org.junit.Assert.assertEquals;
-
-import java.lang.management.ManagementFactory;
-import java.util.Set;
-
-import javax.management.MBeanServer;
-import javax.management.ObjectName;
-
+import com.google.common.collect.Sets;
import org.junit.After;
import org.junit.Before;
import org.junit.Test;
-import org.opendaylight.controller.config.api.jmx.ConfigTransactionControllerMXBean;
import org.opendaylight.controller.config.api.jmx.ObjectNameUtil;
-import org.opendaylight.controller.config.util.jolokia.ConfigTransactionJolokiaClient;
-public class ConfigTransactionClientsTest {
+import javax.management.MBeanServer;
+import javax.management.ObjectName;
+import java.lang.management.ManagementFactory;
+import java.util.Set;
+import static org.junit.Assert.assertEquals;
+
+public class ConfigTransactionClientsTest {
private final MBeanServer mbs = ManagementFactory.getPlatformMBeanServer();
- private String jolokiaURL;
- private ConfigTransactionControllerMXBean transactionController;
+ private TestingConfigTransactionController transactionController;
private ObjectName transactionControllerON;
- private ConfigTransactionClient jmxTransactionClient,
- jolokiaTransactionClient;
+ private ConfigTransactionClient jmxTransactionClient;
@Before
public void setUp() throws Exception {
- jolokiaURL = JolokiaHelper.startTestingJolokia();
transactionController = new TestingConfigTransactionController();
transactionControllerON = new ObjectName(ObjectNameUtil.ON_DOMAIN + ":"
+ ObjectNameUtil.TYPE_KEY + "=TransactionController");
mbs.registerMBean(transactionController, transactionControllerON);
- jmxTransactionClient = new ConfigTransactionJMXClient(null,
- transactionControllerON,
+ jmxTransactionClient = new ConfigTransactionJMXClient(null, transactionControllerON,
ManagementFactory.getPlatformMBeanServer());
- jolokiaTransactionClient = new ConfigTransactionJolokiaClient(
- jolokiaURL, transactionControllerON, null);
}
@After
public void cleanUp() throws Exception {
- JolokiaHelper.stopJolokia();
if (transactionControllerON != null) {
mbs.unregisterMBean(transactionControllerON);
}
@Test
public void testLookupConfigBeans() throws Exception {
Set<ObjectName> jmxLookup = testClientLookupConfigBeans(jmxTransactionClient);
- Set<ObjectName> jolokiaLookup = testClientLookupConfigBeans(jolokiaTransactionClient);
- assertEquals(jmxLookup, jolokiaLookup);
+ assertEquals(Sets.newHashSet(transactionController.conf1,
+ transactionController.conf2, transactionController.conf3), jmxLookup);
}
private Set<ObjectName> testClientLookupConfigBeans(
assertEquals(3, beans.size());
return beans;
}
-
}
+++ /dev/null
-/*
- * Copyright (c) 2013 Cisco Systems, Inc. and others. All rights reserved.
- *
- * This program and the accompanying materials are made available under the
- * terms of the Eclipse Public License v1.0 which accompanies this distribution,
- * and is available at http://www.eclipse.org/legal/epl-v10.html
- */
-package org.opendaylight.controller.config.util;
-
-import org.jolokia.jvmagent.JolokiaServer;
-import org.jolokia.jvmagent.JvmAgentConfig;
-
-public class JolokiaHelper {
- private static JolokiaServer jolokiaServer;
-
- /**
- * Bind to port 17777. By convention, ports above 10000 are used for testing
- * and < 10000 for production
- *
- * @return url that can be passed to new J4pClient(url)
- */
- public static String startTestingJolokia() {
- return startJolokia("localhost", 17777);
- }
-
- /**
- * @return url that can be passed to new J4pClient(url)
- * @throws IOException
- */
- public static String startJolokia(String host, int port) {
- String agentArgs = "host=" + host + ",port=" + port;
- JvmAgentConfig config = new JvmAgentConfig(agentArgs);
- Exception lastException = null;
- for (int i = 0; i < 10; i++) {
- try {
- jolokiaServer = new JolokiaServer(config, false);
- jolokiaServer.start();
- return "http://" + host + ":" + port + "/jolokia/";
- } catch (Exception e) {
- lastException = e;
- try {
- Thread.sleep(100);
- } catch (InterruptedException ie) {
- ie.printStackTrace();
- }
- }
- }
- throw new RuntimeException(lastException);
- }
-
- public static void stopJolokia() {
- jolokiaServer.stop();
- }
-}
*/
package org.opendaylight.controller.config.util;
-import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.fail;
-
-import java.lang.management.ManagementFactory;
-import java.lang.reflect.Method;
-import java.util.Map;
-import java.util.Map.Entry;
-import java.util.Set;
-
-import javax.management.InstanceNotFoundException;
-import javax.management.MBeanServer;
-import javax.management.ObjectName;
-
+import com.google.common.collect.ImmutableMap;
+import com.google.common.collect.Sets;
import org.junit.After;
import org.junit.Before;
import org.junit.Test;
import org.opendaylight.controller.config.api.LookupRegistry;
import org.opendaylight.controller.config.api.jmx.ConfigTransactionControllerMXBean;
import org.opendaylight.controller.config.api.jmx.ObjectNameUtil;
-import org.opendaylight.controller.config.util.jolokia.ConfigRegistryJolokiaClient;
-import org.opendaylight.controller.config.util.jolokia.ConfigTransactionJolokiaClient;
-import com.google.common.collect.ImmutableMap;
-import com.google.common.collect.Sets;
+import javax.management.InstanceNotFoundException;
+import javax.management.MBeanServer;
+import javax.management.ObjectName;
+import java.lang.management.ManagementFactory;
+import java.lang.reflect.Method;
+import java.util.HashSet;
+import java.util.Map;
+import java.util.Map.Entry;
+import java.util.Set;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.fail;
public class LookupTest {
- private String jolokiaURL;
private TestingConfigRegistry testingRegistry;
private ObjectName testingRegistryON;
private final MBeanServer mbs = ManagementFactory.getPlatformMBeanServer();
- private ConfigRegistryClient jmxRegistryClient, jolokiaRegistryClient;
+ private ConfigRegistryClient jmxRegistryClient;
private ConfigTransactionControllerMXBean testingTransactionController;
private ObjectName testingTransactionControllerON;
- private ConfigTransactionClient jmxTransactionClient,
- jolokiaTransactionClient;
+ private ConfigTransactionClient jmxTransactionClient;
Map<LookupRegistry, ? extends Set<? extends LookupRegistry>> lookupProvidersToClients;
@Before
public void setUp() throws Exception {
- jolokiaURL = JolokiaHelper.startTestingJolokia();
testingRegistry = new TestingConfigRegistry();
testingRegistryON = ConfigRegistry.OBJECT_NAME;
mbs.registerMBean(testingRegistry, testingRegistryON);
jmxRegistryClient = new ConfigRegistryJMXClient(
ManagementFactory.getPlatformMBeanServer());
- jolokiaRegistryClient = new ConfigRegistryJolokiaClient(jolokiaURL);
+
testingTransactionController = new TestingConfigTransactionController();
testingTransactionControllerON = new ObjectName(
jmxTransactionClient = new ConfigTransactionJMXClient(null,
testingTransactionControllerON,
ManagementFactory.getPlatformMBeanServer());
- jolokiaTransactionClient = new ConfigTransactionJolokiaClient(
- jolokiaURL, testingTransactionControllerON, null);
- lookupProvidersToClients = ImmutableMap
- .of(testingRegistry, Sets.newHashSet(jmxRegistryClient, jolokiaRegistryClient),
- testingTransactionController, Sets.newHashSet(jmxTransactionClient, jolokiaTransactionClient));
+
+ HashSet<ConfigRegistryClient> registryClients = Sets.newHashSet(jmxRegistryClient);
+ HashSet<ConfigTransactionClient> configTransactionClients = Sets.newHashSet(jmxTransactionClient);
+ lookupProvidersToClients = ImmutableMap.of((LookupRegistry) testingRegistry, registryClients,
+ testingTransactionController, configTransactionClients);
}
@After
public void cleanUp() throws Exception {
- JolokiaHelper.stopJolokia();
mbs.unregisterMBean(testingRegistryON);
mbs.unregisterMBean(testingTransactionControllerON);
}
package org.opendaylight.controller.config.util;
import java.util.List;
+import java.util.Map;
import java.util.Set;
import javax.management.InstanceNotFoundException;
}
}
+ @Override
+ public void checkConfigBeanExists(ObjectName objectName) throws InstanceNotFoundException {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public ObjectName lookupConfigBeanByServiceInterfaceName(String serviceInterfaceName, String refName) {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public Map<String, Map<String, ObjectName>> getServiceMapping() {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public Map<String, ObjectName> lookupServiceReferencesByServiceInterfaceName(String serviceInterfaceName) {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public Set<String> lookupServiceInterfaceNames(ObjectName objectName) throws InstanceNotFoundException {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public String getServiceInterfaceName(String namespace, String localName) {
+ throw new UnsupportedOperationException();
+ }
}
*/
package org.opendaylight.controller.config.util;
+import java.util.Map;
import java.util.Set;
import javax.management.InstanceAlreadyExistsException;
public class TestingConfigTransactionController implements
ConfigTransactionControllerMXBean {
- private final ObjectName conf1, conf2, conf3;
+ public final ObjectName conf1, conf2, conf3;
public static final String moduleName1 = "moduleA";
public static final String moduleName2 = "moduleB";
return null;
}
}
+
+ @Override
+ public void checkConfigBeanExists(ObjectName objectName) throws InstanceNotFoundException {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public void saveServiceReference(String serviceInterfaceName, String refName, ObjectName objectName) throws InstanceNotFoundException {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public boolean removeServiceReference(String serviceInterfaceName, String refName) {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public void removeAllServiceReferences() {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public ObjectName lookupConfigBeanByServiceInterfaceName(String serviceInterfaceName, String refName) {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public Map<String, Map<String, ObjectName>> getServiceMapping() {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public Map<String, ObjectName> lookupServiceReferencesByServiceInterfaceName(String serviceInterfaceName) {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public Set<String> lookupServiceInterfaceNames(ObjectName objectName) throws InstanceNotFoundException {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public String getServiceInterfaceName(String namespace, String localName) {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public boolean removeServiceReferences(ObjectName objectName) throws InstanceNotFoundException {
+ throw new UnsupportedOperationException();
+ }
}
+++ /dev/null
-/*
- * Copyright (c) 2013 Cisco Systems, Inc. and others. All rights reserved.
- *
- * This program and the accompanying materials are made available under the
- * terms of the Eclipse Public License v1.0 which accompanies this distribution,
- * and is available at http://www.eclipse.org/legal/epl-v10.html
- */
-package org.opendaylight.controller.config.util.jolokia;
-
-import static org.hamcrest.core.Is.is;
-import static org.junit.Assert.assertThat;
-
-import java.util.HashMap;
-import java.util.Map;
-
-import org.json.simple.JSONObject;
-import org.json.simple.JSONValue;
-import org.junit.Before;
-import org.junit.Test;
-import org.opendaylight.controller.config.api.ValidationException;
-import org.opendaylight.controller.config.api.ValidationException.ExceptionMessageWithStackTrace;
-
-public class ListableJolokiaClientTest {
-
- private Map<String, Map<String, ExceptionMessageWithStackTrace>> failedValidations;
-
- private ValidationException val;
-
- private final static String ex = "{\"message\":null,"
- + "\"failedValidations\":"
- + "{\"ifc2\":{\"impl1\":{\"message\":\"abc\",\"trace\":\"vvv\"},"
- + "\"impl2\":{\"message\":\"abc2\",\"trace\":\"vvv2\"}},"
- + "\"ifc1\":"
- + "{\"impl1\":{\"message\":\"abc\",\"trace\":\"vvv\"},"
- + "\"impl2\":{\"message\":\"abc2\",\"trace\":\"vvv2\"}}},"
- + "\"localizedMessage\":null," + "\"cause\":null}";
-
- @Before
- public void setUp() {
- failedValidations = new HashMap<String, Map<String, ExceptionMessageWithStackTrace>>();
- Map<String, ExceptionMessageWithStackTrace> map1 = new HashMap<String, ValidationException.ExceptionMessageWithStackTrace>();
- map1.put("impl1", new ExceptionMessageWithStackTrace("abc", "vvv"));
- map1.put("impl2", new ExceptionMessageWithStackTrace("abc2", "vvv2"));
- failedValidations.put("ifc1", map1);
- failedValidations.put("ifc2", map1);
- val = new ValidationException(failedValidations);
- }
-
- @Test
- public void testParsing() {
- JSONObject e = (JSONObject) JSONValue.parse(ex);
- ValidationException val2 = ListableJolokiaClient
- .createValidationExceptionFromJSONObject(e);
- assertThat(val2.getMessage(), is(val.getMessage()));
- assertThat(val2.getFailedValidations(), is(val.getFailedValidations()));
- }
-
-}
<osgi.version>5.0.0</osgi.version>
<jacoco.version>0.6.2.201302030002</jacoco.version>
<slf4j.version>1.7.2</slf4j.version>
- <jolokia.version>1.1.1</jolokia.version>
<opendaylight.yang.version>0.5.9-SNAPSHOT</opendaylight.yang.version>
<opendaylight.binding.version>0.6.0-SNAPSHOT</opendaylight.binding.version>
<opendaylight.yangtools.version>0.1.1-SNAPSHOT</opendaylight.yangtools.version>
<artifactId>guava</artifactId>
<version>14.0.1</version>
</dependency>
- <dependency>
- <groupId>org.jolokia</groupId>
- <artifactId>jolokia-core</artifactId>
- <version>${jolokia.version}</version>
- </dependency>
- <dependency>
- <groupId>org.jolokia</groupId>
- <artifactId>jolokia-jvm</artifactId>
- <version>${jolokia.version}</version>
- <classifier>agent</classifier>
- </dependency>
- <dependency>
- <groupId>org.jolokia</groupId>
- <artifactId>jolokia-client-java</artifactId>
- <version>${jolokia.version}</version>
- </dependency>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
Preconditions.checkNotNull(exportedClassName,
"Cannot create annotation from null exportedClassName");
- List<Parameter> params = Lists.newArrayList(new Parameter("value",
- q(qname.getLocalName())));
- params.add(new Parameter("osgiRegistrationType", exportedClassName
- + ".class"));
+ List<Parameter> params = Lists.newArrayList(new Parameter("value", q(qname.toString())));
+ params.add(new Parameter("osgiRegistrationType", exportedClassName + ".class"));
+
+ 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())));
+
return new Annotation(
ServiceInterfaceAnnotation.class.getCanonicalName(), params);
}
{
public static final java.lang.String NAME = "${globallyUniqueName}";
- private static final java.util.Set<Class<? extends ${abstractServiceInterfaceType}>> serviceIfcs = new java.util.HashSet<Class<? extends ${abstractServiceInterfaceType}>>();
+ private static final java.util.Set<Class<? extends ${abstractServiceInterfaceType}>> serviceIfcs;
<#if providedServices??>
static {
+ java.util.Set<Class<? extends ${abstractServiceInterfaceType}>> serviceIfcs2 = new java.util.HashSet<Class<? extends ${abstractServiceInterfaceType}>>();
<#list providedServices as refId>
- serviceIfcs.add(${refId});
+ serviceIfcs2.add(${refId});
</#list>
+ serviceIfcs = java.util.Collections.unmodifiableSet(serviceIfcs2);
}
</#if>
return false;
}
+ @Override
+ public java.util.Set<Class<? extends ${abstractServiceInterfaceType}>> getImplementedServiceIntefaces() {
+ return serviceIfcs;
+ }
+
+
@Override
public ${moduleType} createModule(String instanceName, ${dependencyResolverType} dependencyResolver, ${bundleContextType} bundleContext) {
return instantiateModule(instanceName, dependencyResolver, bundleContext);
"public static final java.lang.String NAME=\"threadfactory-naming\"");
assertDeclaredField(
fieldDeclarations,
- "private static final java.util.Set<Class<? extends org.opendaylight.controller.config.api.annotations.AbstractServiceInterface>> serviceIfcs=new java.util.HashSet<Class<? extends org.opendaylight.controller.config.api.annotations.AbstractServiceInterface>>()");
+ "private static final java.util.Set<Class<? extends org.opendaylight.controller.config.api.annotations.AbstractServiceInterface>> serviceIfcs");
assertEquals(2, fieldDeclarations.size());
- assertFactoryMethods(visitor.methods, 8);
+ assertFactoryMethods(visitor.methods, 9);
assertEquals("Incorrenct number of generated method descriptions", 0,
visitor.methodDescriptions.size());
assertEquals("Incorrenct number of generated method javadoc", 0,
</dependencies>
</profile>
<profile>
+ <!-- sanitytests are only enabled with this profile -->
<id>integrationtests</id>
<activation>
<activeByDefault>false</activeByDefault>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
- <artifactId>maven-dependency-plugin</artifactId>
- <version>2.8</version>
- <executions>
- <execution>
- <id>copy</id>
- <phase>package</phase>
- <goals>
- <goal>copy</goal>
- </goals>
- </execution>
- </executions>
+ <artifactId>maven-invoker-plugin</artifactId>
+ <version>1.5</version>
<configuration>
- <artifactItems>
- <artifactItem>
- <groupId>org.opendaylight.controller</groupId>
- <artifactId>sanitytest</artifactId>
- <version>${controller.version}</version>
- <type>jar</type>
- </artifactItem>
- </artifactItems>
- </configuration>
- </plugin>
- <plugin>
- <groupId>org.codehaus.mojo</groupId>
- <artifactId>exec-maven-plugin</artifactId>
- <version>1.2.1</version>
- <executions>
- <execution>
- <id>sanity-test</id>
- <phase>package</phase>
- <goals>
- <goal>exec</goal>
- </goals>
- </execution>
- </executions>
- <configuration>
- <executable>${java.home}/bin/java</executable>
- <arguments>
- <argument>-cp</argument>
- <argument>./target/dependency/*</argument>
- <argument>org.opendaylight.controller.distribution.Sanity</argument>
- </arguments>
- <environmentVariables>
- <JAVA_HOME>
- ${java.home}
- </JAVA_HOME>
- </environmentVariables>
- </configuration>
- </plugin>
+ <debug>false</debug>
+ <projectsDirectory>../sanitytest</projectsDirectory>
+ <pomIncludes>
+ <pomInclude>pom.xml</pomInclude>
+ </pomIncludes>
+ <streamLogs>true</streamLogs>
+ <noLog>true</noLog>
+ <goals>
+ <goal>clean</goal>
+ <goal>verify</goal>
+ </goals>
+ </configuration>
+ <executions>
+ <execution>
+ <id>integration-test</id>
+ <goals>
+ <goal>install</goal>
+ <goal>run</goal>
+ </goals>
+ </execution>
+ </executions>
+ </plugin>
</plugins>
</build>
+
+ <dependencies>
+ <dependency>
+ <groupId>org.opendaylight.controller</groupId>
+ <artifactId>controller-maven-plugin</artifactId>
+ <version>0.1.0-SNAPSHOT</version>
+ </dependency>
+ </dependencies>
</profile>
</profiles>
<version>${commons.httpclient.version}</version>
</dependency>
- <dependency>
- <groupId>org.opendaylight.controller</groupId>
- <artifactId>sanitytest</artifactId>
- <version>${controller.version}</version>
- </dependency>
-
-
</dependencies>
</execution>
</executions>
</plugin>
+
</plugins>
</build>
+
</project>
+++ /dev/null
-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
+++ /dev/null
-# 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
-
<exclude>com.sun.jersey:jersey-json</exclude>
<exclude>com.sun.jersey:jersey-server</exclude>
<exclude>org.opendaylight.controller:logging.bridge</exclude>
- <exclude>org.opendaylight.controller:sanitytest</exclude>
</excludes>
<outputFileNameMapping>
${artifact.groupId}.${artifact.artifactId}-${artifact.version}${dashClassifier?}.${artifact.extension}
<name>dom-broker</name>
<data-store xmlns="urn:opendaylight:params:xml:ns:yang:controller:md:sal:dom:impl">
<type xmlns:dom="urn:opendaylight:params:xml:ns:yang:controller:md:sal:dom">dom:dom-data-store</type>
- <!-- to switch to the clustered data store, comment out the ref_hash-map-data-store <name> and uncomment the ref_cluster-data-store one -->
- <name>ref_hash-map-data-store</name>
- <!-- <name>ref_cluster-data-store</name> -->
+ <!-- to switch to the clustered data store, comment out the hash-map-data-store <name> and uncomment the cluster-data-store one -->
+ <name>hash-map-data-store</name>
+ <!-- <name>cluster-data-store</name> -->
</data-store>
</module>
<module>
<name>binding-broker-impl</name>
<notification-service xmlns="urn:opendaylight:params:xml:ns:yang:controller:md:sal:binding:impl">
<type xmlns:binding="urn:opendaylight:params:xml:ns:yang:controller:md:sal:binding">binding:binding-notification-service</type>
- <name>ref_binding-notification-broker</name>
+ <name>binding-notification-broker</name>
</notification-service>
<data-broker xmlns="urn:opendaylight:params:xml:ns:yang:controller:md:sal:binding:impl">
<type xmlns:binding="urn:opendaylight:params:xml:ns:yang:controller:md:sal:binding">binding:binding-data-broker</type>
- <name>ref_binding-data-broker</name>
+ <name>binding-data-broker</name>
</data-broker>
</module>
<module>
<name>binding-data-broker</name>
<dom-broker xmlns="urn:opendaylight:params:xml:ns:yang:controller:md:sal:binding:impl">
<type xmlns:dom="urn:opendaylight:params:xml:ns:yang:controller:md:sal:dom">dom:dom-broker-osgi-registry</type>
- <name>ref_dom-broker</name>
+ <name>dom-broker</name>
</dom-broker>
<mapping-service xmlns="urn:opendaylight:params:xml:ns:yang:controller:md:sal:binding:impl">
<type xmlns:binding="urn:opendaylight:params:xml:ns:yang:controller:md:sal:binding:impl">binding:binding-dom-mapping-service</type>
- <name>ref_runtime-mapping-singleton</name>
+ <name>runtime-mapping-singleton</name>
</mapping-service>
</module>
//SERVICES START
<service>
<type xmlns:dom="urn:opendaylight:params:xml:ns:yang:controller:md:sal:dom">dom:schema-service</type>
<instance>
- <name>ref_yang-schema-service</name>
+ <name>yang-schema-service</name>
<provider>/modules/module[type='schema-service-singleton'][name='yang-schema-service']</provider>
</instance>
</service>
<service>
<type xmlns:binding="urn:opendaylight:params:xml:ns:yang:controller:md:sal:binding">binding:binding-notification-service</type>
<instance>
- <name>ref_binding-notification-broker</name>
+ <name>binding-notification-broker</name>
<provider>/modules/module[type='binding-notification-broker'][name='binding-notification-broker']</provider>
</instance>
</service>
<service>
<type xmlns:dom="urn:opendaylight:params:xml:ns:yang:controller:md:sal:dom">dom:dom-data-store</type>
<instance>
- <name>ref_hash-map-data-store</name>
+ <name>hash-map-data-store</name>
<provider>/modules/module[type='hash-map-data-store'][name='hash-map-data-store']</provider>
</instance>
<instance>
- <name>ref_cluster-data-store</name>
+ <name>cluster-data-store</name>
<provider>/modules/module[type='dom-clustered-store-impl'][name='cluster-data-store']</provider>
</instance>
</service>
<service>
<type xmlns:binding="urn:opendaylight:params:xml:ns:yang:controller:md:sal:binding">binding:binding-broker-osgi-registry</type>
<instance>
- <name>ref_binding-broker-impl</name>
+ <name>binding-osgi-broker</name>
<provider>/modules/module[type='binding-broker-impl'][name='binding-broker-impl']</provider>
</instance>
</service>
<service>
<type xmlns:binding-impl="urn:opendaylight:params:xml:ns:yang:controller:md:sal:binding:impl">binding-impl:binding-dom-mapping-service</type>
<instance>
- <name>ref_runtime-mapping-singleton</name>
+ <name>runtime-mapping-singleton</name>
<provider>/modules/module[type='runtime-generated-mapping'][name='runtime-mapping-singleton']</provider>
</instance>
</service>
<service>
<type xmlns:dom="urn:opendaylight:params:xml:ns:yang:controller:md:sal:dom">dom:dom-broker-osgi-registry</type>
<instance>
- <name>ref_dom-broker</name>
+ <name>dom-broker</name>
<provider>/modules/module[type='dom-broker-impl'][name='dom-broker']</provider>
</instance>
</service>
<service>
<type xmlns:binding="urn:opendaylight:params:xml:ns:yang:controller:md:sal:binding">binding:binding-data-broker</type>
<instance>
- <name>ref_binding-data-broker</name>
+ <name>binding-data-broker</name>
<provider>/modules/module[type='binding-data-broker'][name='binding-data-broker']</provider>
</instance>
</service>
ECHO %RUN_CMD%
if "%startEnabled%" NEQ "" (
- START /B cmd /C CALL %RUN_CMD% > %basedir%\logs\controller.out 2>&1
+ START /B cmd /C CALL %RUN_CMD%
ECHO Running controller in the background.
) else (
%RUN_CMD%
<artifactId>sanitytest</artifactId>
<version>0.4.1-SNAPSHOT</version>
- <packaging>bundle</packaging>
+ <packaging>jar</packaging>
+
+ <properties>
+ <distro.dir>${project.basedir}/../opendaylight/target/distribution.opendaylight-osgipackage/opendaylight</distro.dir>
+ <distro.script>${distro.dir}/run.bat</distro.script>
+ <!-- the address is passed to both the controller & the test to establish the connection -->
+ <sanitytest.bind.address>127.0.0.1</sanitytest.bind.address>
+ <sanitytest.timeout>300</sanitytest.timeout>
+ </properties>
+
+ <profiles>
+ <profile>
+ <id>non-windows</id>
+ <activation>
+ <os>
+ <family>!windows</family>
+ </os>
+ </activation>
+ <properties>
+ <distro.script>${distro.dir}/run.sh</distro.script>
+ <distro.pid>/tmp/opendaylight.PID</distro.pid>
+ </properties>
+ </profile>
+ </profiles>
+
<dependencies>
<dependency>
<groupId>org.osgi</groupId>
<artifactId>org.osgi.core</artifactId>
<scope>provided</scope>
</dependency>
+
+ <dependency>
+ <groupId>junit</groupId>
+ <artifactId>junit</artifactId>
+ <scope>test</scope>
+ </dependency>
+
+ <dependency>
+ <groupId>org.ow2.chameleon.management</groupId>
+ <artifactId>chameleon-mbeans</artifactId>
+ <scope>test</scope>
+ </dependency>
+
</dependencies>
+
<build>
<plugins>
<plugin>
- <groupId>org.apache.felix</groupId>
- <artifactId>maven-bundle-plugin</artifactId>
- <version>${bundle.plugin.version}</version>
- <extensions>true</extensions>
+ <!-- disable the install plugin -->
+ <groupId>org.apache.maven.plugins</groupId>
+ <artifactId>maven-install-plugin</artifactId>
+ <version>${install.plugin.version}</version>
<configuration>
- <instructions>
- <Export-Package>
- org.opendaylight.controller.sanitytest
- </Export-Package>
- <Import-Package>
- 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
- </Import-Package>
- <Bundle-Activator>
- org.opendaylight.controller.sanitytest.internal.Activator
- </Bundle-Activator>
- </instructions>
- <manifestLocation>${project.basedir}/META-INF</manifestLocation>
+ <skip>true</skip>
</configuration>
+ <executions>
+ <execution>
+ <id>default-install</id>
+ <phase>none</phase>
+ </execution>
+ </executions>
</plugin>
+
+ <plugin>
+ <!-- ensure that the distro installation is already built -->
+ <groupId>org.apache.maven.plugins</groupId>
+ <artifactId>maven-enforcer-plugin</artifactId>
+ <version>${enforcer.plugin.version}</version>
+ <executions>
+ <execution>
+ <id>enforce-files-exist</id>
+ <phase>pre-integration-test</phase>
+ <goals>
+ <goal>enforce</goal>
+ </goals>
+ <configuration>
+ <rules>
+ <requireFilesExist>
+ <files>
+ <file>${distro.script}</file>
+ </files>
+ </requireFilesExist>
+ </rules>
+ <fail>true</fail>
+ </configuration>
+ </execution>
+ </executions>
+ </plugin>
+
+ <plugin>
+ <groupId>org.opendaylight.controller</groupId>
+ <artifactId>controller-maven-plugin</artifactId>
+ <version>0.1.0-SNAPSHOT</version>
+ <configuration>
+ <controllerHome>${distro.dir}</controllerHome>
+ <controllerHost>localhost</controllerHost>
+ <controllerWebPort>8080</controllerWebPort>
+ <controllerUsername>admin</controllerUsername>
+ <controllerPassword>admin</controllerPassword>
+ <controllerStartScriptName>${distro.script}</controllerStartScriptName>
+ <pidFile>${distro.pid}</pidFile>
+ </configuration>
+ <executions>
+ <execution>
+ <!-- ensure controller is started in pre-integration phase -->
+ <id>start-controller</id>
+ <phase>pre-integration-test</phase>
+ <configuration>
+ <startArgs>
+ <param>-start</param>
+ <param>-jmx</param>
+ <param>-Djava.rmi.server.hostname=${sanitytest.bind.address} </param>
+ </startArgs>
+ <warmupTimeSecs> 60 </warmupTimeSecs>
+ </configuration>
+ <goals>
+ <goal>run</goal>
+ </goals>
+ </execution>
+ <execution>
+ <!-- ensure controller is stopped in post-integration phase -->
+ <id>stop-controller</id>
+ <phase>post-integration-test</phase>
+ <goals>
+ <goal>stop</goal>
+ </goals>
+ </execution>
+ </executions>
+ </plugin>
+
+ <plugin>
+ <!-- run the test -->
+ <groupId>org.apache.maven.plugins</groupId>
+ <artifactId>maven-failsafe-plugin</artifactId>
+ <version>${failsafe.version}</version>
+ <configuration>
+ <systemPropertyVariables>
+ <ctrl.home>${distro.dir}</ctrl.home>
+ <ctrl.host>${sanitytest.bind.address}</ctrl.host>
+ <ctrl.start.timeout>${sanitytest.timeout}</ctrl.start.timeout>
+ </systemPropertyVariables>
+ </configuration>
+ </plugin>
+
</plugins>
+
+
</build>
</project>
+++ /dev/null
-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<String> script = new ArrayList<String>();
-
- 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());
- }
-}
+++ /dev/null
-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 {
-
- }
-}
--- /dev/null
+/*
+ * Copyright (c) 2013 Cisco Systems, Inc. and others. All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+package org.opendaylight.controller.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<String> bundles =
+ Collections.synchronizedSet(new HashSet<String>());
+ private static final Set<String> fragments =
+ Collections.synchronizedSet(new HashSet<String>());
+
+ @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<ObjectName> 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;
+ }
+ }
+
+
+
+
+}
--- /dev/null
+/**
+ * @author Maros Marsalek
+ *
+ * 12 2013
+ *
+ * Copyright (c) 2012 by Cisco Systems, Inc.
+ * All rights reserved.
+ */
+package org.opendaylight.controller.netconf.confignetconfconnector.mapping.attributes;
+
+public class AttributesConstants {
+
+ /**
+ * Property placed into object names for dependencies to preserve reference name
+ */
+ public static final String REF_NAME_ON_PROPERTY_KEY = "X-refName";
+}
import com.google.common.base.Optional;
import com.google.common.base.Preconditions;
+import org.opendaylight.controller.netconf.confignetconfconnector.mapping.attributes.AttributesConstants;
import org.opendaylight.controller.netconf.confignetconfconnector.mapping.config.Services;
import org.opendaylight.controller.netconf.confignetconfconnector.util.Util;
Util.checkType(value, ObjectName.class);
ObjectName on = (ObjectName) value;
- String refName = tracker.addServiceEntry(namespace, serviceName, on);
+
+ String expectedRefName = on.getKeyProperty(AttributesConstants.REF_NAME_ON_PROPERTY_KEY);
+
+ String refName = expectedRefName == null ? tracker.getRefName(namespace, serviceName, on, Optional.<String> absent())
+ : tracker.getRefName(namespace, serviceName, on, Optional.of(expectedRefName));
return Optional.of(new MappedDependency(namespace, serviceName, refName));
}
import com.google.common.base.Optional;
import org.opendaylight.controller.config.api.jmx.ObjectNameUtil;
+import org.opendaylight.controller.netconf.confignetconfconnector.mapping.attributes.AttributesConstants;
import org.opendaylight.controller.netconf.confignetconfconnector.mapping.attributes.mapping.ObjectNameAttributeMappingStrategy;
import org.opendaylight.controller.netconf.confignetconfconnector.mapping.config.Services;
import org.opendaylight.controller.netconf.confignetconfconnector.mapping.config.Services.ServiceInstance;
ServiceInstance byRefName = serviceTracker.getByServiceAndRefName(namespace, serviceName, refName);
ObjectName on = ObjectNameUtil.createReadOnlyModuleON(byRefName.getModuleName(), byRefName.getInstanceName());
+ on = ObjectNameUtil.createON(on.toString() + "," + AttributesConstants.REF_NAME_ON_PROPERTY_KEY + "=" + refName);
+
logger.debug("Attribute {} : {} parsed to type {}", attrName, value, getOpenType());
return Optional.of(on);
}
import com.google.common.collect.Lists;
import com.google.common.collect.Maps;
import com.google.common.collect.Multimap;
+import org.opendaylight.controller.config.api.ServiceReferenceReadableRegistry;
import org.opendaylight.controller.config.api.jmx.ObjectNameUtil;
import org.opendaylight.controller.netconf.confignetconfconnector.operations.editconfig.EditStrategyType;
import org.opendaylight.controller.netconf.util.xml.XmlElement;
}
public static Map<String, Map<String, Collection<ObjectName>>> getMappedInstances(Set<ObjectName> instancesToMap,
- Services serviceTracker, Map<String, Map<String, ModuleConfig>> configs) {
+ Map<String, Map<String, ModuleConfig>> configs) {
Multimap<String, ObjectName> moduleToInstances = mapInstancesToModules(instancesToMap);
Map<String, Map<String, Collection<ObjectName>>> retVal = Maps.newLinkedHashMap();
innerRetVal.put(moduleName, instances);
- // All found instances add to service tracker in advance
- // This way all instances will be serialized as all available
- // services when get-config is triggered
- // (even if they are not used as services by other instances)
- // = more user friendly
- addServices(serviceTracker, instances, mbeEntry.getValue().getProvidedServices());
-
}
retVal.put(namespace, innerRetVal);
return retVal;
}
- private static void addServices(Services serviceTracker, Collection<ObjectName> instances,
- Multimap<String, String> providedServices) {
- for (ObjectName instanceOn : instances) {
- for (Entry<String, String> serviceName : providedServices.entries()) {
- serviceTracker.addServiceEntry(serviceName.getKey(), serviceName.getValue(), instanceOn);
- }
- }
- }
-
private static Multimap<String, ObjectName> mapInstancesToModules(Set<ObjectName> instancesToMap) {
Multimap<String, ObjectName> retVal = HashMultimap.create();
// }
public Element toXml(Set<ObjectName> instancesToMap, Optional<String> maybeNamespace, Document document,
- Element dataElement) {
- Services serviceTracker = new Services();
+ Element dataElement, Services serviceTracker) {
Map<String, Map<String, Collection<ObjectName>>> moduleToInstances = getMappedInstances(instancesToMap,
- serviceTracker, moduleConfigs);
+ moduleConfigs);
Element root = dataElement;
if (maybeNamespace.isPresent()) {
// TODO refactor, replace string representing namespace with namespace class
// TODO refactor, replace Map->Multimap with e.g. ConfigElementResolved
// class
- public Map<String, Multimap<String, ModuleElementResolved>> fromXml(XmlElement xml, Set<ObjectName> instancesForFillingServiceRefMapping,
- EditStrategyType defaultEditStrategyType) {
+ public ConfigElementResolved fromXml(XmlElement xml,
+ EditStrategyType defaultEditStrategyType, ServiceReferenceReadableRegistry taClient) {
Map<String, Multimap<String, ModuleElementResolved>> retVal = Maps.newHashMap();
List<XmlElement> recognisedChildren = Lists.newArrayList();
- Services serviceTracker = fromXmlServices(xml, recognisedChildren, instancesForFillingServiceRefMapping);
+ Services serviceTracker = fromXmlServices(xml, recognisedChildren, taClient);
List<XmlElement> moduleElements = fromXmlModules(xml, recognisedChildren);
xml.checkUnrecognisedElements(recognisedChildren);
resolveModule(retVal, serviceTracker, moduleElement, defaultEditStrategyType);
}
- return retVal;
+ return new ConfigElementResolved(retVal, serviceTracker);
+ }
+
+ public static class ConfigElementResolved {
+
+ private final Map<String, Multimap<String, ModuleElementResolved>> resolvedModules;
+ private final Services services;
+
+ public ConfigElementResolved(Map<String, Multimap<String, ModuleElementResolved>> retVal, Services serviceTracker) {
+ this.resolvedModules = retVal;
+ this.services = serviceTracker;
+ }
+
+ public Map<String, Multimap<String, ModuleElementResolved>> getResolvedModules() {
+ return resolvedModules;
+ }
+
+ public Services getServices() {
+ return services;
+ }
}
private List<XmlElement> fromXmlModules(XmlElement xml, List<XmlElement> recognisedChildren) {
innerMap.put(factoryName, moduleElementResolved);
}
- private Services fromXmlServices(XmlElement xml, List<XmlElement> recognisedChildren, Set<ObjectName> instancesForFillingServiceRefMapping) {
+ private Services fromXmlServices(XmlElement xml, List<XmlElement> recognisedChildren,
+ ServiceReferenceReadableRegistry taClient) {
Optional<XmlElement> servicesElement = xml.getOnlyChildElementOptionally(XmlNetconfConstants.SERVICES_KEY,
XmlNetconfConstants.URN_OPENDAYLIGHT_PARAMS_XML_NS_YANG_CONTROLLER_CONFIG);
} else {
mappedServices = new HashMap<>();
}
- Services services = Services.resolveServices(mappedServices);
- // merge with what candidate db contains by default - ref_
-
- for(ObjectName existingON: instancesForFillingServiceRefMapping) {
- logger.trace("Filling services from {}", existingON);
- // get all its services
- String factoryName = ObjectNameUtil.getFactoryName(existingON);
- ModuleConfig moduleConfig = moduleNamesToConfigs.get(factoryName);
-
- checkState(moduleConfig != null, "Cannot find ModuleConfig with name " + factoryName + " in " + moduleNamesToConfigs);
- // Set<String> services = ;
- for (Entry<String, String> serviceName : moduleConfig.getProvidedServices().entries()) {
-
- services.addServiceEntry(serviceName.getKey(), serviceName.getValue(), existingON);
- }
- }
+ Services services = Services.resolveServices(mappedServices, taClient);
return services;
}
import com.google.common.base.Preconditions;
import com.google.common.collect.Lists;
import com.google.common.collect.Maps;
+import com.google.common.collect.Multimap;
import org.opendaylight.controller.config.util.ConfigRegistryClient;
import org.opendaylight.controller.config.yangjmxgenerator.RuntimeBeanEntry;
import org.opendaylight.controller.config.yangjmxgenerator.attribute.AttributeIfc;
}
public InstanceConfigElementResolved fromXml(XmlElement moduleElement, Services services, String moduleNamespace,
- EditStrategyType defaultStrategy) {
+ EditStrategyType defaultStrategy, Multimap<String, String> providedServices) {
Map<String, AttributeConfigElement> retVal = Maps.newHashMap();
Map<String, AttributeReadingStrategy> strats = new ObjectXmlReader().prepareReading(yangToAttrConfig);
XmlNetconfConstants.URN_IETF_PARAMS_XML_NS_NETCONF_BASE_1_0);
InstanceConfigElementResolved instanceConfigElementResolved = perInstanceEditStrategy.equals("") ? new InstanceConfigElementResolved(
- retVal, defaultStrategy) : new InstanceConfigElementResolved(perInstanceEditStrategy, retVal, defaultStrategy);
+ retVal, defaultStrategy, providedServices) : new InstanceConfigElementResolved(perInstanceEditStrategy, retVal, defaultStrategy, providedServices);
resolveConfiguration(instanceConfigElementResolved, services);
return instanceConfigElementResolved;
package org.opendaylight.controller.netconf.confignetconfconnector.mapping.config;
import com.google.common.base.Preconditions;
+import com.google.common.collect.Multimap;
import org.opendaylight.controller.netconf.confignetconfconnector.mapping.attributes.fromxml.AttributeConfigElement;
import org.opendaylight.controller.netconf.confignetconfconnector.operations.editconfig.EditConfigStrategy;
import org.opendaylight.controller.netconf.confignetconfconnector.operations.editconfig.EditConfigXmlParser;
private final EditStrategyType editStrategy;
private final Map<String, AttributeConfigElement> configuration;
+ private final Multimap<String, String> providedServices;
- public InstanceConfigElementResolved(String currentStrategy, Map<String, AttributeConfigElement> configuration, EditStrategyType defaultStrategy) {
+ public InstanceConfigElementResolved(String currentStrategy, Map<String, AttributeConfigElement> configuration, EditStrategyType defaultStrategy, Multimap<String, String> providedServices) {
EditStrategyType valueOf = checkStrategy(currentStrategy, defaultStrategy);
this.editStrategy = valueOf;
this.configuration = configuration;
+ this.providedServices = providedServices;
}
- public InstanceConfigElementResolved(Map<String, AttributeConfigElement> configuration, EditStrategyType defaultStrategy) {
+ public InstanceConfigElementResolved(Map<String, AttributeConfigElement> configuration, EditStrategyType defaultStrategy, Multimap<String, String> providedServices) {
editStrategy = defaultStrategy;
this.configuration = configuration;
+ this.providedServices = providedServices;
}
public EditConfigStrategy getEditStrategy() {
- return editStrategy.getFittingStrategy();
+ return editStrategy.getFittingStrategy(providedServices);
}
public Map<String, AttributeConfigElement> getConfiguration() {
public ModuleElementResolved fromXml(XmlElement moduleElement, Services depTracker, String instanceName,
String moduleNamespace, EditStrategyType defaultStrategy) {
- InstanceConfigElementResolved ice = instanceConfig.fromXml(moduleElement, depTracker, moduleNamespace, defaultStrategy);
+ InstanceConfigElementResolved ice = instanceConfig.fromXml(moduleElement, depTracker, moduleNamespace, defaultStrategy, providedServices);
return new ModuleElementResolved(instanceName, ice);
}
package org.opendaylight.controller.netconf.confignetconfconnector.mapping.config;
import com.google.common.annotations.VisibleForTesting;
-import com.google.common.base.Function;
+import com.google.common.base.Optional;
import com.google.common.base.Preconditions;
+import com.google.common.collect.HashMultimap;
import com.google.common.collect.Maps;
+import com.google.common.collect.Multimap;
import com.google.common.collect.Sets;
+import org.opendaylight.controller.config.api.ServiceReferenceReadableRegistry;
+import org.opendaylight.controller.config.api.jmx.ObjectNameUtil;
import org.opendaylight.controller.netconf.confignetconfconnector.mapping.attributes.fromxml.ObjectNameAttributeReadingStrategy;
import org.opendaylight.controller.netconf.util.xml.XmlElement;
import org.opendaylight.controller.netconf.util.xml.XmlNetconfConstants;
import org.w3c.dom.Document;
import org.w3c.dom.Element;
-import javax.annotation.Nullable;
import javax.management.ObjectName;
import java.util.Collection;
+import java.util.Collections;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import java.util.regex.Pattern;
public final class Services {
+
private static final Logger logger = LoggerFactory.getLogger(Services.class);
private static final String PROVIDER_KEY = "provider";
private long suffix = 1;
- private final Map<ServiceInstance, String> instanceToRef = Maps.newHashMap();
private final Map<String /*Namespace*/, Map<String/* ServiceName */, Map<String/* refName */, ServiceInstance>>> namespaceToServiceNameToRefNameToInstance = Maps
.newHashMap();
+ private ServiceReferenceReadableRegistry configServiceRefRegistry;
- public String addServiceEntry(String namespace, String serviceName, ObjectName on) {
-
- String moduleName = on.getKeyProperty("moduleFactoryName");
- String instanceName = on.getKeyProperty("instanceName");
-
- String refName = addServiceEntry(namespace, serviceName, moduleName, instanceName);
- logger.trace("Added service entry to tracker. Service name {}, ref name {}, module name {}, instance name {}",
- serviceName, refName, moduleName, instanceName);
- return refName;
+ public Services(ServiceReferenceReadableRegistry configServiceRefRegistry) {
+ this.configServiceRefRegistry = configServiceRefRegistry;
}
@VisibleForTesting
- public String addServiceEntry(String namespace, String serviceName, String moduleName, String instanceName) {
- ServiceInstance serviceInstance = new ServiceInstance(moduleName, instanceName);
- serviceInstance.setServiceName(serviceName);
+ public String getNewDefaultRefName(String namespace, String serviceName, String moduleName, String instanceName) {
+ String refName;
+ refName = "ref_" + instanceName;
- String refName = instanceToRef.get(serviceInstance);
+ Map<String, Map<String, String>> serviceNameToRefNameToInstance = getMappedServices().get(namespace);
- Map<String, Map<String, ServiceInstance>> serviceNameToRefNameToInstance = namespaceToServiceNameToRefNameToInstance.get(namespace);
- if (serviceNameToRefNameToInstance == null) {
- serviceNameToRefNameToInstance = Maps.newHashMap();
- namespaceToServiceNameToRefNameToInstance.put(namespace, serviceNameToRefNameToInstance);
- }
+ Map<String, String> refNameToInstance;
+ if(serviceNameToRefNameToInstance == null || serviceNameToRefNameToInstance.containsKey(serviceName) == false) {
+ refNameToInstance = Collections.emptyMap();
+ } else
+ refNameToInstance = serviceNameToRefNameToInstance.get(serviceName);
- Map<String, ServiceInstance> refNameToInstance = serviceNameToRefNameToInstance.get(serviceName);
- if (refNameToInstance == null) {
- refNameToInstance = Maps.newHashMap();
- serviceNameToRefNameToInstance.put(serviceName, refNameToInstance);
+ final Set<String> refNamesAsSet = toSet(refNameToInstance.keySet());
+ if (refNamesAsSet.contains(refName)) {
+ refName = findAvailableRefName(refName, refNamesAsSet);
}
- if (refName != null) {
- if (serviceNameToRefNameToInstance.get(serviceName).containsKey(moduleName) == false) {
- refNameToInstance.put(refName, serviceInstance);
- }
- return refName;
- } else {
- refName = "ref_" + instanceName;
-
- final Set<String> refNamesAsSet = toSet(instanceToRef.values());
- if (refNamesAsSet.contains(refName)) {
- refName = findAvailableRefName(refName, refNamesAsSet);
- }
-
- instanceToRef.put(serviceInstance, refName);
- refNameToInstance.put(refName, serviceInstance);
-
- return refName;
- }
+ return refName;
}
private Set<String> toSet(Collection<String> values) {
}
public ServiceInstance getByServiceAndRefName(String namespace, String serviceName, String refName) {
- Map<String, Map<String, ServiceInstance>> serviceNameToRefNameToInstance = namespaceToServiceNameToRefNameToInstance.get(namespace);
- Preconditions.checkArgument(serviceNameToRefNameToInstance != null, "No serviceInstances mapped to " + namespace + " , "
- + serviceNameToRefNameToInstance.keySet());
+ Map<String, Map<String, String>> serviceNameToRefNameToInstance = getMappedServices().get(namespace);
+
+ Preconditions.checkArgument(serviceNameToRefNameToInstance != null, "No serviceInstances mapped to " + namespace);
- Map<String, ServiceInstance> refNameToInstance = serviceNameToRefNameToInstance.get(serviceName);
+ Map<String, String> refNameToInstance = serviceNameToRefNameToInstance.get(serviceName);
Preconditions.checkArgument(refNameToInstance != null, "No serviceInstances mapped to " + serviceName + " , "
+ serviceNameToRefNameToInstance.keySet());
- ServiceInstance serviceInstance = refNameToInstance.get(refName);
+ ServiceInstance serviceInstance = ServiceInstance.fromString(refNameToInstance.get(refName));
Preconditions.checkArgument(serviceInstance != null, "No serviceInstance mapped to " + refName
+ " under service name " + serviceName + " , " + refNameToInstance.keySet());
return serviceInstance;
for (String serviceName : serviceNameToRefNameToInstance.keySet()) {
- Map<String, String> innerInnerRetVal = Maps.transformValues(
- serviceNameToRefNameToInstance.get(serviceName), new Function<ServiceInstance, String>() {
- @Nullable
- @Override
- public String apply(@Nullable ServiceInstance serviceInstance) {
- return serviceInstance.toString();
- }
- });
+ Map<String, String> innerInnerRetVal = Maps.newHashMap();
+ for (Entry<String, ServiceInstance> refNameToSi : serviceNameToRefNameToInstance.get(serviceName).entrySet()) {
+ innerInnerRetVal.put(refNameToSi.getKey(), refNameToSi.getValue().toString());
+ }
innerRetVal.put(serviceName, innerInnerRetVal);
}
retVal.put(namespace, innerRetVal);
}
+ Map<String, Map<String, ObjectName>> serviceMapping = configServiceRefRegistry.getServiceMapping();
+ for (String serviceQName : serviceMapping.keySet())
+ for (String refName : serviceMapping.get(serviceQName).keySet()) {
+
+ ObjectName on = serviceMapping.get(serviceQName).get(refName);
+ ServiceInstance si = ServiceInstance.fromObjectName(on);
+
+ // FIXME use QName's new String constructor, after its implemented
+ Pattern p = Pattern.compile("\\(([^\\(\\?]+)\\?[^\\?\\)]*\\)([^\\)]+)");
+ Matcher matcher = p.matcher(serviceQName);
+ Preconditions.checkArgument(matcher.matches());
+ String namespace = matcher.group(1);
+ String localName = matcher.group(2);
+
+ Map<String, Map<String, String>> serviceToRefs = retVal.get(namespace);
+ if(serviceToRefs==null) {
+ serviceToRefs = Maps.newHashMap();
+ retVal.put(namespace, serviceToRefs);
+ }
+
+ Map<String, String> refsToSis = serviceToRefs.get(localName);
+ if(refsToSis==null) {
+ refsToSis = Maps.newHashMap();
+ serviceToRefs.put(localName, refsToSis);
+ }
+
+ Preconditions.checkState(refsToSis.containsKey(refName) == false,
+ "Duplicate reference name %s for service %s:%s, now for instance %s", refName, namespace,
+ localName, on);
+ refsToSis.put(refName, si.toString());
+ }
+
return retVal;
}
+ /**
+ *
+ */
+ public Map<String, Map<String, Map<String, ServiceInstance>>> getNamespaceToServiceNameToRefNameToInstance() {
+ return namespaceToServiceNameToRefNameToInstance;
+ }
+
// TODO hide resolveServices, call it explicitly in fromXml
- public static Services resolveServices(Map<String, Map<String, Map<String, String>>> mappedServices) {
- Services tracker = new Services();
+ public static Services resolveServices(Map<String, Map<String, Map<String, String>>> mappedServices, ServiceReferenceReadableRegistry taClient) {
+ Services tracker = new Services(taClient);
for (Entry<String, Map<String, Map<String, String>>> namespaceEntry : mappedServices.entrySet()) {
String namespace = namespaceEntry.getKey();
}
String refName = refEntry.getKey();
- Preconditions.checkState(false == refNameToInstance.containsKey(refName),
- "Duplicate reference name to service " + refName + " under service " + serviceName);
+
ServiceInstance serviceInstance = ServiceInstance.fromString(refEntry.getValue());
refNameToInstance.put(refName, serviceInstance);
- tracker.instanceToRef.put(serviceInstance, refEntry.getKey());
}
}
}
return tracker;
}
+ // TODO support edit strategies on services
+
public static Map<String, Map<String, Map<String, String>>> fromXml(XmlElement xml) {
Map<String, Map<String, Map<String, String>>> retVal = Maps.newHashMap();
return root;
}
+ public String getRefName(String namespace, String serviceName, ObjectName on, Optional<String> expectedRefName) {
+ Optional<String> refNameOptional = getRefNameOptional(namespace, serviceName, on, expectedRefName);
+ Preconditions.checkState(refNameOptional.isPresent(), "No reference names mapped to %s, %s, %s", namespace,
+ serviceName, on);
+ return refNameOptional.get();
+ }
+
+ public Optional<String> getRefNameOptional(String namespace, String serviceName, ObjectName on,
+ Optional<String> expectedRefName) {
+ Map<String, Map<String, String>> services = getMappedServices().get(namespace);
+
+ if(services == null) return Optional.absent();
+ Map<String, String> refs = services.get(serviceName);
+
+ if(refs == null) return Optional.absent();
+ Multimap<ServiceInstance, String> reverted = revertMap(refs);
+
+ ServiceInstance serviceInstance = ServiceInstance.fromObjectName(on);
+ Collection<String> references = reverted.get(serviceInstance);
+
+ if (expectedRefName.isPresent() && references.contains(expectedRefName.get())) {
+ logger.debug("Returning expected ref name {} for {}", expectedRefName.get(), on);
+ return expectedRefName;
+ } else if (references.size() > 0) {
+ String next = references.iterator().next();
+ logger.debug("Returning random ref name {} for {}", next, on);
+ return Optional.of(next);
+ } else
+ return Optional.absent();
+ }
+
+ private Multimap<ServiceInstance, String> revertMap(Map<String, String> refs) {
+ Multimap<ServiceInstance, String> multimap = HashMultimap.create();
+
+ for (Entry<String, String> e : refs.entrySet()) {
+ multimap.put(ServiceInstance.fromString(e.getValue()), e.getKey());
+ }
+
+ return multimap;
+ }
+
+ public boolean hasRefName(String key, String value, ObjectName on) {
+ return getRefNameOptional(key, value, on, Optional.<String>absent()).isPresent();
+ }
+
public static final class ServiceInstance {
public ServiceInstance(String moduleName, String instanceName) {
this.moduleName = moduleName;
return true;
}
+ public ObjectName getObjectName(String transactionName) {
+ return ObjectNameUtil.createTransactionModuleON(transactionName, moduleName, instanceName);
+ }
+
+ public static ServiceInstance fromObjectName(ObjectName on) {
+ return new ServiceInstance(ObjectNameUtil.getFactoryName(on), ObjectNameUtil.getInstanceName(on));
+ }
}
}
import com.google.common.collect.HashMultimap;
import com.google.common.collect.Maps;
import com.google.common.collect.Multimap;
+import org.opendaylight.controller.config.api.ServiceReferenceReadableRegistry;
import org.opendaylight.controller.config.api.jmx.ObjectNameUtil;
import org.opendaylight.controller.netconf.confignetconfconnector.mapping.config.Config;
import org.opendaylight.controller.netconf.confignetconfconnector.mapping.config.ModuleConfig;
return retVal;
}
- public Element toXml(Set<ObjectName> instancesToMap, Set<ObjectName> configBeans, Document document) {
- Services serviceTracker = new Services();
+ public Element toXml(Set<ObjectName> instancesToMap, Set<ObjectName> configBeans, Document document, ServiceReferenceReadableRegistry serviceRegistry) {
+ Services serviceTracker = new Services(serviceRegistry);
Element root = document.createElement(XmlNetconfConstants.DATA_KEY);
Map<String, Multimap<String, ObjectName>> moduleToRuntimeInstance = mapInstancesToModules(instancesToMap);
Map<String, Map<String, Collection<ObjectName>>> moduleToConfigInstance = Config.getMappedInstances(
- configBeans, serviceTracker, moduleConfigs);
+ configBeans, moduleConfigs);
for (String localNamespace : moduleConfigs.keySet()) {
package org.opendaylight.controller.netconf.confignetconfconnector.operations.editconfig;
-import java.util.Map;
-
-import javax.management.InstanceNotFoundException;
-import javax.management.ObjectName;
-
import org.opendaylight.controller.config.util.ConfigTransactionClient;
import org.opendaylight.controller.netconf.confignetconfconnector.mapping.attributes.fromxml.AttributeConfigElement;
+import org.opendaylight.controller.netconf.confignetconfconnector.mapping.config.Services;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
+import javax.management.InstanceNotFoundException;
+import javax.management.ObjectName;
+import java.util.Map;
+
public abstract class AbstractEditConfigStrategy implements EditConfigStrategy {
private static final Logger logger = LoggerFactory.getLogger(AbstractEditConfigStrategy.class);
@Override
public void executeConfiguration(String module, String instance, Map<String, AttributeConfigElement> configuration,
- ConfigTransactionClient ta) {
+ ConfigTransactionClient ta, Services services) {
try {
ObjectName on = ta.lookupConfigBean(module, instance);
logger.debug("ServiceInstance for {} {} located successfully under {}", module, instance, on);
- executeStrategy(configuration, ta, on);
+ executeStrategy(configuration, ta, on, services);
} catch (InstanceNotFoundException e) {
- handleMissingInstance(configuration, ta, module, instance);
+ handleMissingInstance(configuration, ta, module, instance, services);
}
}
abstract void handleMissingInstance(Map<String, AttributeConfigElement> configuration, ConfigTransactionClient ta,
- String module, String instance);
+ String module, String instance, Services services);
abstract void executeStrategy(Map<String, AttributeConfigElement> configuration, ConfigTransactionClient ta,
- ObjectName objectName);
+ ObjectName objectName, Services services);
}
package org.opendaylight.controller.netconf.confignetconfconnector.operations.editconfig;
-import java.util.Map;
-
-import javax.management.InstanceNotFoundException;
-import javax.management.ObjectName;
-
+import com.google.common.collect.HashMultimap;
+import com.google.common.collect.Multimap;
import org.opendaylight.controller.config.util.ConfigTransactionClient;
import org.opendaylight.controller.netconf.confignetconfconnector.mapping.attributes.fromxml.AttributeConfigElement;
+import org.opendaylight.controller.netconf.confignetconfconnector.mapping.config.Services;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
+import javax.management.InstanceNotFoundException;
+import javax.management.ObjectName;
+import java.util.Map;
+
public class DeleteEditConfigStrategy extends AbstractEditConfigStrategy {
private static final Logger logger = LoggerFactory.getLogger(DeleteEditConfigStrategy.class);
+ private final Multimap<String, String> providedServices;
+
+ public DeleteEditConfigStrategy() {
+ this.providedServices = HashMultimap.create();
+ }
+
+ public DeleteEditConfigStrategy(Multimap<String, String> providedServices) {
+ this.providedServices = providedServices;
+ }
+
@Override
void handleMissingInstance(Map<String, AttributeConfigElement> configuration, ConfigTransactionClient ta,
- String module, String instance) {
+ String module, String instance, Services services) {
throw new IllegalStateException("Unable to delete " + module + ":" + instance + " , ServiceInstance not found");
}
@Override
- void executeStrategy(Map<String, AttributeConfigElement> configuration, ConfigTransactionClient ta, ObjectName on) {
+ void executeStrategy(Map<String, AttributeConfigElement> configuration, ConfigTransactionClient ta, ObjectName on, Services services) {
try {
ta.destroyModule(on);
logger.debug("ServiceInstance {} deleted successfully", on);
import org.opendaylight.controller.netconf.confignetconfconnector.mapping.config.InstanceConfigElementResolved;
import org.opendaylight.controller.netconf.confignetconfconnector.mapping.config.ModuleConfig;
import org.opendaylight.controller.netconf.confignetconfconnector.mapping.config.ModuleElementResolved;
+import org.opendaylight.controller.netconf.confignetconfconnector.mapping.config.Services;
import org.opendaylight.controller.netconf.confignetconfconnector.operations.AbstractConfigNetconfOperation;
import org.opendaylight.controller.netconf.confignetconfconnector.operations.editconfig.EditConfigXmlParser.EditConfigExecution;
import org.opendaylight.controller.netconf.confignetconfconnector.transactions.TransactionProvider;
import org.w3c.dom.Document;
import org.w3c.dom.Element;
+import javax.management.InstanceNotFoundException;
import javax.management.ObjectName;
import java.util.HashMap;
import java.util.Map;
@VisibleForTesting
Element getResponseInternal(final Document document,
final EditConfigXmlParser.EditConfigExecution editConfigExecution) throws NetconfDocumentedException {
+
if (editConfigExecution.shouldTest()) {
executeTests(configRegistryClient, editConfigExecution);
}
private void executeTests(ConfigRegistryClient configRegistryClient,
EditConfigExecution editConfigExecution) throws NetconfDocumentedException {
try {
- test(configRegistryClient, editConfigExecution.getResolvedXmlElements(), editConfigExecution.getDefaultStrategy());
+ test(configRegistryClient, editConfigExecution, editConfigExecution.getDefaultStrategy());
} catch (IllegalStateException | JmxAttributeValidationException | ValidationException e) {
logger.warn("Test phase for {} failed", EditConfigXmlParser.EDIT_CONFIG, e);
final Map<String, String> errorInfo = new HashMap<>();
}
private void test(ConfigRegistryClient configRegistryClient,
- Map<String, Multimap<String, ModuleElementResolved>> resolvedModules, EditStrategyType editStrategyType) {
+ EditConfigExecution execution, EditStrategyType editStrategyType) {
ObjectName taON = transactionProvider.getTestTransaction();
try {
if (editStrategyType == EditStrategyType.replace) {
transactionProvider.wipeTestTransaction(taON);
}
- setOnTransaction(configRegistryClient, resolvedModules, taON);
+
+ setOnTransaction(configRegistryClient, execution.getResolvedXmlElements(), execution.getServices(), taON);
+ // TODO add service reference persistance testing here
transactionProvider.validateTestTransaction(taON);
} finally {
transactionProvider.abortTestTransaction(taON);
if (editConfigExecution.getDefaultStrategy() == EditStrategyType.replace) {
transactionProvider.wipeTransaction();
}
- setOnTransaction(configRegistryClient, editConfigExecution.getResolvedXmlElements(), taON);
+
+ setOnTransaction(configRegistryClient, editConfigExecution.getResolvedXmlElements(),
+ editConfigExecution.getServices(), taON);
+ setServicesOnTransaction(configRegistryClient, editConfigExecution.getServices(), taON);
+ }
+
+ private void setServicesOnTransaction(ConfigRegistryClient configRegistryClient, Services services,
+ ObjectName taON) {
+ ConfigTransactionClient ta = configRegistryClient.getConfigTransactionClient(taON);
+
+ Map<String, Map<String, Map<String, Services.ServiceInstance>>> namespaceToServiceNameToRefNameToInstance = services
+ .getNamespaceToServiceNameToRefNameToInstance();
+
+ for (String serviceNamespace : namespaceToServiceNameToRefNameToInstance.keySet()) {
+ for (String serviceName : namespaceToServiceNameToRefNameToInstance.get(serviceNamespace).keySet()) {
+
+ String qnameOfService = getQname(ta, serviceNamespace, serviceName);
+ Map<String, Services.ServiceInstance> refNameToInstance = namespaceToServiceNameToRefNameToInstance
+ .get(serviceNamespace).get(serviceName);
+
+ for (String refName : refNameToInstance.keySet()) {
+ ObjectName on = refNameToInstance.get(refName).getObjectName(ta.getTransactionName());
+ // TODO check for duplicates
+ try {
+ ta.saveServiceReference(qnameOfService, refName, on);
+ } catch (InstanceNotFoundException e) {
+ throw new IllegalStateException("Unable to save ref name " + refName + " for instance " + on, e);
+ }
+ }
+ }
+ }
+ }
+
+ private String getQname(ConfigTransactionClient ta, String namespace, String serviceName) {
+ return ta.getServiceInterfaceName(namespace, serviceName);
}
private void setOnTransaction(ConfigRegistryClient configRegistryClient,
- Map<String, Multimap<String, ModuleElementResolved>> resolvedXmlElements, ObjectName taON) {
+ Map<String, Multimap<String, ModuleElementResolved>> resolvedXmlElements, Services services, ObjectName taON) {
ConfigTransactionClient ta = configRegistryClient.getConfigTransactionClient(taON);
for (Multimap<String, ModuleElementResolved> modulesToResolved : resolvedXmlElements.values()) {
InstanceConfigElementResolved ice = moduleElementResolved.getInstanceConfigElementResolved();
EditConfigStrategy strategy = ice.getEditStrategy();
- strategy.executeConfiguration(moduleName, instanceName, ice.getConfiguration(), ta);
+ strategy.executeConfiguration(moduleName, instanceName, ice.getConfiguration(), ta, services);
}
}
}
import org.opendaylight.controller.config.util.ConfigTransactionClient;
import org.opendaylight.controller.netconf.confignetconfconnector.mapping.attributes.fromxml.AttributeConfigElement;
+import org.opendaylight.controller.netconf.confignetconfconnector.mapping.config.Services;
import java.util.Map;
public interface EditConfigStrategy {
void executeConfiguration(String module, String instance, Map<String, AttributeConfigElement> configuration,
- ConfigTransactionClient ta);
+ ConfigTransactionClient ta, Services services);
}
import com.google.common.base.Optional;
import com.google.common.base.Preconditions;
import com.google.common.collect.Multimap;
+import org.opendaylight.controller.config.api.ServiceReferenceReadableRegistry;
import org.opendaylight.controller.config.util.ConfigRegistryClient;
+import org.opendaylight.controller.config.util.ConfigTransactionClient;
import org.opendaylight.controller.netconf.api.NetconfDocumentedException;
import org.opendaylight.controller.netconf.confignetconfconnector.mapping.config.Config;
import org.opendaylight.controller.netconf.confignetconfconnector.mapping.config.ModuleElementResolved;
+import org.opendaylight.controller.netconf.confignetconfconnector.mapping.config.Services;
import org.opendaylight.controller.netconf.confignetconfconnector.operations.Datastore;
import org.opendaylight.controller.netconf.confignetconfconnector.transactions.TransactionProvider;
import org.opendaylight.controller.netconf.util.xml.XmlElement;
import javax.management.ObjectName;
import java.util.Arrays;
-import java.util.Collections;
import java.util.Map;
-import java.util.Set;
public class EditConfigXmlParser {
TransactionProvider transactionProvider, ConfigRegistryClient configRegistryClient)
throws NetconfDocumentedException {
+ //TODO remove transactionProvider and CfgRegistry from parameters, accept only service ref store
+
EditStrategyType editStrategyType = EditStrategyType.getDefaultStrategy();
xml.checkName(EditConfigXmlParser.EDIT_CONFIG);
logger.trace("Setting merge strategy to {}", mergeStrategyString);
editStrategyType = EditStrategyType.valueOf(mergeStrategyString);
}
- Set<ObjectName> instancesForFillingServiceRefMapping = Collections.emptySet();
- if (editStrategyType == EditStrategyType.merge) {
- instancesForFillingServiceRefMapping = Datastore.getInstanceQueryStrategy(targetDatastore, transactionProvider)
- .queryInstances(configRegistryClient);
- logger.trace("Pre-filling services from following instances: {}", instancesForFillingServiceRefMapping);
- }
XmlElement configElement = xml.getOnlyChildElementWithSameNamespace(XmlNetconfConstants.CONFIG_KEY);
- return new EditConfigXmlParser.EditConfigExecution(xml, cfgMapping, configElement, testOption,
- instancesForFillingServiceRefMapping, editStrategyType);
- }
+ ObjectName taON = transactionProvider.getOrCreateTransaction();
+ ConfigTransactionClient ta = configRegistryClient.getConfigTransactionClient(taON);
- private void removeMountpointsFromConfig(XmlElement configElement, XmlElement mountpointsElement) {
- configElement.getDomElement().removeChild(mountpointsElement.getDomElement());
+ return new EditConfigXmlParser.EditConfigExecution(cfgMapping, configElement, testOption,
+ ta, editStrategyType);
}
@VisibleForTesting
@VisibleForTesting
static class EditConfigExecution {
- private final XmlElement editConfigXml;
+
private final Map<String, Multimap<String, ModuleElementResolved>> resolvedXmlElements;
private final TestOption testOption;
private final EditStrategyType defaultEditStrategyType;
+ private final Services services;
- EditConfigExecution(XmlElement xml, Config configResolver, XmlElement configElement, TestOption testOption, Set<ObjectName> instancesForFillingServiceRefMapping,
- EditStrategyType defaultStrategy) {
- this.editConfigXml = xml;
- this.resolvedXmlElements = configResolver.fromXml(configElement, instancesForFillingServiceRefMapping, defaultStrategy);
+ EditConfigExecution(Config configResolver, XmlElement configElement, TestOption testOption, ServiceReferenceReadableRegistry ta, EditStrategyType defaultStrategy) {
+ Config.ConfigElementResolved configElementResolved = configResolver.fromXml(configElement, defaultStrategy, ta);
+ this.resolvedXmlElements = configElementResolved.getResolvedModules();
+ this.services = configElementResolved.getServices();
this.testOption = testOption;
this.defaultEditStrategyType = defaultStrategy;
}
EditStrategyType getDefaultStrategy() {
return defaultEditStrategyType;
}
+
+ Services getServices() {
+ return services;
+ }
}
}
package org.opendaylight.controller.netconf.confignetconfconnector.operations.editconfig;
+import com.google.common.collect.Multimap;
+
import java.util.EnumSet;
import java.util.Set;
}
}
- public EditConfigStrategy getFittingStrategy() {
+ public EditConfigStrategy getFittingStrategy(Multimap<String, String> providedServices) {
switch (this) {
case merge:
- return new MergeEditConfigStrategy();
+ return new MergeEditConfigStrategy(providedServices);
case replace:
- return new ReplaceEditConfigStrategy();
+ return new ReplaceEditConfigStrategy(providedServices);
case delete:
- return new DeleteEditConfigStrategy();
+ return new DeleteEditConfigStrategy(providedServices);
case remove:
return new RemoveEditConfigStrategy();
case none:
package org.opendaylight.controller.netconf.confignetconfconnector.operations.editconfig;
-import java.util.Map;
-import java.util.Map.Entry;
-
-import javax.management.Attribute;
-import javax.management.InstanceAlreadyExistsException;
-import javax.management.ObjectName;
-
+import com.google.common.collect.HashMultimap;
+import com.google.common.collect.Multimap;
import org.opendaylight.controller.config.util.ConfigTransactionClient;
import org.opendaylight.controller.netconf.confignetconfconnector.mapping.attributes.fromxml.AttributeConfigElement;
+import org.opendaylight.controller.netconf.confignetconfconnector.mapping.config.Services;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
+import javax.management.Attribute;
+import javax.management.InstanceAlreadyExistsException;
+import javax.management.InstanceNotFoundException;
+import javax.management.ObjectName;
+import java.util.Map;
+import java.util.Map.Entry;
+
public class MergeEditConfigStrategy extends AbstractEditConfigStrategy {
private static final Logger logger = LoggerFactory.getLogger(MergeEditConfigStrategy.class);
+ private final Multimap<String, String> providedServices;
+
+ public MergeEditConfigStrategy() {
+ this.providedServices = HashMultimap.create();
+ }
+
+ public MergeEditConfigStrategy(Multimap<String, String> providedServices) {
+ this.providedServices = providedServices;
+ }
@Override
void handleMissingInstance(Map<String, AttributeConfigElement> configuration, ConfigTransactionClient ta,
- String module, String instance) {
- ObjectName on;
+ String module, String instance, Services services) {
+ ObjectName on = null;
try {
on = ta.createModule(module, instance);
logger.info("New instance for {} {} created under name {}", module, instance, on);
- executeStrategy(configuration, ta, on);
+ addRefNames(services, providedServices, module, instance, ta, on);
+ executeStrategy(configuration, ta, on, services);
} catch (InstanceAlreadyExistsException e1) {
throw new IllegalStateException("Unable to create instance for " + module + " : " + instance);
+ } catch (InstanceNotFoundException e) {
+ throw new IllegalStateException("Unable to save default ref name for instance " + on, e);
+ }
+ }
+
+ private void addRefNames(Services services, Multimap<String, String> providedServices, String module,
+ String instance, ConfigTransactionClient ta, ObjectName on) throws InstanceNotFoundException {
+ for (Entry<String, String> namespaceToService : providedServices.entries()) {
+
+ if(services.hasRefName(namespaceToService.getKey(),
+ namespaceToService.getValue(), on))
+ continue;
+
+ String refName = services.getNewDefaultRefName(namespaceToService.getKey(), namespaceToService.getValue(),
+ module, instance);
+ ta.saveServiceReference(
+ ta.getServiceInterfaceName(namespaceToService.getKey(), namespaceToService.getValue()), refName, on);
}
}
@Override
- void executeStrategy(Map<String, AttributeConfigElement> configuration, ConfigTransactionClient ta, ObjectName on) {
+ void executeStrategy(Map<String, AttributeConfigElement> configuration, ConfigTransactionClient ta, ObjectName on, Services services) {
for (Entry<String, AttributeConfigElement> configAttributeEntry : configuration.entrySet()) {
try {
AttributeConfigElement ace = configAttributeEntry.getValue();
import org.opendaylight.controller.config.util.ConfigTransactionClient;
import org.opendaylight.controller.netconf.confignetconfconnector.mapping.attributes.fromxml.AttributeConfigElement;
+import org.opendaylight.controller.netconf.confignetconfconnector.mapping.config.Services;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@Override
public void executeConfiguration(String module, String instance, Map<String, AttributeConfigElement> configuration,
- ConfigTransactionClient ta) {
+ ConfigTransactionClient ta, Services services) {
logger.debug("Skipping configuration element for {}:{}", module, instance);
}
import org.opendaylight.controller.config.util.ConfigTransactionClient;
import org.opendaylight.controller.netconf.confignetconfconnector.mapping.attributes.fromxml.AttributeConfigElement;
+import org.opendaylight.controller.netconf.confignetconfconnector.mapping.config.Services;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@Override
void handleMissingInstance(Map<String, AttributeConfigElement> configuration, ConfigTransactionClient ta,
- String module, String instance) {
+ String module, String instance, Services services) {
logger.warn("Unable to delete {}:{}, ServiceInstance not found", module, instance);
}
}
package org.opendaylight.controller.netconf.confignetconfconnector.operations.editconfig;
-import java.util.Map;
-import java.util.Map.Entry;
-
-import javax.management.Attribute;
-import javax.management.InstanceAlreadyExistsException;
-import javax.management.ObjectName;
-
+import com.google.common.collect.HashMultimap;
+import com.google.common.collect.Multimap;
import org.opendaylight.controller.config.util.ConfigTransactionClient;
import org.opendaylight.controller.netconf.confignetconfconnector.mapping.attributes.fromxml.AttributeConfigElement;
+import org.opendaylight.controller.netconf.confignetconfconnector.mapping.config.Services;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
+import javax.management.Attribute;
+import javax.management.InstanceAlreadyExistsException;
+import javax.management.InstanceNotFoundException;
+import javax.management.ObjectName;
+import java.util.Map;
+import java.util.Map.Entry;
+
public class ReplaceEditConfigStrategy extends AbstractEditConfigStrategy {
private static final Logger logger = LoggerFactory.getLogger(ReplaceEditConfigStrategy.class);
+ private final Multimap<String, String> providedServices;
+
+ public ReplaceEditConfigStrategy() {
+ this.providedServices = HashMultimap.create();
+ }
+
+ public ReplaceEditConfigStrategy(Multimap<String, String> providedServices) {
+ this.providedServices = providedServices;
+ }
+
@Override
void handleMissingInstance(Map<String, AttributeConfigElement> configuration, ConfigTransactionClient ta,
- String module, String instance) {
+ String module, String instance, Services services) {
+ ObjectName on = null;
try {
- ObjectName on = ta.createModule(module, instance);
+ on = ta.createModule(module, instance);
logger.debug("New instance for {} {} created under name {}", module, instance, on);
- executeStrategy(configuration, ta, on);
+ addRefNames(services, providedServices, module, instance, ta, on);
+ executeStrategy(configuration, ta, on, services);
} catch (InstanceAlreadyExistsException e) {
logger.warn("Error creating instance {}:{}, replace failed", module, instance, e);
throw new IllegalStateException("Unable to create new instance for " + module + " : " + instance, e);
+ } catch (InstanceNotFoundException e) {
+ throw new IllegalStateException("Unable to save default ref name for instance " + on, e);
}
}
+ private void addRefNames(Services services, Multimap<String, String> providedServices, String module,
+ String instance, ConfigTransactionClient ta, ObjectName on) throws InstanceNotFoundException {
+ for (Entry<String, String> namespaceToService : providedServices.entries()) {
+
+ if(services.hasRefName(namespaceToService.getKey(),
+ namespaceToService.getValue(), on))
+ continue;
+
+ String refName = services.getNewDefaultRefName(namespaceToService.getKey(), namespaceToService.getValue(),
+ module, instance);
+ ta.saveServiceReference(
+ ta.getServiceInterfaceName(namespaceToService.getKey(), namespaceToService.getValue()), refName, on);
+ }
+ }
@Override
- void executeStrategy(Map<String, AttributeConfigElement> configuration, ConfigTransactionClient ta, ObjectName on) {
+ void executeStrategy(Map<String, AttributeConfigElement> configuration, ConfigTransactionClient ta, ObjectName on, Services services) {
for (Entry<String, AttributeConfigElement> configAttributeEntry : configuration.entrySet()) {
try {
AttributeConfigElement ace = configAttributeEntry.getValue();
import com.google.common.collect.Maps;
import org.opendaylight.controller.config.util.ConfigRegistryClient;
+import org.opendaylight.controller.config.util.ConfigTransactionClient;
import org.opendaylight.controller.config.yang.store.api.YangStoreSnapshot;
import org.opendaylight.controller.config.yangjmxgenerator.ModuleMXBeanEntry;
import org.opendaylight.controller.config.yangjmxgenerator.RuntimeBeanEntry;
import org.opendaylight.controller.netconf.confignetconfconnector.operations.AbstractConfigNetconfOperation;
import org.opendaylight.controller.netconf.confignetconfconnector.operations.Datastore;
import org.opendaylight.controller.netconf.confignetconfconnector.operations.getconfig.GetConfig;
+import org.opendaylight.controller.netconf.confignetconfconnector.transactions.TransactionProvider;
import org.opendaylight.controller.netconf.util.xml.XmlElement;
import org.opendaylight.controller.netconf.util.xml.XmlNetconfConstants;
import org.slf4j.Logger;
private final YangStoreSnapshot yangStoreSnapshot;
private static final Logger logger = LoggerFactory.getLogger(Get.class);
+ private final TransactionProvider transactionProvider;
public Get(YangStoreSnapshot yangStoreSnapshot, ConfigRegistryClient configRegistryClient,
- String netconfSessionIdForReporting) {
+ String netconfSessionIdForReporting, TransactionProvider transactionProvider) {
super(configRegistryClient, netconfSessionIdForReporting);
this.yangStoreSnapshot = yangStoreSnapshot;
+ this.transactionProvider = transactionProvider;
}
private Map<String, Map<String, ModuleRuntime>> createModuleRuntimes(ConfigRegistryClient configRegistryClient,
final Runtime runtime = new Runtime(moduleRuntimes, moduleConfigs);
- final Element element = runtime.toXml(runtimeBeans, configBeans, document);
+ ObjectName txOn = transactionProvider.getOrCreateTransaction();
+ ConfigTransactionClient ta = configRegistryClient.getConfigTransactionClient(txOn);
+ final Element element = runtime.toXml(runtimeBeans, configBeans, document, ta);
logger.info("{} operation successful", XmlNetconfConstants.GET);
import com.google.common.base.Optional;
import com.google.common.collect.Maps;
import org.opendaylight.controller.config.util.ConfigRegistryClient;
+import org.opendaylight.controller.config.util.ConfigTransactionClient;
import org.opendaylight.controller.config.yang.store.api.YangStoreSnapshot;
import org.opendaylight.controller.config.yangjmxgenerator.ModuleMXBeanEntry;
import org.opendaylight.controller.netconf.api.NetconfDocumentedException;
import org.opendaylight.controller.netconf.confignetconfconnector.mapping.config.Config;
import org.opendaylight.controller.netconf.confignetconfconnector.mapping.config.InstanceConfig;
import org.opendaylight.controller.netconf.confignetconfconnector.mapping.config.ModuleConfig;
+import org.opendaylight.controller.netconf.confignetconfconnector.mapping.config.Services;
import org.opendaylight.controller.netconf.confignetconfconnector.operations.AbstractConfigNetconfOperation;
import org.opendaylight.controller.netconf.confignetconfconnector.operations.Datastore;
import org.opendaylight.controller.netconf.confignetconfconnector.transactions.TransactionProvider;
final Config configMapping = new Config(transform(configRegistryClient,
yangStoreSnapshot.getModuleMXBeanEntryMap()));
- dataElement = configMapping.toXml(instances, this.maybeNamespace, document, dataElement);
+
+
+ ObjectName on = transactionProvider.getOrCreateTransaction();
+ ConfigTransactionClient ta = configRegistryClient.getConfigTransactionClient(on);
+
+ Services serviceTracker = new Services(ta);
+ dataElement = configMapping.toXml(instances, this.maybeNamespace, document, dataElement, serviceTracker);
logger.info("{} operation successful", GET_CONFIG);
ops.add(new EditConfig(yangStoreSnapshot, transactionProvider, configRegistryClient,
netconfSessionIdForReporting));
ops.add(new Commit(transactionProvider, configRegistryClient, netconfSessionIdForReporting));
- ops.add(new Get(yangStoreSnapshot, configRegistryClient, netconfSessionIdForReporting));
+ ops.add(new Get(yangStoreSnapshot, configRegistryClient, netconfSessionIdForReporting, transactionProvider));
ops.add(new DiscardChanges(transactionProvider, configRegistryClient, netconfSessionIdForReporting));
ops.add(new Validate(transactionProvider, configRegistryClient, netconfSessionIdForReporting));
ops.add(new RuntimeRpc(yangStoreSnapshot, configRegistryClient, netconfSessionIdForReporting));
}
/**
- * Wiping means removing all module instances keeping the transaction open.
+ * Wiping means removing all module instances keeping the transaction open + service references.
*/
synchronized void wipeInternal(ObjectName taON, boolean isTest, String moduleName) {
ConfigTransactionClient transactionClient = configRegistryClient.getConfigTransactionClient(taON);
Set<ObjectName> lookupConfigBeans = moduleName == null ? transactionClient.lookupConfigBeans()
: transactionClient.lookupConfigBeans(moduleName);
+ int i = lookupConfigBeans.size();
for (ObjectName instance : lookupConfigBeans) {
try {
transactionClient.destroyModule(instance);
throw new IllegalStateException("Unable to clean configuration in transactiom " + taON, e);
}
}
- logger.debug("Transaction {} wiped clean", taON);
+ logger.debug("Transaction {} wiped clean of {} config beans", taON, i);
+
+ transactionClient.removeAllServiceReferences();
+ logger.debug("Transaction {} wiped clean of all service references", taON);
}
public void wipeTransaction() {
import com.google.common.base.Preconditions;
import com.google.common.collect.Lists;
import com.google.common.collect.Maps;
+import org.apache.commons.lang3.StringUtils;
import org.junit.Before;
import org.junit.Ignore;
import org.junit.Test;
import org.junit.matchers.JUnitMatchers;
import org.mockito.Mock;
import org.mockito.MockitoAnnotations;
+import org.opendaylight.controller.config.api.annotations.AbstractServiceInterface;
+import org.opendaylight.controller.config.api.annotations.ServiceInterfaceAnnotation;
import org.opendaylight.controller.config.manager.impl.AbstractConfigTest;
import org.opendaylight.controller.config.manager.impl.factoriesresolver.HardcodedModuleFactoriesResolver;
import org.opendaylight.controller.config.util.ConfigTransactionJMXClient;
import org.slf4j.LoggerFactory;
import org.w3c.dom.Document;
import org.w3c.dom.Element;
+import org.w3c.dom.NodeList;
import org.xml.sax.SAXException;
import javax.management.InstanceAlreadyExistsException;
+import javax.management.InstanceNotFoundException;
import javax.management.ObjectName;
import javax.xml.parsers.ParserConfigurationException;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.InputStream;
import java.math.BigInteger;
+import java.net.URISyntaxException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
public class NetconfMappingTest extends AbstractConfigTest {
private static final Logger logger = LoggerFactory.getLogger(NetconfMappingTest.class);
- private static final String INSTANCE_NAME = "test1";
+ private static final String INSTANCE_NAME = "instance-from-code";
private static final String NETCONF_SESSION_ID = "foo";
private NetconfTestImplModuleFactory factory;
private DepTestImplModuleFactory factory2;
transactionProvider = new TransactionProvider(this.configRegistryClient, NETCONF_SESSION_ID);
}
- private ObjectName createModule(final String instanceName) throws InstanceAlreadyExistsException {
+ private ObjectName createModule(final String instanceName) throws InstanceAlreadyExistsException, InstanceNotFoundException, URISyntaxException {
final ConfigTransactionJMXClient transaction = this.configRegistryClient.createTransaction();
final ObjectName on = transaction.createModule(this.factory.getImplementationName(), instanceName);
final NetconfTestImplModuleMXBean mxBean = transaction.newMXBeanProxy(on, NetconfTestImplModuleMXBean.class);
- setModule(mxBean, transaction);
+ setModule(mxBean, transaction, instanceName + "_dep");
+ int i = 1;
+ for (Class<? extends AbstractServiceInterface> sInterface : factory.getImplementedServiceIntefaces()) {
+ ServiceInterfaceAnnotation annotation = sInterface.getAnnotation(ServiceInterfaceAnnotation.class);
+ transaction.saveServiceReference(
+ transaction.getServiceInterfaceName(annotation.namespace(), annotation.localName()), "ref_from_code_to_" + instanceName + "_" + i++,
+ on);
+
+ }
transaction.commit();
return on;
}
+ @Test
+ public void testServicePersistance() throws Exception {
+ createModule(INSTANCE_NAME);
+
+ edit("netconfMessages/editConfig.xml");
+ Element config = getConfigCandidate();
+ assertCorrectServiceNames(config, 6, "ref_test2", "user_to_instance_from_code", "ref_dep_user",
+ "ref_dep_user_two", "ref_from_code_to_instance-from-code_dep_1",
+ "ref_from_code_to_instance-from-code_1");
+
+ edit("netconfMessages/editConfig_addServiceName.xml");
+ config = getConfigCandidate();
+ assertCorrectServiceNames(config, 7, "ref_test2", "user_to_instance_from_code", "ref_dep_user",
+ "ref_dep_user_two", "ref_from_code_to_instance-from-code_dep_1",
+ "ref_from_code_to_instance-from-code_1", "ref_dep_user_another");
+
+ commit();
+ config = getConfigRunning();
+ assertCorrectRefNamesForDependencies(config);
+ assertCorrectServiceNames(config, 7, "ref_test2", "user_to_instance_from_code", "ref_dep_user",
+ "ref_dep_user_two", "ref_from_code_to_instance-from-code_dep_1",
+ "ref_from_code_to_instance-from-code_1", "ref_dep_user_another");
+
+ edit("netconfMessages/editConfig_replace_default.xml");
+ config = getConfigCandidate();
+ assertCorrectServiceNames(config, 2, "ref_dep", "ref_dep2");
+
+ edit("netconfMessages/editConfig_remove.xml");
+ config = getConfigCandidate();
+ assertCorrectServiceNames(config, 0);
+
+ commit();
+ config = getConfigCandidate();
+ assertCorrectServiceNames(config, 0);
+
+ }
+
+ private void assertCorrectRefNamesForDependencies(Element config) {
+ NodeList modulesList = config.getElementsByTagName("modules");
+ assertEquals(1, modulesList.getLength());
+
+ Element modules = (Element) modulesList.item(0);
+
+ String trimmedModules = XmlUtil.toString(modules).replaceAll("\\s", "");
+ int defaultRefNameCount = StringUtils.countMatches(trimmedModules, "ref_dep2");
+ int userRefNameCount = StringUtils.countMatches(trimmedModules, "ref_dep_user_two");
+
+ assertEquals(0, defaultRefNameCount);
+ assertEquals(2, userRefNameCount);
+ }
+
+ private void assertCorrectServiceNames(Element configCandidate, int servicesSize, String... refNames) {
+ NodeList elements = configCandidate.getElementsByTagName("provider");
+ assertEquals(servicesSize, elements.getLength());
+
+ NodeList servicesList = configCandidate.getElementsByTagName("services");
+ assertEquals(1, servicesList.getLength());
+
+ Element services = (Element) servicesList.item(0);
+ String trimmedServices = XmlUtil.toString(services).replaceAll("\\s", "");
+
+ for (String s : refNames) {
+ assertThat(trimmedServices, JUnitMatchers.containsString(s));
+ }
+ }
+
@Test
public void testConfigNetconf() throws Exception {
createModule(INSTANCE_NAME);
edit("netconfMessages/editConfig.xml");
- checkBinaryLeafEdited(getConfigCandidate());
+ Element configCandidate = getConfigCandidate();
+ checkBinaryLeafEdited(configCandidate);
// default-operation:none, should not affect binary leaf
return executeOp(getConfigOp, "netconfMessages/getConfig.xml");
}
+ @Ignore("second edit message corrupted")
@Test(expected = NetconfDocumentedException.class)
public void testConfigNetconfReplaceDefaultEx() throws Exception {
for (XmlElement moduleElement : modulesElement.getChildElements("module")) {
String name = moduleElement.getOnlyChildElement("name").getTextContent();
- if(name.equals("test1")) {
+ if(name.equals(INSTANCE_NAME)) {
XmlElement enumAttr = moduleElement.getOnlyChildElement(enumName);
assertEquals(enumContent, enumAttr.getTextContent());
}
}
- assertEquals("configAttributeType", configAttributeType.getTextContent());
+ // TODO verify if should be default value
+ assertEquals("default-string", configAttributeType.getTextContent());
}
private Map<String, Map<String, ModuleMXBeanEntry>> getMbes() throws Exception {
}
private Element get() throws NetconfDocumentedException, ParserConfigurationException, SAXException, IOException {
- Get getOp = new Get(yangStoreSnapshot, configRegistryClient, NETCONF_SESSION_ID);
+ Get getOp = new Get(yangStoreSnapshot, configRegistryClient, NETCONF_SESSION_ID, transactionProvider);
return executeOp(getOp, "netconfMessages/get.xml");
}
return Lists.newArrayList(yangDependencies);
}
- private void setModule(final NetconfTestImplModuleMXBean mxBean, final ConfigTransactionJMXClient transaction)
- throws InstanceAlreadyExistsException {
+ private void setModule(final NetconfTestImplModuleMXBean mxBean, final ConfigTransactionJMXClient transaction, String depName)
+ throws InstanceAlreadyExistsException, InstanceNotFoundException {
mxBean.setSimpleInt((long) 44);
mxBean.setBinaryLeaf(new byte[] { 8, 7, 9 });
final DtoD dtob = getDtoD();
mxBean.setComplexList(Lists.<ComplexList> newArrayList());
mxBean.setSimpleList(Lists.<Integer> newArrayList());
- final ObjectName testingDepOn = transaction.createModule(this.factory2.getImplementationName(), "dep");
+ final ObjectName testingDepOn = transaction.createModule(this.factory2.getImplementationName(), depName);
+ int i = 1;
+ for (Class<? extends AbstractServiceInterface> sInterface : factory2.getImplementedServiceIntefaces()) {
+ ServiceInterfaceAnnotation annotation = sInterface.getAnnotation(ServiceInterfaceAnnotation.class);
+ transaction.saveServiceReference(
+ transaction.getServiceInterfaceName(annotation.namespace(), annotation.localName()), "ref_from_code_to_" + depName + "_" + i++,
+ testingDepOn);
+
+ }
mxBean.setTestingDep(testingDepOn);
}
import org.opendaylight.controller.netconf.confignetconfconnector.mapping.config.Services.ServiceInstance;
import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertTrue;
public class ServiceTrackerTest {
assertEquals(serviceInstance, serviceInstance2);
}
- @Test
- public void testOneInstanceMultipleServices() {
- Services services = new Services();
- services.addServiceEntry("nm", "s1", "module", "instance");
- assertEquals(1, services.getMappedServices().size());
-
- services.addServiceEntry("nm2", "s2", "module", "instance");
- assertEquals(2, services.getMappedServices().size());
- }
-
- @Test
- public void testMultipleInstancesOneName() throws Exception {
- Services services = new Services();
- services.addServiceEntry("nm", "s1", "module", "instance");
- assertEquals(1, services.getMappedServices().size());
-
- services.addServiceEntry("nm", "s1", "module2", "instance");
- assertEquals(1, services.getMappedServices().size());
- assertEquals(2, services.getMappedServices().get("nm").get("s1").size());
- assertTrue(services.getMappedServices().get("nm").get("s1").containsKey("ref_instance"));
- assertTrue(services.getMappedServices().get("nm").get("s1").containsKey("ref_instance_1"));
- }
-
- @Test
- public void testMultipleInstancesOneName2() throws Exception {
- Services services = new Services();
- services.addServiceEntry("nm", "s1", "module", "instance_1");
-
- services.addServiceEntry("nm2", "s2", "module2", "instance");
- services.addServiceEntry("nm2", "s2", "module3", "instance");
- services.addServiceEntry("nm", "s1", "module3", "instance");
-
- assertEquals(2, services.getMappedServices().get("nm").get("s1").size());
- assertEquals(2, services.getMappedServices().get("nm2").get("s2").size());
- assertTrue(services.getMappedServices().get("nm").get("s1").containsKey("ref_instance_2"));
- assertTrue(services.getMappedServices().get("nm").get("s1").containsKey("ref_instance_1"));
- assertTrue(services.getMappedServices().get("nm2").get("s2").containsKey("ref_instance"));
- assertTrue(services.getMappedServices().get("nm2").get("s2").containsKey("ref_instance_2"));
- }
-
}
import org.junit.Test;
import org.mockito.Mock;
import org.mockito.MockitoAnnotations;
+import org.opendaylight.controller.config.api.ServiceReferenceReadableRegistry;
import org.opendaylight.controller.config.util.ConfigRegistryClient;
import org.opendaylight.controller.config.util.ConfigTransactionClient;
import org.opendaylight.controller.config.yang.store.api.YangStoreSnapshot;
import org.opendaylight.controller.netconf.api.NetconfDocumentedException;
import org.opendaylight.controller.netconf.confignetconfconnector.mapping.attributes.fromxml.AttributeConfigElement;
-import org.opendaylight.controller.netconf.confignetconfconnector.mapping.config.Config;
import org.opendaylight.controller.netconf.confignetconfconnector.mapping.config.InstanceConfigElementResolved;
import org.opendaylight.controller.netconf.confignetconfconnector.mapping.config.ModuleElementResolved;
+import org.opendaylight.controller.netconf.confignetconfconnector.mapping.config.Services;
import org.opendaylight.controller.netconf.confignetconfconnector.operations.ValidateTest;
import org.opendaylight.controller.netconf.confignetconfconnector.operations.editconfig.EditConfigXmlParser.EditConfigExecution;
import org.opendaylight.controller.netconf.confignetconfconnector.transactions.TransactionProvider;
-import org.opendaylight.controller.netconf.util.xml.XmlElement;
import org.opendaylight.controller.netconf.util.xml.XmlUtil;
import javax.management.ObjectName;
import java.util.Collections;
import java.util.Map;
-import java.util.Set;
import static org.mockito.Matchers.any;
import static org.mockito.Matchers.anyMap;
EditConfig edit = new EditConfig(yangStoreSnapshot, provider, configRegistry,
ValidateTest.NETCONF_SESSION_ID_FOR_REPORTING);
EditConfigStrategy editStrat = mock(EditConfigStrategy.class);
- doNothing().when(editStrat).executeConfiguration(anyString(), anyString(), anyMap(),
- any(ConfigTransactionClient.class));
- Map<String, Multimap<String, ModuleElementResolved>> resolvedXmlElements = getMapping(editStrat);
- Config cfg = mock(Config.class);
- XmlElement xmlElement = mock(XmlElement.class);
- Set<ObjectName> instancesForFillingServiceRefMapping = Collections.emptySet();
- EditStrategyType defaultStrategy = EditStrategyType.getDefaultStrategy();
- doReturn(resolvedXmlElements).when(cfg).fromXml(xmlElement, instancesForFillingServiceRefMapping, defaultStrategy);
+ doNothing().when(editStrat).executeConfiguration(anyString(), anyString(), anyMap(),
+ any(ConfigTransactionClient.class), any(Services.class));
- EditConfigExecution editConfigExecution = new EditConfigExecution(null, cfg, xmlElement,
- EditConfigXmlParser.TestOption.testThenSet, instancesForFillingServiceRefMapping, defaultStrategy);
+ EditConfigExecution editConfigExecution = mockExecution(editStrat);
edit.getResponseInternal(XmlUtil.newDocument(), editConfigExecution);
// For every instance execute strat
verify(editStrat, times(2/* Test */+ 2/* Set */)).executeConfiguration(anyString(), anyString(), anyMap(),
- any(ConfigTransactionClient.class));
+ any(ConfigTransactionClient.class), any(Services.class));
+ }
+
+ private EditConfigExecution mockExecution(EditConfigStrategy editStrat) {
+ EditConfigExecution mock = mock(EditConfigExecution.class);
+ doReturn(getMapping(editStrat)).when(mock).getResolvedXmlElements();
+ doReturn(EditStrategyType.merge).when(mock).getDefaultStrategy();
+ doReturn(true).when(mock).shouldSet();
+ doReturn(true).when(mock).shouldTest();
+ doReturn(mockServices()).when(mock).getServices();
+ return mock;
+ }
+
+ private static ServiceReferenceReadableRegistry mockServiceRegistry() {
+ ServiceReferenceReadableRegistry mock = mock(ServiceReferenceReadableRegistry.class);
+ doReturn(
+ Collections.emptyMap())
+ .when(mock).getServiceMapping();
+ doReturn("mockedServiceReg").when(mock).toString();
+
+ return mock;
+ }
+
+ static Services mockServices() {
+ return new Services(mockServiceRegistry());
}
private Map<String, Multimap<String, ModuleElementResolved>> getMapping(EditConfigStrategy editStrat) {
doReturn(Sets.newHashSet(mockON(), mockON())).when(ta).lookupConfigBeans();
- strat.executeConfiguration("m1", "i1", map, ta);
+ strat.executeConfiguration("m1", "i1", map, ta, EditConfigTest.mockServices());
verify(ta).lookupConfigBean(anyString(), anyString());
verify(ta).setAttribute(any(ObjectName.class), anyString(), any(Attribute.class));
NetconfMessage message = createEditConfigMessage(xmlToBePersisted, "/netconfOp/editConfig.xml");
// sending message to netconf
- NetconfMessage responseMessage = netconfClient.sendMessage(message, NETCONF_SEND_ATTEMPTS, NETCONF_SEND_ATTEMPT_MS_DELAY);
+ NetconfMessage responseMessage = getResponse(message, netconfClient);
XmlElement element = XmlElement.fromDomDocument(responseMessage.getDocument());
Preconditions.checkState(element.getName().equals(XmlNetconfConstants.RPC_REPLY_KEY));
Util.checkIsOk(element, responseMessage);
response.append(XmlUtil.toString(responseMessage.getDocument()));
response.append("}");
- responseMessage = netconfClient.sendMessage(getNetconfMessageFromResource("/netconfOp/commit.xml"), NETCONF_SEND_ATTEMPTS, NETCONF_SEND_ATTEMPT_MS_DELAY);
+ responseMessage = getResponse(getNetconfMessageFromResource("/netconfOp/commit.xml"), netconfClient);
element = XmlElement.fromDomDocument(responseMessage.getDocument());
Preconditions.checkState(element.getName().equals(XmlNetconfConstants.RPC_REPLY_KEY));
logger.trace("Detailed message {}", response);
}
+ private static NetconfMessage getResponse(NetconfMessage request, NetconfClient netconfClient) {
+ try {
+ return netconfClient.sendMessage(request, NETCONF_SEND_ATTEMPTS, NETCONF_SEND_ATTEMPT_MS_DELAY);
+ } catch(RuntimeException e) {
+ logger.error("Error while sending message {} to {}", request, netconfClient);
+ throw e;
+ }
+ }
+
private static NetconfMessage createEditConfigMessage(Element dataElement, String editConfigResourcename) {
try (InputStream stream = ConfigPersisterNotificationHandler.class.getResourceAsStream(editConfigResourcename)) {
Preconditions.checkNotNull(stream, "Unable to load resource " + editConfigResourcename);
}
public NetconfMessage sendMessage(NetconfMessage message, int attempts, int attemptMsDelay) {
+ long startTime = System.currentTimeMillis();
Preconditions.checkState(clientSession.isUp(), "Session was not up yet");
clientSession.sendMessage(message);
try {
throw new RuntimeException(this + " Cannot read message from " + address, e);
} catch (IllegalStateException e) {
throw new IllegalStateException(this + " Cannot read message from " + address, e);
+ } finally {
+ long diffMillis = System.currentTimeMillis() - startTime;
+ logger.debug("Total time spent waiting for response {}", diffMillis);
}
}
<modules xmlns="urn:opendaylight:params:xml:ns:yang:controller:config">
<module>
- <name>dep</name>
+ <name>instance-from-code_dep</name>
<type xmlns:test-impl="urn:opendaylight:params:xml:ns:yang:controller:test:impl">
test-impl:impl-dep
</type>
test-impl:impl-netconf
</type>
- <name>test1</name>
+ <name>instance-from-code</name>
<sleep-factor>
2.58
</peers>
<testing-dep>
<type xmlns:prefix="urn:opendaylight:params:xml:ns:yang:controller:test">prefix:testing</type>
- <name>ref_dep</name>
+ <name>ref_dep_user</name>
</testing-dep>
<testing-deps>
<type xmlns:prefix="urn:opendaylight:params:xml:ns:yang:controller:test">prefix:testing</type>
- <name>ref_dep</name>
+ <name>ref_dep_user</name>
</testing-deps>
<testing-deps>
<type xmlns:prefix="urn:opendaylight:params:xml:ns:yang:controller:test">prefix:testing</type>
- <name>ref_dep_2</name>
+ <name>ref_dep_user_two</name>
</testing-deps>
</module>
<testing-dep>
<type xmlns:prefix="urn:opendaylight:params:xml:ns:yang:controller:test">prefix:testing</type>
- <name>ref_dep_2</name>
+ <name>ref_dep_user_two</name>
</testing-dep>
</module>
</modules>
<service>
<type xmlns:prefix="urn:opendaylight:params:xml:ns:yang:controller:test">prefix:testing</type>
<instance>
- <name>ref_dep</name>
- <provider>/modules/module[type='impl-dep'][name='dep']
+ <name>ref_dep_user</name>
+ <provider>/modules/module[type='impl-dep'][name='instance-from-code_dep']
</provider>
</instance>
<instance>
- <name>ref_dep_2</name>
+ <name>ref_dep_user_two</name>
<provider>/config/modules/module[name='impl-dep']/instance[name='dep2']
</provider>
</instance>
<instance>
- <name>ref_test1</name>
+ <name>user_to_instance_from_code</name>
<provider>
- /modules/module[type='impl-netconf'][name='test1']
+ /modules/module[type='impl-netconf'][name='instance-from-code']
</provider>
</instance>
</service>
--- /dev/null
+<rpc message-id="a" a="64" xmlns="urn:ietf:params:xml:ns:netconf:base:1.0">
+ <edit-config>
+ <target>
+ <candidate/>
+ </target>
+ <test-option>
+ set
+ </test-option>
+ <default-operation>merge</default-operation>
+ <config>
+ <modules xmlns="urn:opendaylight:params:xml:ns:yang:controller:config">
+
+ <module>
+ <name>instance-from-code_dep</name>
+ <type xmlns:test-impl="urn:opendaylight:params:xml:ns:yang:controller:test:impl">
+ test-impl:impl-dep
+ </type>
+ </module>
+
+ </modules>
+
+ <services xmlns="urn:opendaylight:params:xml:ns:yang:controller:config">
+ <service>
+ <type xmlns:prefix="urn:opendaylight:params:xml:ns:yang:controller:test">prefix:testing</type>
+ <instance>
+ <name>ref_dep_user_another</name>
+ <provider>/modules/module[type='impl-dep'][name='instance-from-code_dep']
+ </provider>
+ </instance>
+ </service>
+ </services>
+ </config>
+ </edit-config>
+</rpc>
-<?xml version="1.0" encoding="UTF-8"?>
+<?xml version="1.0" encoding="UTF-8" ?>
<rpc message-id="6"
xmlns="urn:ietf:params:xml:ns:netconf:base:1.0">
<edit-config xmlns="urn:ietf:params:xml:ns:netconf:base:1.0">
</name-prefix>
</module>
</modules>
+ <services xmlns="urn:opendaylight:params:xml:ns:yang:controller:config">
+ <service>
+ <type xmlns:prefix="urn:opendaylight:params:xml:ns:yang:controller:threadpool:impl">prefix:threadfactory</type>
+ <instance>
+ <name>user_to_instance_from_code</name>
+ <provider>
+ /modules/module[type='threadfactory-naming'][name='threadfactory-naming-instance']</provider>
+ </instance>
+ </service>
+ </services>
</config>
</edit-config>
</rpc>
<config>
<modules xmlns="urn:opendaylight:params:xml:ns:yang:controller:config">
<module>
- <name>dep</name>
+ <name>instance-from-code_dep</name>
<type xmlns:test-impl="urn:opendaylight:params:xml:ns:yang:controller:test:impl">
test-impl:impl-dep
</type>
</type>
</module>
+
<module>
<type xmlns:test-impl="urn:opendaylight:params:xml:ns:yang:controller:test:impl">
test-impl:impl-netconf
<simple-int3>456</simple-int3>
<core-size>44</core-size>
</peers>
- <testing-dep>
- <type xmlns:prefix="urn:opendaylight:params:xml:ns:yang:controller:test">prefix:testing</type>
- <name>ref_dep</name>
- </testing-dep>
</module>
<module>
<type xmlns:test-impl="urn:opendaylight:params:xml:ns:yang:controller:test:impl">
test-impl:impl-netconf
</type>
<name>test2</name>
- <testing-dep>
- <type xmlns:prefix="urn:opendaylight:params:xml:ns:yang:controller:test">prefix:testing</type>
- <name>ref_dep</name>
- </testing-dep>
</module>
</modules>
+
<services xmlns="urn:opendaylight:params:xml:ns:yang:controller:config">
- <service>
- <type xmlns:prefix="urn:opendaylight:params:xml:ns:yang:controller:test">prefix:testing</type>
- <instance>
- <name>ref_dep</name>
- <provider>/modules/module[type='impl-dep'][name='dep']
- </provider>
- </instance>
- <instance>
- <name>ref_dep_2</name>
- <provider>/modules/module[type='impl-dep'][name='dep2']
- </provider>
- </instance>
- <instance>
- <name>ref_test1</name>
- <provider>
- /modules/module[type='impl-netconf'][name='test1']
- </provider>
- </instance>
- </service>
</services>
</config>
</edit-config>
<default-operation>none</default-operation>
<config>
<modules xmlns="urn:opendaylight:params:xml:ns:yang:controller:config">
+ <module xmlns:nc="urn:ietf:params:xml:ns:netconf:base:1.0"
+ nc:operation="remove">
+ <name>instance-from-code_dep</name>
+ <type xmlns:test-impl="urn:opendaylight:params:xml:ns:yang:controller:test:impl">
+ test-impl:impl-dep
+ </type>
+ </module>
+
+
<module xmlns:nc="urn:ietf:params:xml:ns:netconf:base:1.0"
nc:operation="remove">
<name>dep</name>
<type xmlns:test-impl="urn:opendaylight:params:xml:ns:yang:controller:test:impl">
test-impl:impl-netconf
</type>
- <name>test1</name>
+ <name>instance-from-code</name>
</module>
<module xmlns:nc="urn:ietf:params:xml:ns:netconf:base:1.0"
<rpc message-id="a" a="64" xmlns="urn:ietf:params:xml:ns:netconf:base:1.0">
<no-arg xmlns="urn:opendaylight:params:xml:ns:yang:controller:test:impl">
- <context-instance>/modules/module[type='impl-netconf' and name='test1']</context-instance>
+ <context-instance>/modules/module[type='impl-netconf' and name='instance-from-code']</context-instance>
<arg1>
testarg1
</arg1>
<rpc message-id="a" a="64" xmlns="urn:ietf:params:xml:ns:netconf:base:1.0">
<noArgInner xmlns="urn:opendaylight:params:xml:ns:yang:controller:test:impl">
<context-instance>
- /modules/module[name='test1'][type='impl-netconf']/inner-running-data-additional[key='1']
+ /modules/module[name='instance-from-code'][type='impl-netconf']/inner-running-data-additional[key='1']
</context-instance>
</noArgInner>
</rpc>
<leaf-list-output
xmlns="urn:opendaylight:params:xml:ns:yang:controller:test:impl">
<context-instance>
- /modules/module[type='impl-netconf'][name='test1']/inner-running-data[key='0']/inner-inner-running-data[key='1']
+ /modules/module[type='impl-netconf'][name='instance-from-code']/inner-running-data[key='0']/inner-inner-running-data[key='1']
</context-instance>
</leaf-list-output>
</rpc>
<module>opendaylight/commons/opendaylight</module>
<module>opendaylight/commons/parent</module>
<module>opendaylight/commons/logback_settings</module>
+ <module>opendaylight/commons/controller-maven-plugin</module>
</modules>
<profiles>
<module>opendaylight/statisticsmanager/integrationtest</module>
<module>opendaylight/commons/integrationtest</module>
<module>opendaylight/containermanager/it.implementation</module>
- <module>opendaylight/distribution/sanitytest/</module>
</modules>
</profile>
<profile>