bug #56: Initial commit to repo of affinity classes. 15/915/1
authorSuchi Raman <suchi.raman@plexxi.com>
Mon, 19 Aug 2013 19:43:20 +0000 (15:43 -0400)
committerSuchi Raman <suchi.raman@plexxi.com>
Mon, 19 Aug 2013 19:43:20 +0000 (15:43 -0400)
Signed-off-by: Suchi Raman <suchi.raman@plexxi.com>
42 files changed:
.gitignore [new file with mode: 0644]
affinity/api/.classpath [new file with mode: 0644]
affinity/api/.project [new file with mode: 0644]
affinity/api/.settings/org.eclipse.core.resources.prefs [new file with mode: 0644]
affinity/api/.settings/org.eclipse.jdt.core.prefs [new file with mode: 0644]
affinity/api/.settings/org.eclipse.m2e.core.prefs [new file with mode: 0644]
affinity/api/META-INF/MANIFEST.MF [new file with mode: 0644]
affinity/api/pom.xml [new file with mode: 0644]
affinity/api/src/main/java/org/opendaylight/controller/affinity/AffinityConfig.java [new file with mode: 0644]
affinity/api/src/main/java/org/opendaylight/controller/affinity/IAffinityManager.java [new file with mode: 0644]
affinity/api/src/main/java/org/opendaylight/controller/affinity/IAffinityManagerAware.java [new file with mode: 0644]
affinity/implementation/.classpath [new file with mode: 0644]
affinity/implementation/.project [new file with mode: 0644]
affinity/implementation/.settings/org.eclipse.core.resources.prefs [new file with mode: 0644]
affinity/implementation/.settings/org.eclipse.jdt.core.prefs [new file with mode: 0644]
affinity/implementation/.settings/org.eclipse.m2e.core.prefs [new file with mode: 0644]
affinity/implementation/META-INF/MANIFEST.MF [new file with mode: 0644]
affinity/implementation/pom.xml [new file with mode: 0644]
affinity/implementation/src/main/java/org/opendaylight/controller/affinity/internal/Activator.java [new file with mode: 0644]
affinity/implementation/src/main/java/org/opendaylight/controller/affinity/internal/AffinityManagerImpl.java [new file with mode: 0644]
affinity/implementation/src/test/java/org/opendaylight/controller/affinity/internal/AffinityManagerImplTest.java [new file with mode: 0644]
affinity/implementation/src/test/resources/logback.xml [new file with mode: 0644]
affinity/northbound/enunciate.xml [new file with mode: 0644]
affinity/northbound/pom.xml [new file with mode: 0644]
affinity/northbound/src/main/java/org/opendaylight/controller/affinity/northbound/Affinities.java [new file with mode: 0644]
affinity/northbound/src/main/java/org/opendaylight/controller/affinity/northbound/AffinityNorthbound.java [new file with mode: 0644]
affinity/northbound/src/main/java/org/opendaylight/controller/affinity/northbound/AffinityNorthboundRSApplication.java [new file with mode: 0644]
affinity/northbound/src/main/resources/META-INF/MANIFEST.MF [new file with mode: 0644]
affinity/northbound/src/main/resources/META-INF/spring.factories [new file with mode: 0644]
affinity/northbound/src/main/resources/META-INF/spring.handlers [new file with mode: 0644]
affinity/northbound/src/main/resources/META-INF/spring.schemas [new file with mode: 0644]
affinity/northbound/src/main/resources/META-INF/spring.tooling [new file with mode: 0644]
affinity/northbound/src/main/resources/WEB-INF/web.xml [new file with mode: 0644]
analytics/pom.xml [new file with mode: 0644]
analytics/src/main/java/org/opendaylight/controller/analytics/internal/Activator.java [new file with mode: 0644]
analytics/src/main/java/org/opendaylight/controller/analytics/internal/AnalyticsManager.java [new file with mode: 0644]
analytics/src/test/java/org/opendaylight/controller/analytics/internal/AnalyticsManagerTest.java [new file with mode: 0644]
pom.xml [new file with mode: 0644]
scripts/affinity.py [new file with mode: 0644]
scripts/osgi.txt [new file with mode: 0644]
scripts/stats.py [new file with mode: 0644]
scripts/topo.py [new file with mode: 0644]

diff --git a/.gitignore b/.gitignore
new file mode 100644 (file)
index 0000000..d1b8261
--- /dev/null
@@ -0,0 +1,15 @@
+*.class
+**/target
+**/bin
+dist
+**/logs
+products
+repository
+workspace
+*~
+target
+.classpath
+.project
+.settings
+MANIFEST.MF
+opendaylight/northbound/integrationtest/logs/*
diff --git a/affinity/api/.classpath b/affinity/api/.classpath
new file mode 100644 (file)
index 0000000..fd7ad7f
--- /dev/null
@@ -0,0 +1,26 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<classpath>
+       <classpathentry kind="src" output="target/classes" path="src/main/java">
+               <attributes>
+                       <attribute name="optional" value="true"/>
+                       <attribute name="maven.pomderived" value="true"/>
+               </attributes>
+       </classpathentry>
+       <classpathentry kind="src" output="target/test-classes" path="src/test/java">
+               <attributes>
+                       <attribute name="optional" value="true"/>
+                       <attribute name="maven.pomderived" value="true"/>
+               </attributes>
+       </classpathentry>
+       <classpathentry kind="con" path="org.eclipse.jdt.launching.JRE_CONTAINER/org.eclipse.jdt.internal.debug.ui.launcher.StandardVMType/JavaSE-1.6">
+               <attributes>
+                       <attribute name="maven.pomderived" value="true"/>
+               </attributes>
+       </classpathentry>
+       <classpathentry kind="con" path="org.eclipse.m2e.MAVEN2_CLASSPATH_CONTAINER">
+               <attributes>
+                       <attribute name="maven.pomderived" value="true"/>
+               </attributes>
+       </classpathentry>
+       <classpathentry kind="output" path="target/classes"/>
+</classpath>
diff --git a/affinity/api/.project b/affinity/api/.project
new file mode 100644 (file)
index 0000000..35e626e
--- /dev/null
@@ -0,0 +1,23 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<projectDescription>
+       <name>switchmanager</name>
+       <comment></comment>
+       <projects>
+       </projects>
+       <buildSpec>
+               <buildCommand>
+                       <name>org.eclipse.jdt.core.javabuilder</name>
+                       <arguments>
+                       </arguments>
+               </buildCommand>
+               <buildCommand>
+                       <name>org.eclipse.m2e.core.maven2Builder</name>
+                       <arguments>
+                       </arguments>
+               </buildCommand>
+       </buildSpec>
+       <natures>
+               <nature>org.eclipse.jdt.core.javanature</nature>
+               <nature>org.eclipse.m2e.core.maven2Nature</nature>
+       </natures>
+</projectDescription>
diff --git a/affinity/api/.settings/org.eclipse.core.resources.prefs b/affinity/api/.settings/org.eclipse.core.resources.prefs
new file mode 100644 (file)
index 0000000..f9fe345
--- /dev/null
@@ -0,0 +1,4 @@
+eclipse.preferences.version=1
+encoding//src/main/java=UTF-8
+encoding//src/test/java=UTF-8
+encoding/<project>=UTF-8
diff --git a/affinity/api/.settings/org.eclipse.jdt.core.prefs b/affinity/api/.settings/org.eclipse.jdt.core.prefs
new file mode 100644 (file)
index 0000000..60105c1
--- /dev/null
@@ -0,0 +1,5 @@
+eclipse.preferences.version=1
+org.eclipse.jdt.core.compiler.codegen.targetPlatform=1.6
+org.eclipse.jdt.core.compiler.compliance=1.6
+org.eclipse.jdt.core.compiler.problem.forbiddenReference=warning
+org.eclipse.jdt.core.compiler.source=1.6
diff --git a/affinity/api/.settings/org.eclipse.m2e.core.prefs b/affinity/api/.settings/org.eclipse.m2e.core.prefs
new file mode 100644 (file)
index 0000000..f897a7f
--- /dev/null
@@ -0,0 +1,4 @@
+activeProfiles=
+eclipse.preferences.version=1
+resolveWorkspaceProjects=true
+version=1
diff --git a/affinity/api/META-INF/MANIFEST.MF b/affinity/api/META-INF/MANIFEST.MF
new file mode 100644 (file)
index 0000000..668433e
--- /dev/null
@@ -0,0 +1,22 @@
+Manifest-Version: 1.0\r
+Bnd-LastModified: 1376940266146\r
+Build-Jdk: 1.6.0_37\r
+Built-By: sraman\r
+Bundle-ManifestVersion: 2\r
+Bundle-Name: affinity\r
+Bundle-SymbolicName: org.opendaylight.controller.affinity\r
+Bundle-Version: 0.4.0.SNAPSHOT\r
+Created-By: Apache Maven Bundle Plugin\r
+Export-Package: org.opendaylight.controller.affinity;uses:="javax.xml.bi\r
+ nd.annotation,org.opendaylight.controller.sal.utils";version="0.4.0.SNA\r
+ PSHOT"\r
+Import-Package: javax.xml.bind.annotation,org.apache.commons.lang3.build\r
+ er;version="[3.1,4)",org.apache.felix.dm;version="[3.0,4)",org.eclipse.\r
+ osgi.framework.console;version="[1.1,2)",org.opendaylight.controller.cl\r
+ ustering.services;version="[0.4,1)",org.opendaylight.controller.configu\r
+ ration;version="[0.4,1)",org.opendaylight.controller.sal.core;version="\r
+ [0.5,1)",org.opendaylight.controller.sal.inventory;version="[0.5,1)",or\r
+ g.opendaylight.controller.sal.packet;version="[0.5,1)",org.opendaylight\r
+ .controller.sal.utils;version="[0.5,1)",org.osgi.framework;version="[1.\r
+ 7,2)",org.slf4j;version="[1.7,2)"\r
+Tool: Bnd-1.50.0\r
diff --git a/affinity/api/pom.xml b/affinity/api/pom.xml
new file mode 100644 (file)
index 0000000..c0ea7e0
--- /dev/null
@@ -0,0 +1,104 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<project xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd" xmlns="http://maven.apache.org/POM/4.0.0"
+    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
+  <modelVersion>4.0.0</modelVersion>
+<!--   <parent>
+    <groupId>org.opendaylight.controller</groupId>
+    <artifactId>affinity</artifactId>
+    <version>1.4.0-SNAPSHOT</version>
+  </parent> -->
+
+  <groupId>org.opendaylight.controller</groupId>
+  <artifactId>affinity</artifactId>
+  <version>0.4.0-SNAPSHOT</version>
+  <packaging>bundle</packaging>
+
+  <properties>
+    <!-- Sonar properties using jacoco to retrieve integration test results -->
+    <sonar.java.coveragePlugin>jacoco</sonar.java.coveragePlugin>
+    <sonar.dynamicAnalysis>reuseReports</sonar.dynamicAnalysis>
+    <sonar.jacoco.Reportpath>target/jacoco.exec</sonar.jacoco.Reportpath>
+    <sonar.jacoco.itReportPath>target/jacoco-it.exec</sonar.jacoco.itReportPath>
+    <sonar.language>java</sonar.language>
+  </properties>
+  <build>
+    <pluginManagement>
+      <plugins>
+        <plugin>
+          <groupId>org.jacoco</groupId>
+          <artifactId>jacoco-maven-plugin</artifactId>
+          <version>0.5.3.201107060350</version>
+        </plugin>
+      </plugins>
+    </pluginManagement>
+    <plugins>
+      <plugin>
+        <groupId>org.apache.felix</groupId>
+        <artifactId>maven-bundle-plugin</artifactId>
+        <version>2.3.6</version>
+        <extensions>true</extensions>
+        <configuration>
+          <instructions>
+            <Export-Package>
+              org.opendaylight.controller.affinity
+            </Export-Package>
+            <Import-Package>
+              org.opendaylight.controller.clustering.services,
+              org.opendaylight.controller.configuration,
+              org.opendaylight.controller.sal.core,
+              org.opendaylight.controller.sal.utils,
+              org.opendaylight.controller.sal.packet,
+              org.opendaylight.controller.sal.inventory,
+              org.slf4j,
+              org.apache.felix.dm,
+              org.eclipse.osgi.framework.console,
+              org.osgi.framework,
+              javax.xml.bind.annotation,
+              org.apache.commons.lang3.builder
+            </Import-Package>
+          </instructions>
+          <manifestLocation>${project.basedir}/META-INF</manifestLocation>
+        </configuration>
+      </plugin>
+      <plugin>
+        <groupId>org.jacoco</groupId>
+        <artifactId>jacoco-maven-plugin</artifactId>
+        <configuration>
+          <includes>org.opendaylight.controller.*</includes>
+        </configuration>
+        <executions>
+          <execution>
+            <id>pre-test</id>
+            <goals>
+              <goal>prepare-agent</goal>
+            </goals>
+          </execution>
+          <execution>
+            <id>post-test</id>
+            <phase>test</phase>
+            <goals>
+              <goal>report</goal>
+            </goals>
+          </execution>
+        </executions>
+      </plugin>
+    </plugins>
+  </build>
+  <dependencies>
+    <dependency>
+      <groupId>org.opendaylight.controller</groupId>
+      <artifactId>clustering.services</artifactId>
+      <version>0.4.0-SNAPSHOT</version>
+    </dependency>
+    <dependency>
+      <groupId>org.opendaylight.controller</groupId>
+      <artifactId>configuration</artifactId>
+      <version>0.4.0-SNAPSHOT</version>
+    </dependency>
+    <dependency>
+      <groupId>org.opendaylight.controller</groupId>
+      <artifactId>sal</artifactId>
+      <version>0.5.0-SNAPSHOT</version>
+    </dependency>
+  </dependencies>
+</project>
diff --git a/affinity/api/src/main/java/org/opendaylight/controller/affinity/AffinityConfig.java b/affinity/api/src/main/java/org/opendaylight/controller/affinity/AffinityConfig.java
new file mode 100644 (file)
index 0000000..26e1e00
--- /dev/null
@@ -0,0 +1,135 @@
+
+/*
+ * Copyright (c) 2013 Plexxi, 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.affinity;
+
+import java.io.Serializable;
+import java.net.InetAddress;
+import java.net.UnknownHostException;
+import java.util.ArrayList;
+import java.util.List;
+
+import javax.xml.bind.annotation.XmlAccessType;
+import javax.xml.bind.annotation.XmlAccessorType;
+import javax.xml.bind.annotation.XmlAttribute;
+import javax.xml.bind.annotation.XmlRootElement;
+
+//import org.opendaylight.controller.sal.utils;
+
+/**
+ * The class represents an affinity configuration.
+ */
+@XmlRootElement
+@XmlAccessorType(XmlAccessType.NONE)
+public class AffinityConfig implements Cloneable, Serializable {
+    //static fields are by default excluded by Gson parser
+    private static final long serialVersionUID = 1L;
+
+    /*    private static final String affinityFields[] = { GUIField.NAME.toString(),
+                                                    GUIField.AFFINITYFROM.toString(), 
+                                                    GUIField.AFFINITYTO.toString(), 
+                                                    GUIField.AFFINITYTYPE.toString() };
+    */
+
+    // Order matters: JSP file expects following fields in the
+    // following order
+    @XmlAttribute
+    private String name;
+    @XmlAttribute
+    private String fromIp; // A.B.C.D
+    private String toIp; // A.B.C.D
+    private String affinityType;
+
+    public AffinityConfig() {
+    }
+
+    public AffinityConfig(String desc, String from, String to, String aType) {
+        name = desc;
+        fromIp = from;
+        toIp = to;
+        affinityType = aType;
+    }
+
+    public AffinityConfig(AffinityConfig ac) {
+        name = ac.name;
+        fromIp = ac.fromIp;
+        toIp = ac.toIp;
+        affinityType = ac.affinityType;
+    }
+
+    public String getName() {
+        return name;
+    }
+    public InetAddress getFromIP() {
+        InetAddress ip = null;
+        try {
+            ip = InetAddress.getByName(fromIp);
+        } catch (UnknownHostException e1) {
+            return null;
+        }
+        return ip;
+    }
+
+    public InetAddress getToIP() {
+        InetAddress ip = null;
+        try {
+            ip = InetAddress.getByName(toIp);
+        } catch (UnknownHostException e1) {
+            return null;
+        }
+        return ip;
+    }
+
+    @Override
+    public int hashCode() {
+        return name.hashCode();
+    }
+
+    @Override
+    public boolean equals(Object obj) {
+        /*
+         * Configuration will be stored in collection only if it is valid
+         * Hence we don't check here for uninitialized fields
+         */
+        if (this == obj)
+            return true;
+        if (obj == null)
+            return false;
+        if (getClass() != obj.getClass())
+            return false;
+        AffinityConfig that = (AffinityConfig) obj;
+        if (this.fromIp.equals(that.fromIp) && this.toIp.equals(that.toIp) && (this.affinityType.equals(that.affinityType))) {
+            return true;
+        }
+        return false;
+    }
+    /*
+    public static List<String> getGuiFieldsNames() {
+        List<String> fieldList = new ArrayList<String>();
+        for (String str : affinityFields) {
+            fieldList.add(str);
+        }
+        return fieldList;
+    }
+    */
+    @Override
+    public String toString() {
+        return ("AffinityConfig [Description=" + name + ", From=" + fromIp
+                + ", To=" + toIp + ", Type=" + affinityType + "]");
+    }
+
+    /**
+     * Implement clonable interface
+     */
+    @Override
+    public AffinityConfig clone() {
+        return new AffinityConfig(this);
+    }
+
+}
diff --git a/affinity/api/src/main/java/org/opendaylight/controller/affinity/IAffinityManager.java b/affinity/api/src/main/java/org/opendaylight/controller/affinity/IAffinityManager.java
new file mode 100644 (file)
index 0000000..15fc195
--- /dev/null
@@ -0,0 +1,62 @@
+
+/*
+ * Copyright (c) 2013 Plexxi, 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.affinity;
+
+import java.net.InetAddress;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+
+import org.opendaylight.controller.sal.core.Node;
+import org.opendaylight.controller.sal.core.NodeConnector;
+import org.opendaylight.controller.sal.core.Property;
+import org.opendaylight.controller.sal.utils.Status;
+
+import org.opendaylight.controller.affinity.AffinityConfig;
+
+/**
+ * Primary purpose of this interface is to provide methods for
+ * applications to set affinity configuration.
+ */
+public interface IAffinityManager {
+
+    /**
+     * Remove an affinity configuration
+     *
+     * @param  configObject refer to {@link Open Declaration org.opendaylight.controller.affinitymanager.AffinityConfig}
+     * @return "Success" or failure reason
+     */
+    public Status removeAffinityConfigObject(AffinityConfig configObject);
+
+    /**
+     * Remove an affinity configuration given the name
+     *
+     * @param   name      affinity name
+     * @return  "Success" or failure reason
+     */
+    public Status removeAffinityConfig(String name);
+
+    /**
+     * Save the current affinity configurations
+     *
+     * @return the status code
+     */
+    public Status saveAffinityConfig();
+
+    /**
+     * Update Switch specific configuration such as Affinity name and type. Add if absent.
+     *
+     * @param cfgConfig refer to {@link Open Declaration org.opendaylight.controller.affinity.AffinityConfig}
+     */
+    public Status updateAffinityConfig(AffinityConfig cfgObject);
+
+    public List<AffinityConfig> getAffinityConfigList();
+    public AffinityConfig getAffinityConfig(String affinity);
+}
diff --git a/affinity/api/src/main/java/org/opendaylight/controller/affinity/IAffinityManagerAware.java b/affinity/api/src/main/java/org/opendaylight/controller/affinity/IAffinityManagerAware.java
new file mode 100644 (file)
index 0000000..87d2b29
--- /dev/null
@@ -0,0 +1,39 @@
+/*
+ * Copyright (c) 2013 Plexxi, 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.affinity;
+
+/**
+ * The interface which describes the methods forwarding rules manager will call
+ * for notifying the listeners of policy installation updates.
+ */
+public interface IAffinityManagerAware {
+
+    /**
+     * Inform the listeners that specified affinity was updated.
+     *
+     * @param aff
+     *            the affinity config that was added or removed
+     * @param add true if add; false otherwise
+     */
+    public void affinityNotify(AffinityConfig aff, boolean add);
+
+    /**
+     * Inform listeners that the network node has notified us about a failure in
+     * executing the controller generated asynchronous request identified by the
+     * passed unique id.
+     *
+     * @param requestId
+     *            the unique id associated with the request which failed to be
+     *            executed on the network node
+     * @param error
+     *            the string describing the error reported by the network node
+     */
+    public void requestFailed(long requestId, String error);
+
+}
diff --git a/affinity/implementation/.classpath b/affinity/implementation/.classpath
new file mode 100644 (file)
index 0000000..f8ce0d3
--- /dev/null
@@ -0,0 +1,31 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<classpath>
+       <classpathentry kind="src" output="target/classes" path="src/main/java">
+               <attributes>
+                       <attribute name="optional" value="true"/>
+                       <attribute name="maven.pomderived" value="true"/>
+               </attributes>
+       </classpathentry>
+       <classpathentry kind="src" output="target/test-classes" path="src/test/java">
+               <attributes>
+                       <attribute name="optional" value="true"/>
+                       <attribute name="maven.pomderived" value="true"/>
+               </attributes>
+       </classpathentry>
+       <classpathentry excluding="**" kind="src" output="target/test-classes" path="src/test/resources">
+               <attributes>
+                       <attribute name="maven.pomderived" value="true"/>
+               </attributes>
+       </classpathentry>
+       <classpathentry kind="con" path="org.eclipse.jdt.launching.JRE_CONTAINER/org.eclipse.jdt.internal.debug.ui.launcher.StandardVMType/JavaSE-1.6">
+               <attributes>
+                       <attribute name="maven.pomderived" value="true"/>
+               </attributes>
+       </classpathentry>
+       <classpathentry kind="con" path="org.eclipse.m2e.MAVEN2_CLASSPATH_CONTAINER">
+               <attributes>
+                       <attribute name="maven.pomderived" value="true"/>
+               </attributes>
+       </classpathentry>
+       <classpathentry kind="output" path="target/classes"/>
+</classpath>
diff --git a/affinity/implementation/.project b/affinity/implementation/.project
new file mode 100644 (file)
index 0000000..4e4a8d4
--- /dev/null
@@ -0,0 +1,23 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<projectDescription>
+       <name>switchmanager.implementation</name>
+       <comment></comment>
+       <projects>
+       </projects>
+       <buildSpec>
+               <buildCommand>
+                       <name>org.eclipse.jdt.core.javabuilder</name>
+                       <arguments>
+                       </arguments>
+               </buildCommand>
+               <buildCommand>
+                       <name>org.eclipse.m2e.core.maven2Builder</name>
+                       <arguments>
+                       </arguments>
+               </buildCommand>
+       </buildSpec>
+       <natures>
+               <nature>org.eclipse.jdt.core.javanature</nature>
+               <nature>org.eclipse.m2e.core.maven2Nature</nature>
+       </natures>
+</projectDescription>
diff --git a/affinity/implementation/.settings/org.eclipse.core.resources.prefs b/affinity/implementation/.settings/org.eclipse.core.resources.prefs
new file mode 100644 (file)
index 0000000..cdfe4f1
--- /dev/null
@@ -0,0 +1,5 @@
+eclipse.preferences.version=1
+encoding//src/main/java=UTF-8
+encoding//src/test/java=UTF-8
+encoding//src/test/resources=UTF-8
+encoding/<project>=UTF-8
diff --git a/affinity/implementation/.settings/org.eclipse.jdt.core.prefs b/affinity/implementation/.settings/org.eclipse.jdt.core.prefs
new file mode 100644 (file)
index 0000000..60105c1
--- /dev/null
@@ -0,0 +1,5 @@
+eclipse.preferences.version=1
+org.eclipse.jdt.core.compiler.codegen.targetPlatform=1.6
+org.eclipse.jdt.core.compiler.compliance=1.6
+org.eclipse.jdt.core.compiler.problem.forbiddenReference=warning
+org.eclipse.jdt.core.compiler.source=1.6
diff --git a/affinity/implementation/.settings/org.eclipse.m2e.core.prefs b/affinity/implementation/.settings/org.eclipse.m2e.core.prefs
new file mode 100644 (file)
index 0000000..f897a7f
--- /dev/null
@@ -0,0 +1,4 @@
+activeProfiles=
+eclipse.preferences.version=1
+resolveWorkspaceProjects=true
+version=1
diff --git a/affinity/implementation/META-INF/MANIFEST.MF b/affinity/implementation/META-INF/MANIFEST.MF
new file mode 100644 (file)
index 0000000..8ab6578
--- /dev/null
@@ -0,0 +1,22 @@
+Manifest-Version: 1.0\r
+Bnd-LastModified: 1376940268439\r
+Build-Jdk: 1.6.0_37\r
+Built-By: sraman\r
+Bundle-Activator: org.opendaylight.controller.affinity.internal.Activato\r
+ r\r
+Bundle-ManifestVersion: 2\r
+Bundle-Name: implementation\r
+Bundle-SymbolicName: org.opendaylight.controller.affinity.implementation\r
+Bundle-Version: 0.4.0.SNAPSHOT\r
+Created-By: Apache Maven Bundle Plugin\r
+Import-Package: javax.xml.bind.annotation,org.apache.commons.lang3.build\r
+ er;version="[3.1,4)",org.apache.felix.dm;version="[3.0,4)",org.eclipse.\r
+ osgi.framework.console;version="[1.1,2)",org.opendaylight.controller.af\r
+ finity;version="[0.4,1)",org.opendaylight.controller.clustering.service\r
+ s;version="[0.4,1)",org.opendaylight.controller.configuration;version="\r
+ [0.4,1)",org.opendaylight.controller.sal.core;version="[0.5,1)",org.ope\r
+ ndaylight.controller.sal.inventory;version="[0.5,1)",org.opendaylight.c\r
+ ontroller.sal.packet;version="[0.5,1)",org.opendaylight.controller.sal.\r
+ utils;version="[0.5,1)",org.osgi.framework;version="[1.7,2)",org.slf4j;\r
+ version="[1.7,2)"\r
+Tool: Bnd-1.50.0\r
diff --git a/affinity/implementation/pom.xml b/affinity/implementation/pom.xml
new file mode 100644 (file)
index 0000000..c5ab5a8
--- /dev/null
@@ -0,0 +1,125 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<project xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd" xmlns="http://maven.apache.org/POM/4.0.0"
+    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
+  <modelVersion>4.0.0</modelVersion>
+<!--  <parent>
+    <groupId>org.opendaylight.controller</groupId>
+    <artifactId>affinity</artifactId>
+    <version>1.4.0-SNAPSHOT</version>
+  </parent> -->
+
+  <groupId>org.opendaylight.controller.affinity</groupId>
+  <artifactId>implementation</artifactId>
+  <version>0.4.0-SNAPSHOT</version>
+  <packaging>bundle</packaging>
+
+  <properties>
+    <!-- Sonar properties using jacoco to retrieve integration test results -->
+    <sonar.java.coveragePlugin>jacoco</sonar.java.coveragePlugin>
+    <sonar.dynamicAnalysis>reuseReports</sonar.dynamicAnalysis>
+    <sonar.jacoco.Reportpath>target/jacoco.exec</sonar.jacoco.Reportpath>
+    <sonar.jacoco.itReportPath>target/jacoco-it.exec</sonar.jacoco.itReportPath>
+    <sonar.language>java</sonar.language>
+    <junit.version>4.10</junit.version>
+  </properties>
+  <build>
+    <pluginManagement>
+      <plugins>
+        <plugin>
+          <groupId>org.jacoco</groupId>
+          <artifactId>jacoco-maven-plugin</artifactId>
+          <version>0.5.3.201107060350</version>
+        </plugin>
+      </plugins>
+    </pluginManagement>
+    <plugins>
+      <plugin>
+        <groupId>org.apache.felix</groupId>
+        <artifactId>maven-bundle-plugin</artifactId>
+        <version>2.3.6</version>
+        <extensions>true</extensions>
+        <configuration>
+          <instructions>
+            <Export-Package>
+              org.opendaylight.controller.affinity.implementation            
+            </Export-Package>
+            <Import-Package>
+              org.opendaylight.controller.affinity,
+              org.opendaylight.controller.clustering.services,
+              org.opendaylight.controller.configuration,
+              org.opendaylight.controller.sal.core,
+              org.opendaylight.controller.sal.utils,
+              org.opendaylight.controller.sal.packet,
+              org.opendaylight.controller.sal.inventory,
+              org.slf4j,
+              org.apache.felix.dm,
+              org.eclipse.osgi.framework.console,
+              org.osgi.framework,
+              javax.xml.bind.annotation,
+              org.apache.commons.lang3.builder
+            </Import-Package>
+            <Bundle-Activator>
+              org.opendaylight.controller.affinity.internal.Activator
+            </Bundle-Activator>
+          </instructions>
+          <manifestLocation>${project.basedir}/META-INF</manifestLocation>
+        </configuration>
+      </plugin>
+      <plugin>
+        <groupId>org.jacoco</groupId>
+        <artifactId>jacoco-maven-plugin</artifactId>
+        <configuration>
+          <includes>org.opendaylight.controller.*</includes>
+        </configuration>
+        <executions>
+          <execution>
+            <id>pre-test</id>
+            <goals>
+              <goal>prepare-agent</goal>
+            </goals>
+          </execution>
+          <execution>
+            <id>post-test</id>
+            <phase>test</phase>
+            <goals>
+              <goal>report</goal>
+            </goals>
+          </execution>
+        </executions>
+      </plugin>
+    </plugins>
+  </build>
+  <dependencies>
+    <dependency>
+      <groupId>junit</groupId>
+      <artifactId>junit</artifactId>
+      <version>${junit.version}</version>
+      <scope>test</scope>
+    </dependency>
+    <dependency>
+      <groupId>org.opendaylight.controller</groupId>
+      <artifactId>clustering.services</artifactId>
+      <version>0.4.0-SNAPSHOT</version>
+    </dependency>
+    <dependency>
+      <groupId>org.opendaylight.controller</groupId>
+      <artifactId>configuration</artifactId>
+      <version>0.4.0-SNAPSHOT</version>
+    </dependency>
+    <dependency>
+      <groupId>org.opendaylight.controller</groupId>
+      <artifactId>sal</artifactId>
+      <version>0.5.0-SNAPSHOT</version>
+    </dependency>
+    <dependency>
+      <groupId>org.opendaylight.controller</groupId>
+      <artifactId>forwardingrulesmanager</artifactId>
+      <version>0.4.0-SNAPSHOT</version>
+    </dependency>
+    <dependency>
+      <groupId>org.opendaylight.controller</groupId>
+      <artifactId>affinity</artifactId>
+      <version>0.4.0-SNAPSHOT</version>
+    </dependency>
+  </dependencies>
+</project>
diff --git a/affinity/implementation/src/main/java/org/opendaylight/controller/affinity/internal/Activator.java b/affinity/implementation/src/main/java/org/opendaylight/controller/affinity/internal/Activator.java
new file mode 100644 (file)
index 0000000..f2a5240
--- /dev/null
@@ -0,0 +1,106 @@
+
+/*
+ * Copyright (c) 2013 Plexxi, 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.affinity.internal;
+
+import java.util.Dictionary;
+import java.util.HashSet;
+import java.util.Hashtable;
+import java.util.Set;
+
+import org.apache.felix.dm.Component;
+import org.opendaylight.controller.clustering.services.ICacheUpdateAware;
+import org.opendaylight.controller.clustering.services.IClusterContainerServices;
+import org.opendaylight.controller.configuration.IConfigurationContainerAware;
+import org.opendaylight.controller.sal.core.ComponentActivatorAbstractBase;
+import org.opendaylight.controller.affinity.IAffinityManager;
+import org.opendaylight.controller.affinity.IAffinityManagerAware;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ * AffinityManager Bundle Activator
+ *
+ *
+ */
+public class Activator extends ComponentActivatorAbstractBase {
+    protected static final Logger logger = LoggerFactory
+            .getLogger(Activator.class);
+
+    /**
+     * Function called when the activator starts just after some
+     * initializations are done by the
+     * ComponentActivatorAbstractBase.
+     *
+     */
+    public void init() {
+
+    }
+
+    /**
+     * Function called when the activator stops just before the
+     * cleanup done by ComponentActivatorAbstractBase
+     *
+     */
+    public void destroy() {
+
+    }
+
+    /**
+     * Function that is used to communicate to dependency manager the
+     * list of known implementations for services inside a container
+     *
+     *
+     * @return An array containing all the CLASS objects that will be
+     * instantiated in order to get an fully working implementation
+     * Object
+     */
+    public Object[] getImplementations() {
+        Object[] res = { AffinityManagerImpl.class };
+        return res;
+    }
+
+    /**
+     * Function that is called when configuration of the dependencies
+     * is required.
+     *
+     * @param c dependency manager Component object, used for
+     * configuring the dependencies exported and imported
+     * @param imp Implementation class that is being configured,
+     * needed as long as the same routine can configure multiple
+     * implementations
+     * @param containerName The containerName being configured, this allow
+     * also optional per-container different behavior if needed, usually
+     * should not be the case though.
+     */
+    public void configureInstance(Component c, Object imp, String containerName) {
+        if (imp.equals(AffinityManagerImpl.class)) {
+            Dictionary<String, Set<String>> props = new Hashtable<String, Set<String>>();
+            Set<String> propSet = new HashSet<String>();
+            propSet.add("affinitymanager.configSaveEvent");
+            props.put("cachenames", propSet);
+            // export the service
+            c.setInterface(new String[] {
+                    IAffinityManager.class.getName(),
+                    ICacheUpdateAware.class.getName(),
+                    IConfigurationContainerAware.class.getName() }, props);
+
+            // Now lets add a service dependency to make sure the
+            // provider of service exists
+            c.add(createContainerServiceDependency(containerName).setService(
+                    IAffinityManagerAware.class).setCallbacks(
+                    "setAffinityManagerAware", "unsetAffinityManagerAware")
+                    .setRequired(false));
+            c.add(createContainerServiceDependency(containerName).setService(
+                    IClusterContainerServices.class).setCallbacks(
+                    "setClusterContainerService",
+                    "unsetClusterContainerService").setRequired(true));
+        }
+    }
+}
diff --git a/affinity/implementation/src/main/java/org/opendaylight/controller/affinity/internal/AffinityManagerImpl.java b/affinity/implementation/src/main/java/org/opendaylight/controller/affinity/internal/AffinityManagerImpl.java
new file mode 100644 (file)
index 0000000..1246d37
--- /dev/null
@@ -0,0 +1,390 @@
+/*
+ * Copyright (c) 2013 Plexxi, 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.affinity.internal;
+
+import java.io.FileNotFoundException;
+import java.io.IOException;
+import java.io.ObjectInputStream;
+import java.net.InetAddress;
+import java.net.NetworkInterface;
+import java.net.SocketException;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.Date;
+import java.util.Dictionary;
+import java.util.EnumSet;
+import java.util.Enumeration;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+import java.util.concurrent.ConcurrentHashMap;
+import java.util.concurrent.ConcurrentMap;
+import java.util.concurrent.CopyOnWriteArrayList;
+import java.util.ArrayList;
+import java.util.EnumSet;
+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.concurrent.ConcurrentHashMap;
+import java.util.concurrent.ConcurrentMap;
+
+import org.apache.felix.dm.Component;
+import org.eclipse.osgi.framework.console.CommandInterpreter;
+import org.eclipse.osgi.framework.console.CommandProvider;
+import org.opendaylight.controller.clustering.services.CacheConfigException;
+import org.opendaylight.controller.clustering.services.CacheExistException;
+import org.opendaylight.controller.clustering.services.ICacheUpdateAware;
+import org.opendaylight.controller.clustering.services.IClusterContainerServices;
+import org.opendaylight.controller.clustering.services.IClusterServices;
+import org.opendaylight.controller.configuration.IConfigurationContainerAware;
+import org.opendaylight.controller.forwardingrulesmanager.FlowEntry;
+import org.opendaylight.controller.sal.core.IContainer;
+import org.opendaylight.controller.sal.core.Node;
+import org.opendaylight.controller.sal.core.NodeConnector;
+import org.opendaylight.controller.sal.core.NodeTable;
+import org.opendaylight.controller.sal.core.Property;
+import org.opendaylight.controller.sal.core.UpdateType;
+import org.opendaylight.controller.sal.flowprogrammer.Flow;
+import org.opendaylight.controller.sal.inventory.IListenInventoryUpdates;
+import org.opendaylight.controller.sal.reader.FlowOnNode;
+import org.opendaylight.controller.sal.reader.IReadService;
+import org.opendaylight.controller.sal.reader.IReadServiceListener;
+import org.opendaylight.controller.sal.utils.GlobalConstants;
+import org.opendaylight.controller.sal.utils.IObjectReader;
+import org.opendaylight.controller.sal.utils.ObjectReader;
+import org.opendaylight.controller.sal.utils.ObjectWriter;
+
+import org.opendaylight.controller.sal.reader.NodeConnectorStatistics;
+import org.opendaylight.controller.sal.reader.NodeDescription;
+import org.opendaylight.controller.sal.reader.NodeTableStatistics;
+import org.opendaylight.controller.sal.utils.Status;
+import org.opendaylight.controller.sal.utils.StatusCode;
+
+import org.opendaylight.controller.sal.utils.ServiceHelper;
+import org.opendaylight.controller.affinity.AffinityConfig;
+import org.opendaylight.controller.affinity.IAffinityManager;
+import org.opendaylight.controller.affinity.IAffinityManagerAware;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ * The class caches latest network nodes statistics as notified by reader
+ * services and provides API to retrieve them.
+ */
+public class AffinityManagerImpl implements IAffinityManager, IConfigurationContainerAware, IObjectReader, ICacheUpdateAware<Long, String> {
+    private static final Logger log = LoggerFactory.getLogger(AffinityManagerImpl.class);
+
+
+    private static String ROOT = GlobalConstants.STARTUPHOME.toString();
+    private static final String SAVE = "Save";
+    private String affinityConfigFileName = null;
+    private ConcurrentMap<String, AffinityConfig> affinityConfigList;
+
+    private ConcurrentMap<Long, String> configSaveEvent;
+    private final Set<IAffinityManagerAware> affinityManagerAware = Collections
+            .synchronizedSet(new HashSet<IAffinityManagerAware>());
+
+    private byte[] MAC;
+    private static boolean hostRefresh = true;
+    private int hostRetryCount = 5;
+    private IClusterContainerServices clusterContainerService = null;
+    private String containerName = null;
+    private boolean isDefaultContainer = true;
+    private static final int REPLACE_RETRY = 1;
+
+    public enum ReasonCode {
+        SUCCESS("Success"), FAILURE("Failure"), INVALID_CONF(
+                "Invalid Configuration"), EXIST("Entry Already Exist"), CONFLICT(
+                        "Configuration Conflict with Existing Entry");
+
+        private final String name;
+
+        private ReasonCode(String name) {
+            this.name = name;
+        }
+
+        @Override
+        public String toString() {
+            return name;
+        }
+    }
+
+    /* Only default container. */
+    public String getContainerName() {
+        return containerName;
+    }
+
+    public void startUp() {
+        // Initialize configuration file names
+        affinityConfigFileName = ROOT + "affinityConfig_" + this.getContainerName()
+            + ".conf";
+
+        // Instantiate cluster synced variables
+        allocateCaches();
+        retrieveCaches();
+
+        /*
+         * Read startup and build database if we have not already gotten the
+         * configurations synced from another node
+         */
+        if (affinityConfigList.isEmpty()) {
+            loadAffinityConfiguration();
+        }
+    }
+
+    public void shutDown() {
+    }
+
+    @SuppressWarnings("deprecation")
+    private void allocateCaches() {
+        if (this.clusterContainerService == null) {
+            this.nonClusterObjectCreate();
+            log.warn("un-initialized clusterContainerService, can't create cache");
+            return;
+        }
+
+        try {
+            clusterContainerService.createCache(
+                    "affinity.affinityConfigList",
+                    EnumSet.of(IClusterServices.cacheMode.NON_TRANSACTIONAL));
+            clusterContainerService.createCache(
+                    "affinity.configSaveEvent",
+                    EnumSet.of(IClusterServices.cacheMode.NON_TRANSACTIONAL));
+        } catch (CacheConfigException cce) {
+            log.error("\nCache configuration invalid - check cache mode");
+        } catch (CacheExistException ce) {
+            log.error("\nCache already exits - destroy and recreate if needed");
+        }
+    }
+
+    @SuppressWarnings({ "unchecked", "deprecation" })
+    private void retrieveCaches() {
+        if (this.clusterContainerService == null) {
+            log.info("un-initialized clusterContainerService, can't create cache");
+            return;
+        }
+        affinityConfigList = (ConcurrentMap<String, AffinityConfig>) clusterContainerService
+            .getCache("affinity.affinityConfigList");
+        if (affinityConfigList == null) {
+            log.error("\nFailed to get cache for affinityConfigList");
+        }
+        configSaveEvent = (ConcurrentMap<Long, String>) clusterContainerService
+            .getCache("affinity.configSaveEvent");
+        if (configSaveEvent == null) {
+            log.error("\nFailed to get cache for configSaveEvent");
+        }
+    }
+
+    private void nonClusterObjectCreate() {
+        affinityConfigList = new ConcurrentHashMap<String, AffinityConfig>();
+        configSaveEvent = new ConcurrentHashMap<Long, String>();
+    }
+
+    @Override
+    public List<AffinityConfig> getAffinityConfigList() {
+        return new ArrayList<AffinityConfig>(affinityConfigList.values());
+    }
+
+    @Override
+    public AffinityConfig getAffinityConfig(String affinity) {
+        return affinityConfigList.get(affinity);
+    }
+
+
+    @Override
+    public Object readObject(ObjectInputStream ois)
+            throws FileNotFoundException, IOException, ClassNotFoundException {
+        // Perform the class deserialization locally, from inside the package
+        // where the class is defined
+        return ois.readObject();
+    }
+
+    @SuppressWarnings("unchecked")
+    private void loadAffinityConfiguration() {
+        ObjectReader objReader = new ObjectReader();
+        ConcurrentMap<String, AffinityConfig> confList = (ConcurrentMap<String, AffinityConfig>) objReader
+                .read(this, affinityConfigFileName);
+
+        if (confList == null) {
+            return;
+        }
+
+        for (AffinityConfig conf : confList.values()) {
+            updateAffinityConfig(conf);
+        }
+    }
+
+    /* Add if absent. */
+    @Override
+    public Status updateAffinityConfig(AffinityConfig cfgObject) {
+        // update default container only
+        if (!isDefaultContainer) {
+            return new Status(StatusCode.INTERNALERROR, "Not default container");
+        }
+
+        AffinityConfig ac = affinityConfigList.get(cfgObject.getName());
+        if (ac == null) {
+            if (affinityConfigList.putIfAbsent(cfgObject.getName(), cfgObject) != null) {
+                return new Status(StatusCode.CONFLICT, "affinity configuration already exists" + cfgObject.getName());
+            }
+        } else {
+            if (!affinityConfigList.replace(cfgObject.getName(), ac, cfgObject)) {
+                return new Status(StatusCode.INTERNALERROR, "Failed to add affinity configuration.");
+            }
+        }
+        return new Status(StatusCode.SUCCESS, "Updated affinity configuration " + cfgObject.getName());
+    }
+
+
+    /* Remove affinity config */
+    @Override
+    public Status removeAffinityConfig(String cfgName) {
+        // update default container only
+        if (!isDefaultContainer) {
+            return new Status(StatusCode.INTERNALERROR, "Not default container");
+        }
+        AffinityConfig ac = affinityConfigList.get(cfgName);
+        if (ac != null) {
+            return removeAffinityConfigObject(ac);
+        }
+        return new Status(StatusCode.INTERNALERROR, "Missing affinity config" + cfgName);
+    }
+    /* Remove affinity config */
+    @Override
+    public Status removeAffinityConfigObject(AffinityConfig cfgObject) {
+        // update default container only
+        if (!isDefaultContainer) {
+            return new Status(StatusCode.INTERNALERROR, "Not default container");
+        }
+
+        AffinityConfig ac = affinityConfigList.get(cfgObject.getName());
+        if (ac != null) {
+            if (affinityConfigList.remove(cfgObject.getName(), ac)) {
+                return new Status(StatusCode.SUCCESS, "Configuration removed: " + cfgObject.getName());
+            } else {
+                String msg = "Remove failed " + cfgObject.getName();
+                return new Status(StatusCode.INTERNALERROR, msg);
+            }
+        }
+        return new Status(StatusCode.INTERNALERROR, "Remove failed: " + cfgObject.getName());
+    }
+    @Override
+    public Status saveConfiguration() {
+        return saveAffinityConfig();
+    }
+
+    @Override
+    public Status saveAffinityConfig() {
+        // Publish the save config event to the cluster nodes
+        configSaveEvent.put(new Date().getTime(), SAVE);
+        return saveAffinityConfigInternal();
+    }
+
+    public Status saveAffinityConfigInternal() {
+        Status retS = null, retP = null;
+        ObjectWriter objWriter = new ObjectWriter();
+
+        retS = objWriter.write(new ConcurrentHashMap<String, AffinityConfig>(
+                affinityConfigList), affinityConfigFileName);
+
+        if (retS.equals(retP)) {
+            if (retS.isSuccess()) {
+                return retS;
+            } else {
+                return new Status(StatusCode.INTERNALERROR, "Save failed");
+            }
+        } else {
+            return new Status(StatusCode.INTERNALERROR, "Partial save failure");
+        }
+    }
+
+    @Override
+    public void entryCreated(Long key, String cacheName, boolean local) {
+    }
+
+    @Override
+    public void entryUpdated(Long key, String new_value, String cacheName,
+            boolean originLocal) {
+        saveAffinityConfigInternal();
+    }
+
+    @Override
+    public void entryDeleted(Long key, String cacheName, boolean originLocal) {
+    }
+
+    /**
+     * Function called by the dependency manager when all the required
+     * dependencies are satisfied
+     *
+     */
+    void init() {
+        log.debug("INIT called!");
+        containerName = GlobalConstants.DEFAULT.toString();
+        startUp();
+    }
+
+    /**
+     * Function called by the dependency manager when at least one
+     * dependency become unsatisfied or when the component is shutting
+     * down because for example bundle is being stopped.
+     *
+     */
+    void destroy() {
+        log.debug("DESTROY called!");
+    }
+
+    /**
+     * Function called by dependency manager after "init ()" is called
+     * and after the services provided by the class are registered in
+     * the service registry
+     *
+     */
+    void start() {
+        log.debug("START called!");
+    }
+
+    /**
+     * Function called after registering the service in OSGi service registry.
+     */
+    void started(){
+        // Retrieve current statistics so we don't have to wait for next refresh
+        IAffinityManager affinityManager = (IAffinityManager) ServiceHelper.getInstance(
+                IAffinityManager.class, this.getContainerName(), this);
+        if (affinityManager != null) {
+            log.debug("STARTED method called!");
+        }
+    }
+
+    /**
+     * Function called by the dependency manager before the services
+     * exported by the component are unregistered, this will be
+     * followed by a "destroy ()" calls
+     *
+     */
+    void stop() {
+        log.debug("STOP called!");
+    }
+
+    void setClusterContainerService(IClusterContainerServices s) {
+        log.debug("Cluster Service set for Statistics Mgr");
+        this.clusterContainerService = s;
+    }
+
+    void unsetClusterContainerService(IClusterContainerServices s) {
+        if (this.clusterContainerService == s) {
+            log.debug("Cluster Service removed for Statistics Mgr!");
+            this.clusterContainerService = null;
+        }
+    }
+}
diff --git a/affinity/implementation/src/test/java/org/opendaylight/controller/affinity/internal/AffinityManagerImplTest.java b/affinity/implementation/src/test/java/org/opendaylight/controller/affinity/internal/AffinityManagerImplTest.java
new file mode 100644 (file)
index 0000000..f1eed74
--- /dev/null
@@ -0,0 +1,45 @@
+/*
+ * Copyright (c) 2013 Plexxi, 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.affinity.internal;
+
+import java.util.ArrayList;
+import java.util.HashSet;
+import java.util.Set;
+
+import org.junit.Assert;
+import org.junit.Test;
+import org.opendaylight.controller.sal.core.Bandwidth;
+import org.opendaylight.controller.sal.core.Latency;
+import org.opendaylight.controller.sal.core.Property;
+import org.opendaylight.controller.sal.core.State;
+import org.opendaylight.controller.sal.core.UpdateType;
+import org.opendaylight.controller.sal.utils.Status;
+import org.opendaylight.controller.affinity.AffinityConfig;
+
+public class AffinityManagerImplTest {
+
+    @Test
+    public void testAffinityManagerAddRemoveConfig() {
+        AffinityManagerImpl affinitymgr = new AffinityManagerImpl();
+        affinitymgr.startUp();
+
+        AffinityConfig ac = new AffinityConfig("test_affinity1", "10.0.0.1", "10.0.0.2", "Isolate");
+
+        // Add status to update/add
+        Status addResult = affinitymgr.updateAffinityConfig(ac);
+        Assert.assertTrue(addResult.isSuccess());
+
+        Status removeResult = (affinitymgr.removeAffinityConfig(ac.getName()));
+        Assert.assertTrue(removeResult.isSuccess());
+
+        AffinityConfig affinityConfigResult = affinitymgr.getAffinityConfig(ac.getName());
+        Assert.assertTrue(affinityConfigResult == null);
+        // System.out.println("*" + switchmgr.addSubnet(subnet) + "*");
+    }
+}
diff --git a/affinity/implementation/src/test/resources/logback.xml b/affinity/implementation/src/test/resources/logback.xml
new file mode 100644 (file)
index 0000000..5fa21fe
--- /dev/null
@@ -0,0 +1,13 @@
+<configuration scan="true">\r
+\r
+  <appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender">\r
+    <encoder>\r
+      <pattern>%d{HH:mm:ss.SSS} [%thread] %-5level %logger{36} - %msg%n\r
+      </pattern>\r
+    </encoder>\r
+  </appender>\r
+\r
+  <root level="error">\r
+    <appender-ref ref="STDOUT" />\r
+  </root>\r
+</configuration>\r
diff --git a/affinity/northbound/enunciate.xml b/affinity/northbound/enunciate.xml
new file mode 100644 (file)
index 0000000..85201d7
--- /dev/null
@@ -0,0 +1,12 @@
+<?xml version="1.0"?>
+<enunciate label="full" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+    xsi:noNamespaceSchemaLocation="http://enunciate.codehaus.org/schemas/enunciate-1.26.xsd">
+
+  <services>
+    <rest defaultRestSubcontext="/controller/nb/v2/affinity"/>
+  </services>
+
+  <modules>
+    <docs docsDir="rest" title="Affinity REST API" includeExampleXml="true" includeExampleJson="true"/>
+  </modules>
+</enunciate>
diff --git a/affinity/northbound/pom.xml b/affinity/northbound/pom.xml
new file mode 100644 (file)
index 0000000..03f9bcb
--- /dev/null
@@ -0,0 +1,165 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<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>affinity</artifactId>
+    <version>1.4.0-SNAPSHOT</version>
+  </parent> -->
+
+  <groupId>org.opendaylight.controller.affinity</groupId> 
+  <artifactId>northbound</artifactId>
+  <version>0.4.0-SNAPSHOT</version>
+  <packaging>bundle</packaging>
+      <properties>
+       <propertymavenplugin.version>1.0-alpha-2</propertymavenplugin.version>
+       <sonar.host.url>https://sonar.opendaylight.org/</sonar.host.url>
+       <sitedeploy>dav:http://nexus.opendaylight.org/content/sites/site</sitedeploy>
+       <siteplugin>3.2</siteplugin>
+       <projectinfo>2.6</projectinfo>
+       <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
+       <compiler.version>2.3.2</compiler.version>
+       <surefire.version>2.15</surefire.version>
+       <failsafe.version>2.15</failsafe.version>
+       <exam.version>3.0.0</exam.version>
+       <url.version>1.5.0</url.version>
+       <enunciate.version>1.26.2</enunciate.version>
+       <sonar.branch>${user.name}-private-view</sonar.branch>
+       <sonar.skippedModules>org.openflow.openflowj,net.sf.jung2</sonar.skippedModules>
+       <logback.version>1.0.9</logback.version>
+       <slf4j.version>1.7.2</slf4j.version>
+       <jackson.version>1.9.8</jackson.version>
+       <spring.version>3.1.3.RELEASE</spring.version>
+       <spring-security.version>3.1.3.RELEASE</spring-security.version>
+       <jersey.version>1.17</jersey.version>
+       <virgo.version>3.6.0.RELEASE</virgo.version>
+       <geminiweb.version>2.2.0.RELEASE</geminiweb.version>
+       <checkstyle.version>2.10</checkstyle.version>
+       <testvm.argLine>-Xmx1024m -XX:MaxPermSize=256m</testvm.argLine>
+       <nexusproxy>http://nexus.opendaylight.org/content</nexusproxy>
+      </properties>
+
+    <repositories>
+    <!-- OpenDayLight Snapshot artifact -->
+    <repository>
+      <id>opendaylight-snapshot</id>
+      <name>opendaylight-snapshot</name>
+      <url>${nexusproxy}/repositories/opendaylight.snapshot/</url>
+    </repository>
+    </repositories>
+  <distributionManagement>
+    <!-- OpenDayLight Snapshot artifact -->
+    <snapshotRepository>
+      <id>opendaylight-snapshot</id>
+      <url>${nexusproxy}/repositories/opendaylight.snapshot/</url>
+    </snapshotRepository>
+    <!-- Site deployment -->
+    <site>
+      <id>website</id>
+      <url>${sitedeploy}</url>
+    </site>
+  </distributionManagement>
+
+  <build>
+    <plugins>
+      <plugin>
+        <groupId>org.codehaus.enunciate</groupId>
+        <artifactId>maven-enunciate-plugin</artifactId>
+        <version>${enunciate.version}</version>
+        <configuration>
+          <javacCheck>true</javacCheck>
+        </configuration>
+        <dependencies>
+          <dependency>
+            <groupId>org.opendaylight.controller</groupId>
+            <artifactId>sal</artifactId>
+            <version>0.5.0-SNAPSHOT</version>
+          </dependency>
+        </dependencies>
+      </plugin>
+
+      <plugin>
+        <groupId>org.apache.felix</groupId>
+        <artifactId>maven-bundle-plugin</artifactId>
+        <version>2.3.6</version>
+        <extensions>true</extensions>
+        <configuration>
+          <instructions>
+            <Import-Package>
+              org.opendaylight.controller.sal.core,
+              org.opendaylight.controller.sal.utils,
+              org.opendaylight.controller.containermanager,
+              org.opendaylight.controller.affinity,
+              org.opendaylight.controller.usermanager,
+              org.apache.commons.lang3.tuple,
+              org.apache.commons.logging,
+              com.sun.jersey.spi.container.servlet,
+              org.opendaylight.controller.northbound.commons,
+              org.opendaylight.controller.northbound.commons.exception,
+              org.opendaylight.controller.northbound.commons.utils,
+              org.opendaylight.controller.sal.authorization,
+              javax.ws.rs,
+              javax.ws.rs.core,
+              javax.xml.bind.annotation,
+              javax.xml.bind,
+              org.slf4j,
+              !org.codehaus.enunciate.jaxrs
+            </Import-Package>
+           <Export-Package>
+              org.opendaylight.controller.affinity.northbound
+           </Export-Package>
+            <Web-ContextPath>/controller/nb/v2/affinity</Web-ContextPath>
+          </instructions>
+          <manifestLocation>${project.basedir}/src/main/resources/META-INF</manifestLocation>
+        </configuration>
+      </plugin>
+    </plugins>
+  </build>
+  <dependencies>
+    <dependency>
+      <groupId>org.opendaylight.controller.thirdparty</groupId>
+      <artifactId>com.sun.jersey.jersey-servlet</artifactId>
+      <version>1.17-SNAPSHOT</version>
+    </dependency>
+
+    <dependency>
+      <groupId>org.opendaylight.controller</groupId>
+      <artifactId>affinity</artifactId>
+      <version>0.4.0-SNAPSHOT</version>
+    </dependency>
+
+    <dependency>
+      <groupId>org.opendaylight.controller</groupId>
+      <artifactId>containermanager</artifactId>
+      <version>0.4.0-SNAPSHOT</version>
+    </dependency>
+
+    <dependency>
+      <groupId>org.opendaylight.controller</groupId>
+      <artifactId>sal</artifactId>
+      <version>0.5.0-SNAPSHOT</version>
+    </dependency>
+
+    <dependency>
+      <groupId>org.opendaylight.controller</groupId>
+      <artifactId>commons.northbound</artifactId>
+      <version>0.4.0-SNAPSHOT</version>
+    </dependency>
+
+    <dependency>
+      <groupId>org.springframework</groupId>
+      <artifactId>spring-web</artifactId>
+      <version>${spring.version}</version>
+      <scope>provided</scope>
+    </dependency>
+
+    <dependency>
+      <groupId>org.codehaus.enunciate</groupId>
+      <artifactId>enunciate-core-annotations</artifactId>
+      <version>${enunciate.version}</version>
+    </dependency>
+
+  </dependencies>
+
+</project>
diff --git a/affinity/northbound/src/main/java/org/opendaylight/controller/affinity/northbound/Affinities.java b/affinity/northbound/src/main/java/org/opendaylight/controller/affinity/northbound/Affinities.java
new file mode 100644 (file)
index 0000000..7f9aca2
--- /dev/null
@@ -0,0 +1,37 @@
+/*
+ * Copyright (c) 2013 Plexxi, 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.affinity.northbound;
+
+import java.util.List;
+
+import javax.xml.bind.annotation.XmlAccessType;
+import javax.xml.bind.annotation.XmlAccessorType;
+import javax.xml.bind.annotation.XmlElement;
+import javax.xml.bind.annotation.XmlRootElement;
+
+import org.opendaylight.controller.affinity.AffinityConfig;
+
+@XmlRootElement
+@XmlAccessorType(XmlAccessType.NONE)
+public class Affinities {
+        @XmlElement (name="affinity")
+        List<AffinityConfig> affinityList;
+
+        public Affinities() {
+        }
+        public Affinities (List<AffinityConfig> aff) {
+            this.affinityList = aff;
+        }
+        public List<AffinityConfig> getAffinityList() {
+                return affinityList;
+        }
+        public void setAffinityList(List<AffinityConfig> aff) {
+                this.affinityList = aff;
+        }
+}
diff --git a/affinity/northbound/src/main/java/org/opendaylight/controller/affinity/northbound/AffinityNorthbound.java b/affinity/northbound/src/main/java/org/opendaylight/controller/affinity/northbound/AffinityNorthbound.java
new file mode 100644 (file)
index 0000000..375dfb9
--- /dev/null
@@ -0,0 +1,265 @@
+/*
+ * Copyright (c) 2013 Plexxi, 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.affinity.northbound;
+
+import java.util.ArrayList;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+
+import javax.ws.rs.Consumes;
+import javax.ws.rs.DELETE;
+import javax.ws.rs.GET;
+import javax.ws.rs.POST;
+import javax.ws.rs.PUT;
+import javax.ws.rs.Path;
+import javax.ws.rs.PathParam;
+import javax.ws.rs.Produces;
+import javax.ws.rs.core.Context;
+import javax.ws.rs.core.MediaType;
+import javax.ws.rs.core.Response;
+import javax.ws.rs.core.SecurityContext;
+
+import org.codehaus.enunciate.jaxrs.ResponseCode;
+import org.codehaus.enunciate.jaxrs.StatusCodes;
+import org.codehaus.enunciate.jaxrs.TypeHint;
+import org.opendaylight.controller.containermanager.IContainerManager;
+import org.opendaylight.controller.northbound.commons.RestMessages;
+import org.opendaylight.controller.northbound.commons.exception.InternalServerErrorException;
+import org.opendaylight.controller.northbound.commons.exception.ResourceConflictException;
+import org.opendaylight.controller.northbound.commons.exception.ResourceNotFoundException;
+import org.opendaylight.controller.northbound.commons.exception.ServiceUnavailableException;
+import org.opendaylight.controller.northbound.commons.exception.UnauthorizedException;
+import org.opendaylight.controller.northbound.commons.utils.NorthboundUtils;
+import org.opendaylight.controller.sal.authorization.Privilege;
+import org.opendaylight.controller.sal.utils.GlobalConstants;
+import org.opendaylight.controller.sal.utils.ServiceHelper;
+import org.opendaylight.controller.sal.utils.Status;
+import org.opendaylight.controller.affinity.IAffinityManager;
+import org.opendaylight.controller.affinity.AffinityConfig;
+
+/**
+ * The class provides Northbound REST APIs to access affinity configuration.
+ *
+ */
+
+@Path("/")
+public class AffinityNorthbound {
+
+    private String username;
+
+    @Context
+    public void setSecurityContext(SecurityContext context) {
+        username = context.getUserPrincipal().getName();
+    }
+
+    protected String getUserName() {
+        return username;
+    }
+
+    private IAffinityManager getIfAffinityManagerService(String containerName) {
+        IContainerManager containerManager = (IContainerManager) ServiceHelper
+                .getGlobalInstance(IContainerManager.class, this);
+        if (containerManager == null) {
+            throw new ServiceUnavailableException("Container "
+                    + RestMessages.SERVICEUNAVAILABLE.toString());
+        }
+
+        boolean found = false;
+        List<String> containerNames = containerManager.getContainerNames();
+        for (String cName : containerNames) {
+            if (cName.trim().equalsIgnoreCase(containerName.trim())) {
+                found = true;
+                break;
+            }
+        }
+
+        if (found == false) {
+            throw new ResourceNotFoundException(containerName + " "
+                    + RestMessages.SERVICEUNAVAILABLE.toString());
+        }
+
+        IAffinityManager affinityManager = (IAffinityManager) ServiceHelper
+                .getInstance(IAffinityManager.class, containerName, this);
+
+        if (affinityManager == null) {
+            throw new ServiceUnavailableException("Affinity Manager "
+                    + RestMessages.SERVICEUNAVAILABLE.toString());
+        }
+
+        return affinityManager;
+    }
+
+/*
+ * getAllAffinities()
+ * getAffinity(String name)
+ * addAffinity(name, ip1, ip2, type)
+ * removeAffinity(String name)
+ */
+    /**
+     * Retrieve a list of all affinities in this container.
+     */
+    @Path("/{containerName}/affinities")
+    @GET
+    @Produces({ MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML })
+    @TypeHint(Affinities.class)
+    @StatusCodes({
+            @ResponseCode(code = 200, condition = "Operation successful"),
+            @ResponseCode(code = 404, condition = "The containerName is not found"),
+            @ResponseCode(code = 503, condition = "One or more of Controller Services are unavailable") })
+    public Affinities getAllAffinities(@PathParam("containerName") String containerName) {
+
+        if (!NorthboundUtils.isAuthorized(
+                getUserName(), containerName, Privilege.READ, this)) {
+            throw new UnauthorizedException(
+                    "User is not authorized to perform this operation on container "
+                            + containerName);
+        }
+
+        IAffinityManager affinityManager = getIfAffinityManagerService(containerName);
+        if (affinityManager == null) {
+            throw new ServiceUnavailableException("Affinity Manager "
+                    + RestMessages.SERVICEUNAVAILABLE.toString());
+        }
+        return new Affinities(affinityManager.getAffinityConfigList());
+    }
+    /**
+     * Returns details of affinityName affinity.
+     *
+     * @param containerName
+     *            Name of the Container. The Container name for the base
+     *            controller is "default".
+     * @param affinityName
+     *            Name of the affinity being retrieved.
+     * @return affinity configuration that matches the affinity name.
+     */
+    @Path("/{containerName}/{affinityName}")
+    @GET
+    @Produces({ MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML })
+    @TypeHint(AffinityConfig.class)
+    @StatusCodes({
+            @ResponseCode(code = 200, condition = "Operation successful"),
+            @ResponseCode(code = 404, condition = "The containerName is not found"),
+            @ResponseCode(code = 415, condition = "Affinity name is not found"),
+            @ResponseCode(code = 503, condition = "One or more of Controller Services are unavailable") })
+    public AffinityConfig getAffinityDetails(
+            @PathParam("containerName") String containerName,
+            @PathParam("affinityName") String affinityName) {
+        if (!NorthboundUtils.isAuthorized(
+                getUserName(), containerName, Privilege.READ, this)) {
+            throw new UnauthorizedException(
+                    "User is not authorized to perform this operation on container "
+                            + containerName);
+        }
+        IAffinityManager affinityManager = getIfAffinityManagerService(containerName);
+        if (affinityManager == null) {
+            throw new ServiceUnavailableException("Affinity "
+                                                  + RestMessages.SERVICEUNAVAILABLE.toString());
+        }
+
+        AffinityConfig ac = affinityManager.getAffinityConfig(affinityName);
+        if (ac == null) {
+            throw new ResourceNotFoundException(RestMessages.SERVICEUNAVAILABLE.toString());
+        } else {
+            return ac;
+        }
+    }
+    /**
+     * Delete an affinity
+     *
+     * @param containerName
+     *            Name of the Container
+     * @param affinityName
+     *            affinity name 'String'
+     * @return Response as dictated by the HTTP Response Status code
+     */
+
+    @Path("/{containerName}/{affinityName}")
+    @DELETE
+    @Consumes({ MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML })
+    @TypeHint(Response.class)
+    @StatusCodes({
+            @ResponseCode(code = 200, condition = "Operation successful"),
+            @ResponseCode(code = 404, condition = "The Container Name or nodeId or configuration name is not found"),
+            @ResponseCode(code = 503, condition = "One or more of Controller services are unavailable") })
+    public Response deleteAffinity(
+            @PathParam("containerName") String containerName,
+            @PathParam("affinityName") String affinityName) {
+
+        if (!NorthboundUtils.isAuthorized(
+                getUserName(), containerName, Privilege.WRITE, this)) {
+            throw new UnauthorizedException(
+                    "User is not authorized to perform this operation on container "
+                            + containerName);
+        }
+
+        IAffinityManager affinityManager = getIfAffinityManagerService(containerName);
+        if (affinityManager == null) {
+            throw new ServiceUnavailableException("Affinity Manager "
+                    + RestMessages.SERVICEUNAVAILABLE.toString());
+        }
+
+        Status ret = affinityManager.removeAffinityConfig(affinityName);
+        if (ret.isSuccess()) {
+            return Response.ok().build();
+        }
+        throw new ResourceNotFoundException(ret.getDescription());
+    }
+
+    /**
+     * Add an affinity to the configuration database
+     *
+     * @param containerName
+     *            Name of the Container
+     * @param affinityName
+     *            Name of the new affinity being added
+     * @param networkAddress1
+     *            IP address of the flow source
+     * @param networkAddress2
+     *            IP address of the flow destination
+     * @param affinityAttribute
+     *            Type of affinity being added
+     * @return Response as dictated by the HTTP Response Status code
+     */
+
+    @Path("/{containerName}/{affinityName}/{networkAddress1}/{networkAddress2}/{affinityAttribute}")
+    @PUT
+    @Consumes({ MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML })
+    @TypeHint(Response.class)
+    @StatusCodes({
+            @ResponseCode(code = 200, condition = "Operation successful"),
+            @ResponseCode(code = 404, condition = "The Container Name or nodeId or configuration name is not found"),
+            @ResponseCode(code = 503, condition = "One or more of Controller services are unavailable") })
+    public Response addAffinity(
+            @PathParam("containerName") String containerName,
+            @PathParam("affinityName") String affinityName,
+            @PathParam("networkAddress1") String networkAddress1,
+            @PathParam("networkAddress2") String networkAddress2,
+            @PathParam("affinityAttribute") String affinityAttribute) {
+
+        if (!NorthboundUtils.isAuthorized(getUserName(), containerName, Privilege.WRITE, this)) {
+            throw new UnauthorizedException("User is not authorized to perform this operation on container "
+                                            + containerName);
+        }
+
+        IAffinityManager affinityManager = getIfAffinityManagerService(containerName);
+        if (affinityManager == null) {
+            throw new ServiceUnavailableException("Affinity Manager "
+                                                  + RestMessages.SERVICEUNAVAILABLE.toString());
+        }
+
+        AffinityConfig ac = new AffinityConfig(affinityName, networkAddress1, networkAddress2, affinityAttribute);
+        Status ret = affinityManager.updateAffinityConfig(ac);
+        if (ret.isSuccess()) {
+            return Response.status(Response.Status.CREATED).build();
+        }
+        throw new InternalServerErrorException(ret.getDescription());
+    }
+}
diff --git a/affinity/northbound/src/main/java/org/opendaylight/controller/affinity/northbound/AffinityNorthboundRSApplication.java b/affinity/northbound/src/main/java/org/opendaylight/controller/affinity/northbound/AffinityNorthboundRSApplication.java
new file mode 100644 (file)
index 0000000..af0ccd4
--- /dev/null
@@ -0,0 +1,30 @@
+
+/*
+ * Copyright (c) 2013 Plexxi, 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.affinity.northbound;
+
+import java.util.HashSet;
+import java.util.Set;
+import javax.ws.rs.core.Application;
+
+/**
+ * Instance of javax.ws.rs.core.Application used to return the classes
+ * that will be instantiated for JAXRS processing, this is necessary
+ * because the package scanning in jersey doesn't yet work in OSGi
+ * environment.
+ *
+ */
+public class AffinityNorthboundRSApplication extends Application {
+    @Override
+    public Set<Class<?>> getClasses() {
+        Set<Class<?>> classes = new HashSet<Class<?>>();
+        classes.add(AffinityNorthbound.class);
+        return classes;
+    }
+}
diff --git a/affinity/northbound/src/main/resources/META-INF/MANIFEST.MF b/affinity/northbound/src/main/resources/META-INF/MANIFEST.MF
new file mode 100644 (file)
index 0000000..325f59a
--- /dev/null
@@ -0,0 +1,33 @@
+Manifest-Version: 1.0\r
+Bnd-LastModified: 1376940269425\r
+Build-Jdk: 1.6.0_37\r
+Built-By: sraman\r
+Bundle-ManifestVersion: 2\r
+Bundle-Name: northbound\r
+Bundle-SymbolicName: org.opendaylight.controller.affinity.northbound\r
+Bundle-Version: 0.4.0.SNAPSHOT\r
+Created-By: Apache Maven Bundle Plugin\r
+Export-Package: org.opendaylight.controller.affinity.northbound;uses:="o\r
+ rg.opendaylight.controller.affinity,javax.xml.bind.annotation,javax.ws.\r
+ rs,org.opendaylight.controller.northbound.commons,org.opendaylight.cont\r
+ roller.sal.utils,org.opendaylight.controller.containermanager,org.opend\r
+ aylight.controller.sal.authorization,org.opendaylight.controller.northb\r
+ ound.commons.utils,org.opendaylight.controller.northbound.commons.excep\r
+ tion,javax.ws.rs.core";version="0.4.0.SNAPSHOT"\r
+Ignore-Package: org.codehaus.enunciate.jaxrs\r
+Import-Package: com.sun.jersey.spi.container.servlet;version="[1.17,2)",\r
+ javax.ws.rs;version="[1.1,2)",javax.ws.rs.core;version="[1.1,2)",javax.\r
+ xml.bind,javax.xml.bind.annotation,org.apache.commons.lang3.tuple;versi\r
+ on="[3.1,4)",org.apache.commons.logging;version="[1.1,2)",org.opendayli\r
+ ght.controller.affinity;version="[0.4,1)",org.opendaylight.controller.c\r
+ ontainermanager;version="[0.4,1)",org.opendaylight.controller.northboun\r
+ d.commons;version="[0.4,1)",org.opendaylight.controller.northbound.comm\r
+ ons.exception;version="[0.4,1)",org.opendaylight.controller.northbound.\r
+ commons.utils;version="[0.4,1)",org.opendaylight.controller.sal.authori\r
+ zation;version="[0.5,1)",org.opendaylight.controller.sal.core;version="\r
+ [0.5,1)",org.opendaylight.controller.sal.utils;version="[0.5,1)",org.op\r
+ endaylight.controller.usermanager;version="[0.4,1)",org.slf4j;version="\r
+ [1.7,2)"\r
+Originally-Created-By: Apache Maven Bundle Plugin\r
+Tool: Bnd-1.50.0\r
+Web-ContextPath: /controller/nb/v2/affinity\r
diff --git a/affinity/northbound/src/main/resources/META-INF/spring.factories b/affinity/northbound/src/main/resources/META-INF/spring.factories
new file mode 100644 (file)
index 0000000..93db02e
--- /dev/null
@@ -0,0 +1 @@
+org.springframework.beans.BeanInfoFactory=org.springframework.beans.ExtendedBeanInfoFactory
diff --git a/affinity/northbound/src/main/resources/META-INF/spring.handlers b/affinity/northbound/src/main/resources/META-INF/spring.handlers
new file mode 100644 (file)
index 0000000..957af91
--- /dev/null
@@ -0,0 +1,10 @@
+http\://www.springframework.org/schema/context=org.springframework.context.config.ContextNamespaceHandler
+http\://www.springframework.org/schema/jee=org.springframework.ejb.config.JeeNamespaceHandler
+http\://www.springframework.org/schema/lang=org.springframework.scripting.config.LangNamespaceHandler
+http\://www.springframework.org/schema/task=org.springframework.scheduling.config.TaskNamespaceHandler
+http\://www.springframework.org/schema/cache=org.springframework.cache.config.CacheNamespaceHandler
+http\://www.springframework.org/schema/c=org.springframework.beans.factory.xml.SimpleConstructorNamespaceHandler
+http\://www.springframework.org/schema/p=org.springframework.beans.factory.xml.SimplePropertyNamespaceHandler
+http\://www.springframework.org/schema/util=org.springframework.beans.factory.xml.UtilNamespaceHandler
+http\://www.springframework.org/schema/mvc=org.springframework.web.servlet.config.MvcNamespaceHandler
+http\://www.springframework.org/schema/security=org.springframework.security.config.SecurityNamespaceHandler
diff --git a/affinity/northbound/src/main/resources/META-INF/spring.schemas b/affinity/northbound/src/main/resources/META-INF/spring.schemas
new file mode 100644 (file)
index 0000000..d865edc
--- /dev/null
@@ -0,0 +1,49 @@
+http\://www.springframework.org/schema/beans/spring-beans-2.0.xsd=org/springframework/beans/factory/xml/spring-beans-2.0.xsd
+http\://www.springframework.org/schema/beans/spring-beans-2.5.xsd=org/springframework/beans/factory/xml/spring-beans-2.5.xsd
+http\://www.springframework.org/schema/beans/spring-beans-3.0.xsd=org/springframework/beans/factory/xml/spring-beans-3.0.xsd
+http\://www.springframework.org/schema/beans/spring-beans-3.1.xsd=org/springframework/beans/factory/xml/spring-beans-3.1.xsd
+http\://www.springframework.org/schema/beans/spring-beans-3.2.xsd=org/springframework/beans/factory/xml/spring-beans-3.2.xsd
+http\://www.springframework.org/schema/beans/spring-beans.xsd=org/springframework/beans/factory/xml/spring-beans-3.2.xsd
+http\://www.springframework.org/schema/tool/spring-tool-2.0.xsd=org/springframework/beans/factory/xml/spring-tool-2.0.xsd
+http\://www.springframework.org/schema/tool/spring-tool-2.5.xsd=org/springframework/beans/factory/xml/spring-tool-2.5.xsd
+http\://www.springframework.org/schema/tool/spring-tool-3.0.xsd=org/springframework/beans/factory/xml/spring-tool-3.0.xsd
+http\://www.springframework.org/schema/tool/spring-tool-3.1.xsd=org/springframework/beans/factory/xml/spring-tool-3.1.xsd
+http\://www.springframework.org/schema/tool/spring-tool-3.2.xsd=org/springframework/beans/factory/xml/spring-tool-3.2.xsd
+http\://www.springframework.org/schema/tool/spring-tool.xsd=org/springframework/beans/factory/xml/spring-tool-3.2.xsd
+http\://www.springframework.org/schema/util/spring-util-2.0.xsd=org/springframework/beans/factory/xml/spring-util-2.0.xsd
+http\://www.springframework.org/schema/util/spring-util-2.5.xsd=org/springframework/beans/factory/xml/spring-util-2.5.xsd
+http\://www.springframework.org/schema/util/spring-util-3.0.xsd=org/springframework/beans/factory/xml/spring-util-3.0.xsd
+http\://www.springframework.org/schema/util/spring-util-3.1.xsd=org/springframework/beans/factory/xml/spring-util-3.1.xsd
+http\://www.springframework.org/schema/util/spring-util-3.2.xsd=org/springframework/beans/factory/xml/spring-util-3.2.xsd
+http\://www.springframework.org/schema/util/spring-util.xsd=org/springframework/beans/factory/xml/spring-util-3.2.xsd
+http\://www.springframework.org/schema/context/spring-context-2.5.xsd=org/springframework/context/config/spring-context-2.5.xsd
+http\://www.springframework.org/schema/context/spring-context-3.0.xsd=org/springframework/context/config/spring-context-3.0.xsd
+http\://www.springframework.org/schema/context/spring-context-3.1.xsd=org/springframework/context/config/spring-context-3.1.xsd
+http\://www.springframework.org/schema/context/spring-context-3.2.xsd=org/springframework/context/config/spring-context-3.2.xsd
+http\://www.springframework.org/schema/context/spring-context.xsd=org/springframework/context/config/spring-context-3.2.xsd
+http\://www.springframework.org/schema/jee/spring-jee-2.0.xsd=org/springframework/ejb/config/spring-jee-2.0.xsd
+http\://www.springframework.org/schema/jee/spring-jee-2.5.xsd=org/springframework/ejb/config/spring-jee-2.5.xsd
+http\://www.springframework.org/schema/jee/spring-jee-3.0.xsd=org/springframework/ejb/config/spring-jee-3.0.xsd
+http\://www.springframework.org/schema/jee/spring-jee-3.1.xsd=org/springframework/ejb/config/spring-jee-3.1.xsd
+http\://www.springframework.org/schema/jee/spring-jee-3.2.xsd=org/springframework/ejb/config/spring-jee-3.2.xsd
+http\://www.springframework.org/schema/jee/spring-jee.xsd=org/springframework/ejb/config/spring-jee-3.2.xsd
+http\://www.springframework.org/schema/lang/spring-lang-2.0.xsd=org/springframework/scripting/config/spring-lang-2.0.xsd
+http\://www.springframework.org/schema/lang/spring-lang-2.5.xsd=org/springframework/scripting/config/spring-lang-2.5.xsd
+http\://www.springframework.org/schema/lang/spring-lang-3.0.xsd=org/springframework/scripting/config/spring-lang-3.0.xsd
+http\://www.springframework.org/schema/lang/spring-lang-3.1.xsd=org/springframework/scripting/config/spring-lang-3.1.xsd
+http\://www.springframework.org/schema/lang/spring-lang-3.2.xsd=org/springframework/scripting/config/spring-lang-3.2.xsd
+http\://www.springframework.org/schema/lang/spring-lang.xsd=org/springframework/scripting/config/spring-lang-3.2.xsd
+http\://www.springframework.org/schema/task/spring-task-3.0.xsd=org/springframework/scheduling/config/spring-task-3.0.xsd
+http\://www.springframework.org/schema/task/spring-task-3.1.xsd=org/springframework/scheduling/config/spring-task-3.1.xsd
+http\://www.springframework.org/schema/task/spring-task-3.2.xsd=org/springframework/scheduling/config/spring-task-3.2.xsd
+http\://www.springframework.org/schema/task/spring-task.xsd=org/springframework/scheduling/config/spring-task-3.2.xsd
+http\://www.springframework.org/schema/cache/spring-cache-3.1.xsd=org/springframework/cache/config/spring-cache-3.1.xsd
+http\://www.springframework.org/schema/cache/spring-cache-3.2.xsd=org/springframework/cache/config/spring-cache-3.2.xsd
+http\://www.springframework.org/schema/cache/spring-cache.xsd=org/springframework/cache/config/spring-cache-3.2.xsd
+http\://www.springframework.org/schema/mvc/spring-mvc-3.0.xsd=org/springframework/web/servlet/config/spring-mvc-3.0.xsd
+http\://www.springframework.org/schema/mvc/spring-mvc-3.1.xsd=org/springframework/web/servlet/config/spring-mvc-3.1.xsd
+http\://www.springframework.org/schema/mvc/spring-mvc-3.2.xsd=org/springframework/web/servlet/config/spring-mvc-3.2.xsd
+http\://www.springframework.org/schema/mvc/spring-mvc.xsd=org/springframework/web/servlet/config/spring-mvc-3.2.xsd
+http\://www.springframework.org/schema/security/spring-security-3.1.xsd=org/springframework/security/config/spring-security-3.1.xsd
+http\://www.springframework.org/schema/security/spring-security-3.2.xsd=org/springframework/security/config/spring-security-3.2.xsd
+
diff --git a/affinity/northbound/src/main/resources/META-INF/spring.tooling b/affinity/northbound/src/main/resources/META-INF/spring.tooling
new file mode 100644 (file)
index 0000000..057d834
--- /dev/null
@@ -0,0 +1,39 @@
+# Tooling related information for the beans namespace
+http\://www.springframework.org/schema/beans@name=beans Namespace
+http\://www.springframework.org/schema/beans@prefix=beans
+http\://www.springframework.org/schema/beans@icon=org/springframework/beans/factory/xml/spring-beans.gif
+
+# Tooling related information for the util namespace
+http\://www.springframework.org/schema/util@name=util Namespace
+http\://www.springframework.org/schema/util@prefix=util
+http\://www.springframework.org/schema/util@icon=org/springframework/beans/factory/xml/spring-util.gif
+
+# Tooling related information for the context namespace
+http\://www.springframework.org/schema/context@name=context Namespace
+http\://www.springframework.org/schema/context@prefix=context
+http\://www.springframework.org/schema/context@icon=org/springframework/context/config/spring-context.gif
+
+# Tooling related information for the jee namespace
+http\://www.springframework.org/schema/jee@name=jee Namespace
+http\://www.springframework.org/schema/jee@prefix=jee
+http\://www.springframework.org/schema/jee@icon=org/springframework/ejb/config/spring-jee.gif
+
+# Tooling related information for the scheduling namespace
+http\://www.springframework.org/schema/task@name=task Namespace
+http\://www.springframework.org/schema/task@prefix=task
+http\://www.springframework.org/schema/task@icon=org/springframework/scheduling/config/spring-task.gif
+
+# Tooling related information for the lang namespace
+http\://www.springframework.org/schema/lang@name=lang Namespace
+http\://www.springframework.org/schema/lang@prefix=lang
+http\://www.springframework.org/schema/lang@icon=org/springframework/scripting/config/spring-lang.gif
+
+# Tooling related information for the cache namespace
+http\://www.springframework.org/schema/cache@name=cache Namespace
+http\://www.springframework.org/schema/cache@prefix=cache
+http\://www.springframework.org/schema/cache@icon=org/springframework/cache/config/spring-cache.gif
+
+# Tooling related information for the mvc namespace
+http\://www.springframework.org/schema/mvc@name=mvc Namespace
+http\://www.springframework.org/schema/mvc@prefix=mvc
+http\://www.springframework.org/schema/mvc@icon=org/springframework/web/servlet/config/spring-mvc.gif
diff --git a/affinity/northbound/src/main/resources/WEB-INF/web.xml b/affinity/northbound/src/main/resources/WEB-INF/web.xml
new file mode 100644 (file)
index 0000000..188b21b
--- /dev/null
@@ -0,0 +1,50 @@
+<?xml version="1.0" encoding="ISO-8859-1"?>
+<web-app xmlns="http://java.sun.com/xml/ns/javaee" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+        xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd"
+        version="3.0">
+  <servlet>
+    <servlet-name>JAXRSSwitchManager</servlet-name>
+    <servlet-class>com.sun.jersey.spi.container.servlet.ServletContainer</servlet-class>
+    <init-param>
+      <param-name>javax.ws.rs.Application</param-name>
+      <param-value>org.opendaylight.controller.switchmanager.northbound.SwitchNorthboundRSApplication</param-value>
+    </init-param>
+    <load-on-startup>1</load-on-startup>
+  </servlet>
+
+  <servlet-mapping>
+    <servlet-name>JAXRSSwitchManager</servlet-name>
+    <url-pattern>/*</url-pattern>
+  </servlet-mapping>
+
+        <security-constraint>
+                <web-resource-collection>
+                        <web-resource-name>NB api</web-resource-name>
+                        <url-pattern>/*</url-pattern>
+                </web-resource-collection>
+                <auth-constraint>
+                        <role-name>System-Admin</role-name>
+                        <role-name>Network-Admin</role-name>
+                        <role-name>Network-Operator</role-name>
+                        <role-name>Container-User</role-name>
+                </auth-constraint>
+        </security-constraint>
+
+        <security-role>
+                <role-name>System-Admin</role-name>
+        </security-role>
+        <security-role>
+                <role-name>Network-Admin</role-name>
+        </security-role>
+        <security-role>
+                <role-name>Network-Operator</role-name>
+        </security-role>
+        <security-role>
+                <role-name>Container-User</role-name>
+        </security-role>
+
+        <login-config>
+                <auth-method>BASIC</auth-method>
+                <realm-name>opendaylight</realm-name>
+        </login-config>
+</web-app>
\ No newline at end of file
diff --git a/analytics/pom.xml b/analytics/pom.xml
new file mode 100644 (file)
index 0000000..d63315d
--- /dev/null
@@ -0,0 +1,90 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<project xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd" xmlns="http://maven.apache.org/POM/4.0.0"
+    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
+  <modelVersion>4.0.0</modelVersion>
+  <parent>
+    <groupId>org.opendaylight.controller</groupId>
+    <artifactId>affinity</artifactId>
+    <version>0.4.1-SNAPSHOT</version>
+    <relativePath>..</relativePath>
+  </parent>
+
+  <artifactId>analytics</artifactId>
+  <version>0.4.1-SNAPSHOT</version>
+  <packaging>bundle</packaging>
+
+  <build>
+    <plugins>
+      <plugin>
+        <groupId>org.apache.felix</groupId>
+        <artifactId>maven-bundle-plugin</artifactId>
+        <version>2.3.6</version>
+        <extensions>true</extensions>
+        <configuration>
+          <instructions>
+            <Import-Package>
+              org.opendaylight.controller.clustering.services,
+              org.opendaylight.controller.containermanager,
+              org.opendaylight.controller.forwardingrulesmanager,
+              org.opendaylight.controller.hosttracker,
+              org.opendaylight.controller.hosttracker.hostAware,
+              org.opendaylight.controller.sal.core,
+              org.opendaylight.controller.sal.flowprogrammer,
+              org.opendaylight.controller.sal.inventory,
+              org.opendaylight.controller.sal.match,
+              org.opendaylight.controller.sal.packet,
+              org.opendaylight.controller.sal.packet.address,
+              org.opendaylight.controller.sal.reader,
+              org.opendaylight.controller.sal.utils,
+              org.opendaylight.controller.statisticsmanager,
+              org.opendaylight.controller.switchmanager,
+              org.apache.felix.dm,
+              org.slf4j
+            </Import-Package>
+            <Bundle-Activator>
+              org.opendaylight.controller.analytics.internal.Activator
+            </Bundle-Activator>
+          </instructions>
+          <manifestLocation>${project.basedir}/META-INF</manifestLocation>
+        </configuration>
+      </plugin>
+    </plugins>
+  </build>
+  <dependencies>
+    <dependency>
+      <groupId>org.opendaylight.controller</groupId>
+      <artifactId>containermanager</artifactId>
+      <version>0.4.0-SNAPSHOT</version>
+    </dependency>
+    <dependency>
+      <groupId>org.opendaylight.controller</groupId>
+      <artifactId>clustering.services</artifactId>
+      <version>0.4.0-SNAPSHOT</version>
+    </dependency>
+    <dependency>
+      <groupId>org.opendaylight.controller</groupId>
+      <artifactId>forwardingrulesmanager</artifactId>
+      <version>0.4.0-SNAPSHOT</version>
+    </dependency>
+    <dependency>
+      <groupId>org.opendaylight.controller</groupId>
+      <artifactId>hosttracker</artifactId>
+      <version>0.4.0-SNAPSHOT</version>
+    </dependency>
+    <dependency>
+      <groupId>org.opendaylight.controller</groupId>
+      <artifactId>sal</artifactId>
+      <version>0.5.0-SNAPSHOT</version>
+    </dependency>
+    <dependency>
+      <groupId>org.opendaylight.controller</groupId>
+      <artifactId>statisticsmanager</artifactId>
+      <version>0.4.0-SNAPSHOT</version>
+    </dependency>
+    <dependency>
+      <groupId>org.opendaylight.controller</groupId>
+      <artifactId>switchmanager</artifactId>
+      <version>0.4.0-SNAPSHOT</version>
+    </dependency>
+  </dependencies>
+</project>
diff --git a/analytics/src/main/java/org/opendaylight/controller/analytics/internal/Activator.java b/analytics/src/main/java/org/opendaylight/controller/analytics/internal/Activator.java
new file mode 100644 (file)
index 0000000..9d1d007
--- /dev/null
@@ -0,0 +1,82 @@
+/*
+ * Copyright (c) 2013 Plexxi, Inc.  All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+
+package org.opendaylight.controller.analytics.internal;
+
+import org.apache.felix.dm.Component;
+
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import org.opendaylight.controller.hosttracker.IfIptoHost;
+import org.opendaylight.controller.hosttracker.IfHostListener;
+import org.opendaylight.controller.sal.core.ComponentActivatorAbstractBase;
+import org.opendaylight.controller.sal.reader.IReadServiceListener;
+import org.opendaylight.controller.statisticsmanager.IStatisticsManager;
+import org.opendaylight.controller.switchmanager.ISwitchManager;
+
+public class Activator extends ComponentActivatorAbstractBase {
+    protected static final Logger logger = LoggerFactory
+            .getLogger(Activator.class);
+
+    /**
+     * Function called when the activator starts just after some
+     * initializations are done by the
+     * ComponentActivatorAbstractBase.
+     */
+    public void init() {
+    }
+
+    /**
+     * Function called when the activator stops just before the
+     * cleanup done by ComponentActivatorAbstractBase
+     */
+    public void destroy() {
+    }
+
+    /**
+     * Function that is used to communicate to dependency manager the
+     * list of known implementations for services inside a container
+     *
+     * @return An array containing all the CLASS objects that will be
+     * instantiated in order to get an fully working implementation
+     * Object
+     */
+    public Object[] getImplementations() {
+        Object[] res = { AnalyticsManager.class };
+        return res;
+    }
+
+    /**
+     * Function that is called when configuration of the dependencies
+     * is required.
+     *
+     * @param c dependency manager Component object, used for
+     * configuring the dependencies exported and imported
+     * @param imp Implementation class that is being configured,
+     * needed as long as the same routine can configure multiple
+     * implementations
+     * @param containerName The containerName being configured, this allow
+     * also optional per-container different behavior if needed, usually
+     * should not be the case though.
+     */
+    public void configureInstance(Component c, Object imp, String containerName) {
+        if (imp.equals(AnalyticsManager.class)) {
+            // set interfaces
+            c.setInterface(new String[] {
+                    IReadServiceListener.class.getName() }, null);
+
+            c.add(createContainerServiceDependency(containerName).setService(IfIptoHost.class)
+                  .setCallbacks("setHostTracker", "unsetHostTracker").setRequired(true));
+            c.add(createServiceDependency().setService(IStatisticsManager.class)
+                  .setCallbacks("setStatisticsManager", "unsetStatisticsManager").setRequired(false));
+            c.add(createContainerServiceDependency(containerName).setService(ISwitchManager.class)
+                  .setCallbacks("setSwitchManager", "unsetSwitchManager").setRequired(true));
+        }
+    }
+}
diff --git a/analytics/src/main/java/org/opendaylight/controller/analytics/internal/AnalyticsManager.java b/analytics/src/main/java/org/opendaylight/controller/analytics/internal/AnalyticsManager.java
new file mode 100644 (file)
index 0000000..b2edc0b
--- /dev/null
@@ -0,0 +1,256 @@
+/*
+ * Copyright (c) 2013 Plexxi, Inc.  All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+
+package org.opendaylight.controller.analytics.internal;
+
+import java.lang.reflect.Constructor;
+import java.net.InetAddress;
+import java.net.UnknownHostException;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+import java.util.concurrent.Future;
+
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import org.opendaylight.controller.containermanager.IContainerManager;
+import org.opendaylight.controller.hosttracker.IfIptoHost;
+import org.opendaylight.controller.hosttracker.IfHostListener;
+import org.opendaylight.controller.hosttracker.hostAware.HostNodeConnector;
+import org.opendaylight.controller.sal.core.Host;
+import org.opendaylight.controller.sal.core.Node;
+import org.opendaylight.controller.sal.core.NodeConnector;
+import org.opendaylight.controller.sal.flowprogrammer.Flow;
+import org.opendaylight.controller.sal.match.Match;
+import org.opendaylight.controller.sal.match.MatchField;
+import org.opendaylight.controller.sal.match.MatchType;
+import org.opendaylight.controller.sal.packet.address.DataLinkAddress;
+import org.opendaylight.controller.sal.packet.address.EthernetAddress;
+import org.opendaylight.controller.sal.reader.FlowOnNode;
+import org.opendaylight.controller.sal.reader.IReadServiceListener;
+import org.opendaylight.controller.sal.reader.NodeConnectorStatistics;
+import org.opendaylight.controller.sal.reader.NodeDescription;
+import org.opendaylight.controller.sal.reader.NodeTableStatistics;
+import org.opendaylight.controller.sal.utils.ServiceHelper;
+import org.opendaylight.controller.sal.utils.Status;
+import org.opendaylight.controller.statisticsmanager.IStatisticsManager;
+import org.opendaylight.controller.switchmanager.ISwitchManager;
+import org.opendaylight.controller.switchmanager.SubnetConfig;
+
+public class AnalyticsManager implements IReadServiceListener {
+
+    private static final Logger log = LoggerFactory.getLogger(AnalyticsManager.class);
+
+    private IStatisticsManager statisticsManager;
+    private ISwitchManager switchManager;
+    private IfIptoHost hostTracker;
+
+    private Map<Host, Map<Host, Object>> hostToFlowStats; // TODO: Tighter object types
+    private Map<MatchField, Host> destinationHostCache;
+    private Map<MatchField, Host> sourceHostCache;
+
+    void init() {
+        log.debug("INIT called!");
+        this.hostToFlowStats = new HashMap<Host, Map<Host, Object>>();
+        this.destinationHostCache = new HashMap<MatchField, Host>();
+        this.sourceHostCache = new HashMap<MatchField, Host>();
+    }
+
+    void destroy() {
+        log.debug("DESTROY called!");
+    }
+
+    void start() {
+        log.debug("START called!");
+    }
+
+    void started(){
+    }
+
+    void stop() {
+        log.debug("STOP called!");
+    }
+
+    void setStatisticsManager(IStatisticsManager s) {
+        this.statisticsManager = s;
+    }
+
+    void unsetStatisticsManager(IStatisticsManager s) {
+        if (this.statisticsManager.equals(s)) {
+            this.statisticsManager = null;
+        }
+    }
+
+    void setHostTracker(IfIptoHost h) {
+        this.hostTracker = h;
+    }
+
+    void unsetHostTracker(IfIptoHost h) {
+        if (this.hostTracker.equals(h)) {
+            this.hostTracker = null;
+        }
+    }
+
+    void setSwitchManager(ISwitchManager s) {
+        this.switchManager = s;
+
+        // Add a default subnet to allow the hostTracker to populate
+        // the host lists.
+        //
+        // TODO: Is this really the correct way to get the hosts
+        // populated?
+        //
+        // TODO: This is should really use the second SubnetConfig
+        // constructor; see a note in that file.
+        SubnetConfig defaultSubnet = new SubnetConfig();
+        this.switchManager.addSubnet(defaultSubnet);
+    }
+
+    void unsetSwitchManager(ISwitchManager s) {
+        if (this.switchManager.equals(s)) {
+            this.switchManager = null;
+        }
+    }
+
+    /* Returns the destination host associated with this flow, if one
+     * exists.  Returns null otherwise.
+     */
+    private Host getDestinationHostFromFlow(Flow flow) {
+        Host dstHost = null;
+        Match match = flow.getMatch();
+
+        // Flow has to have DL_DST field
+        if (match.isPresent(MatchType.DL_DST)) {
+            MatchField dlDst = match.getField(MatchType.DL_DST);
+
+            // Check cache
+            Host cacheHit = this.destinationHostCache.get(dlDst);
+            if (cacheHit != null) {
+                return cacheHit;
+            }
+
+            // Find the destination host by comparing the MAC address
+            // strings (comparing MAC address bytes, surprisingly, did
+            // not work).
+            String dstMac = MatchType.DL_DST.stringify(dlDst.getValue());
+            for (HostNodeConnector h : this.hostTracker.getAllHosts()) {
+                String hostMac = ((EthernetAddress) h.getDataLayerAddress()).getMacAddress();
+                if (dstMac.equals(hostMac)) {
+                    dstHost = h;
+                    this.destinationHostCache.put(dlDst, dstHost); // Add to cache
+                    break;
+                }
+            }
+        }
+
+        return dstHost;
+    }
+
+    /* Returns the source Host associated with this flow, if one
+     * exists.  Returns null otherwise.
+     */
+    private Host getSourceHostFromFlow(Flow flow) {
+        Host srcHost = null;
+        Match match = flow.getMatch();
+
+        // Flow must have IN_PORT field (DL_SRC rarely (never?)
+        // exists).
+        if (match.isPresent(MatchType.IN_PORT)) {
+            MatchField inPort = match.getField(MatchType.IN_PORT);
+
+            // Check cache
+            Host cacheHit = this.sourceHostCache.get(inPort);
+            if (cacheHit != null) {
+                return cacheHit;
+            }
+
+            // Find the source host by comparing the NodeConnectors
+            NodeConnector inPortNc = (NodeConnector) inPort.getValue();
+            for (HostNodeConnector h : this.hostTracker.getAllHosts()) {
+                NodeConnector hostNc = h.getnodeConnector();
+                if (hostNc.equals(inPortNc)) {
+                    srcHost = h;
+                    this.sourceHostCache.put(inPort, h); // Add to cache
+                    break;
+                }
+            }
+        }
+
+        return srcHost;
+    }
+
+    public long getByteCountBetweenHosts(Host src, Host dst) {
+
+        // TODO: Need a cache so that we don't have to search through all nodes.
+
+        List<FlowOnNode> relevantFlows = new ArrayList<FlowOnNode>();
+
+        Set<Node> allNodes = this.switchManager.getNodes();
+        for (Node node : allNodes) {
+            List<FlowOnNode> flowsOnNode = this.statisticsManager.getFlows(node);
+            for (FlowOnNode f : flowsOnNode) {
+                Host dstHost = getDestinationHostFromFlow(f.getFlow());
+                Host srcHost = getSourceHostFromFlow(f.getFlow());
+
+                // This does not indicate error, it's just a flow we're
+                // not interested in (ARP traffic, e.g.)
+                if (dstHost == null || srcHost == null) {
+                    continue;
+                }
+
+                if (dstHost.equals(dst) && srcHost.equals(src)) {
+                    relevantFlows.add(f);
+                }
+            }
+        }
+
+        long byteCount = 0;
+        for (FlowOnNode f : relevantFlows) {
+            if (f.getByteCount() > byteCount) {
+                byteCount = f.getByteCount();
+            }
+        }
+
+        return byteCount;
+    }
+
+    @Override
+    public void nodeFlowStatisticsUpdated(Node node, List<FlowOnNode> flowStatsList) {
+        // TODO: un-comment out if testing
+        /*
+        for (HostNodeConnector h1 : this.hostTracker.getAllHosts()) {
+            for (HostNodeConnector h2 : this.hostTracker.getAllHosts()) {
+                long b = getByteCountBetweenHosts(h1, h2);
+                System.out.println("!!! result:");
+                System.out.println("!!!   " + h1);
+                System.out.println("!!!   " + h2);
+                System.out.println("!!!   " + b);
+            }
+            }*/
+    }
+
+    @Override
+    public void nodeConnectorStatisticsUpdated(Node node, List<NodeConnectorStatistics> ncStatsList) {
+        // Not interested in this update
+    }
+
+    @Override
+    public void nodeTableStatisticsUpdated(Node node, List<NodeTableStatistics> tableStatsList) {
+        // Not interested in this update
+    }
+
+    @Override
+    public void descriptionStatisticsUpdated(Node node, NodeDescription nodeDescription) {
+        // Not interested in this update
+    }
+}
diff --git a/analytics/src/test/java/org/opendaylight/controller/analytics/internal/AnalyticsManagerTest.java b/analytics/src/test/java/org/opendaylight/controller/analytics/internal/AnalyticsManagerTest.java
new file mode 100644 (file)
index 0000000..5058bc7
--- /dev/null
@@ -0,0 +1,25 @@
+/*\r
+ * Copyright (c) 2013 Plexxi, Inc.  All rights reserved.\r
+ *\r
+ * This program and the accompanying materials are made available under the\r
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,\r
+ * and is available at http://www.eclipse.org/legal/epl-v10.html\r
+ */\r
+\r
+package org.opendaylight.controller.analytics.internal;\r
+\r
+\r
+import junit.framework.TestCase;\r
+\r
+import org.junit.Assert;\r
+import org.junit.Test;\r
+\r
+public class AnalyticsManagerTest extends TestCase {\r
+\r
+        @Test\r
+        public void testAnalyticsManagerCreation() {\r
+                AnalyticsManager am = new AnalyticsManager();\r
+                Assert.assertTrue(am != null);\r
+        }\r
+\r
+}\r
diff --git a/pom.xml b/pom.xml
new file mode 100644 (file)
index 0000000..7ce0e7c
--- /dev/null
+++ b/pom.xml
@@ -0,0 +1,166 @@
+<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">\r
+  <modelVersion>4.0.0</modelVersion>\r
+    <groupId>org.opendaylight.controller</groupId>\r
+    <artifactId>affinity</artifactId>\r
+    <version>0.4.1-SNAPSHOT</version>\r
+    <packaging>pom</packaging>\r
+\r
+  <scm>\r
+    <connection>scm:git:http://git.opendaylight.org/gerrit/p/affinity.git</connection>\r
+    <developerConnection>scm:git:ssh://git.opendaylight.org:29418/affinity.git</developerConnection>\r
+  </scm>\r
+      <properties>\r
+       <propertymavenplugin.version>1.0-alpha-2</propertymavenplugin.version>\r
+       <sonar.host.url>https://sonar.opendaylight.org/</sonar.host.url>\r
+       <sitedeploy>dav:http://nexus.opendaylight.org/content/sites/site</sitedeploy>\r
+       <siteplugin>3.2</siteplugin>\r
+       <projectinfo>2.6</projectinfo>\r
+       <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>\r
+       <compiler.version>2.3.2</compiler.version>\r
+       <surefire.version>2.15</surefire.version>\r
+       <failsafe.version>2.15</failsafe.version>\r
+       <exam.version>3.0.0</exam.version>\r
+       <url.version>1.5.0</url.version>\r
+       <enunciate.version>1.26.2</enunciate.version>\r
+       <sonar.branch>${user.name}-private-view</sonar.branch>\r
+       <sonar.skippedModules>org.openflow.openflowj,net.sf.jung2</sonar.skippedModules>\r
+       <logback.version>1.0.9</logback.version>\r
+       <slf4j.version>1.7.2</slf4j.version>\r
+       <jackson.version>1.9.8</jackson.version>\r
+       <spring.version>3.1.3.RELEASE</spring.version>\r
+       <spring-security.version>3.1.3.RELEASE</spring-security.version>\r
+       <jersey.version>1.17</jersey.version>\r
+       <virgo.version>3.6.0.RELEASE</virgo.version>\r
+       <geminiweb.version>2.2.0.RELEASE</geminiweb.version>\r
+       <checkstyle.version>2.10</checkstyle.version>\r
+       <testvm.argLine>-Xmx1024m -XX:MaxPermSize=256m</testvm.argLine>\r
+      </properties>\r
+\r
+    <modules>\r
+       <module>affinity/api</module>\r
+       <module>affinity/implementation</module>\r
+       <module>affinity/northbound</module>\r
+       <module>analytics</module>\r
+    </modules>\r
+\r
+    <repositories>\r
+      <!-- To get SVNKit -->\r
+      <repository>\r
+       <id>svnkit-snapshots</id>\r
+       <name>svnkit-snapshots</name>\r
+       <url>${nexusproxy}/repositories/svnkit-snapshots/</url>\r
+      </repository>\r
+    <!-- OpenDayLight Released artifact -->\r
+    <repository>\r
+      <id>opendaylight-release</id>\r
+      <name>opendaylight-release</name>\r
+      <url>${nexusproxy}/repositories/opendaylight.release/</url>\r
+    </repository>\r
+    <!-- OpenDayLight Snapshot artifact -->\r
+    <repository>\r
+      <id>opendaylight-snapshot</id>\r
+      <name>opendaylight-snapshot</name>\r
+      <url>${nexusproxy}/repositories/opendaylight.snapshot/</url>\r
+    </repository>\r
+    </repositories>\r
+  <distributionManagement>\r
+    <!-- OpenDayLight Released artifact -->\r
+    <repository>\r
+      <id>opendaylight-release</id>\r
+      <url>${nexusproxy}/repositories/opendaylight.release/</url>\r
+    </repository>\r
+    <!-- OpenDayLight Snapshot artifact -->\r
+    <snapshotRepository>\r
+      <id>opendaylight-snapshot</id>\r
+      <url>${nexusproxy}/repositories/opendaylight.snapshot/</url>\r
+    </snapshotRepository>\r
+    <!-- Site deployment -->\r
+    <site>\r
+      <id>website</id>\r
+      <url>${sitedeploy}</url>\r
+    </site>\r
+  </distributionManagement>\r
+\r
+    <dependencies>\r
+\r
+        <dependency>\r
+            <groupId>junit</groupId>\r
+            <artifactId>junit</artifactId>\r
+            <version>4.10</version>\r
+            <scope>test</scope>\r
+            <optional>true</optional>\r
+        </dependency>\r
+        <dependency>\r
+            <groupId>org.slf4j</groupId>\r
+            <artifactId>slf4j-api</artifactId>\r
+            <version>1.7.2</version>\r
+        </dependency>\r
+        <dependency>\r
+            <groupId>org.slf4j</groupId>\r
+            <artifactId>slf4j-simple</artifactId>\r
+            <version>1.7.2</version>\r
+        </dependency>\r
+    </dependencies>\r
+\r
+  <build>\r
+    <plugins>\r
+      <plugin>\r
+        <groupId>org.codehaus.mojo</groupId>\r
+        <artifactId>buildnumber-maven-plugin</artifactId>\r
+        <version>1.2</version>\r
+        <executions>\r
+          <execution>\r
+            <phase>validate</phase>\r
+            <goals>\r
+              <goal>create</goal>\r
+            </goals>\r
+          </execution>\r
+        </executions>\r
+        <configuration>\r
+          <doCheck>false</doCheck>\r
+          <doUpdate>false</doUpdate>\r
+          <providerImplementations>\r
+            <svn>javasvn</svn>\r
+          </providerImplementations>\r
+          <revisionOnScmFailure>VersionUnknown</revisionOnScmFailure>\r
+        </configuration>\r
+        <dependencies>\r
+          <dependency>\r
+            <groupId>com.google.code.maven-scm-provider-svnjava</groupId>\r
+            <artifactId>maven-scm-provider-svnjava</artifactId>\r
+            <version>2.0.5</version>\r
+          </dependency>\r
+          <dependency>\r
+            <groupId>org.tmatesoft.svnkit</groupId>\r
+            <artifactId>svnkit</artifactId>\r
+            <version>1.7.4-v1</version>\r
+          </dependency>\r
+          <dependency>\r
+            <groupId>org.apache.maven.scm</groupId>\r
+            <artifactId>maven-scm-provider-svn-commons</artifactId>\r
+            <version>1.7</version>\r
+          </dependency>\r
+        </dependencies>\r
+      </plugin>\r
+    </plugins>\r
+  </build>\r
+    <reporting>\r
+        <plugins>\r
+            <plugin>\r
+                <groupId>org.codehaus.mojo</groupId>\r
+                <artifactId>findbugs-maven-plugin</artifactId>\r
+                <version>2.4.0</version>\r
+                <configuration>\r
+                    <effort>Max</effort>\r
+                    <threshold>Low</threshold>\r
+                    <goal>site</goal>\r
+                </configuration>\r
+            </plugin>\r
+            <plugin>\r
+                <groupId>org.codehaus.mojo</groupId>\r
+                <artifactId>jdepend-maven-plugin</artifactId>\r
+                <version>2.0-beta-2</version>\r
+            </plugin>\r
+        </plugins>\r
+    </reporting>\r
+</project>\r
diff --git a/scripts/affinity.py b/scripts/affinity.py
new file mode 100644 (file)
index 0000000..f3ca7ed
--- /dev/null
@@ -0,0 +1,27 @@
+import httplib2
+import json
+
+h = httplib2.Http(".cache")
+h.add_credentials('admin', 'admin')
+
+resp, content = h.request('http://localhost:8080/controller/nb/v2/affinity/default/affinities', "GET")
+content
+
+put_url = 'http://localhost:8080/controller/nb/v2/affinity/default/test1/192.168.1.1/192.168.1.2/isolate'
+resp, content = h.request(put_url, "PUT")
+resp
+content
+
+resp, content = h.request('http://localhost:8080/controller/nb/v2/affinity/default/affinities', "GET")
+content
+
+#####
+
+resp, content = h.request('http://localhost:8080/controller/nb/v2/statistics/default/flowstats', "GET")
+resp
+content
+
+post_url = 'http://localhost:8080/controller/nb/v2/affinity/default/affinity-config'
+resp, content = h.request(post_url, "POST")
+resp
+content
diff --git a/scripts/osgi.txt b/scripts/osgi.txt
new file mode 100644 (file)
index 0000000..20684c1
--- /dev/null
@@ -0,0 +1,15 @@
+install file:/Users/sraman/.m2/repository/org/opendaylight/controller/affinity/0.4.1-SNAPSHOT/affinity-0.4.1-SNAPSHOT.jar
+install file:/Users/sraman/.m2/repository/org/opendaylight/controller/affinity/implementation/0.4.1-SNAPSHOT/implementation-0.4.1-SNAPSHOT.jar
+install file:/Users/sraman/.m2/repository/org/opendaylight/controller/affinity/northbound/0.4.1-SNAPSHOT/northbound-0.4.1-SNAPSHOT.jar
+
+ss | grep affinity
+start <id_affinity>
+start <id_affinityapi>
+start <id_affinityimpl>
+
+# install file:/Users/sraman/.m2/repository/org/opendaylight/controller/tutorial_L2_forwarding/0.4.1-SNAPSHOT/tutorial_L2_forwarding-0.4.1-SNAPSHOT.jar
+#ls -l /Users/sraman/.m2/repository/org/opendaylight/controller/affinity/0.4.1-SNAPSHOT/affinity-0.4.1-SNAPSHOT.jar
+#ls -l /Users/sraman/.m2/repository/org/opendaylight/controller/affinity/implementation/0.4.1-SNAPSHOT/implementation-0.4.1-SNAPSHOT.jar
+#ls -l /Users/sraman/.m2/repository/org/opendaylight/controller/affinity/northbound/0.4.1-SNAPSHOT/northbound-0.4.1-SNAPSHOT.jar
+
+
diff --git a/scripts/stats.py b/scripts/stats.py
new file mode 100644 (file)
index 0000000..b0152fb
--- /dev/null
@@ -0,0 +1,31 @@
+import httplib2
+import json
+h = httplib2.Http(".cache")
+h.add_credentials('admin', 'admin')
+
+resp, content = h.request('http://localhost:8080/controller/nb/v2/statistics/default/flowstats', "GET")
+allFlowStats = json.loads(content)
+flowStats = allFlowStats['flowStatistics']
+print flowStats
+
+# These JSON dumps were handy when trying to parse the responses 
+#print json.dumps(flowStats[0]['flowStat'][1], indent = 2)
+#print json.dumps(flowStats[4], indent = 2)
+for fs in flowStats:
+    print "\nSwitch ID : " + fs['node']['@id']
+    print '{0:8} {1:8} {2:5} {3:15}'.format('Count', 'Action', 'Port', 'DestIP')
+    for aFlow in fs['flowStat']:
+        count = aFlow['packetCount']
+actions = aFlow['flow']['actions'] 
+actionType = ''
+actionPort = ''
+#print actions
+if(type(actions) == type(list())):
+    actionType = actions[1]['@type']
+    actionPort = actions[1]['port']['@id']
+else:
+    actionType = actions['@type']
+    actionPort = actions['port']['@id']
+dst = aFlow['flow']['match']['matchField'][0]['value']
+print '{0:8} {1:8} {2:5} {3:15}'.format(count, actionType, actionPort, dst)
diff --git a/scripts/topo.py b/scripts/topo.py
new file mode 100644 (file)
index 0000000..d35d167
--- /dev/null
@@ -0,0 +1,42 @@
+import json
+import networkx as nx
+from networkx.readwrite import json_graph
+import httplib2
+
+baseUrl = 'http://localhost:8080/controller/nb/v2/'
+containerName = 'default/'
+
+h = httplib2.Http(".cache")
+h.add_credentials('admin', 'admin')
+
+# Get all the edges/links
+resp, content = h.request(baseUrl + 'topology/' + containerName, "GET")
+edgeProperties = json.loads(content)
+odlEdges = edgeProperties['edgeProperties']
+print json.dumps(odlEdges, indent = 2)
+
+# Get all the nodes/switches
+resp, content = h.request(baseUrl + 'switch/' + containerName + 'nodes/', "GET")
+nodeProperties = json.loads(content)
+odlNodes = nodeProperties['nodeProperties']
+print json.dumps(odlNodes, indent = 2)
+
+# Put nodes and edges into a graph
+graph = nx.Graph()
+for node in odlNodes:
+  graph.add_node(node['node']['@id'])
+for edge in odlEdges:
+  e = (edge['edge']['headNodeConnector']['node']['@id'], edge['edge']['tailNodeConnector']['node']['@id'])
+  graph.add_edge(*e)
+# Print out graph info as a sanity check
+print graph.number_of_nodes()
+print graph.nodes()
+#print json.dumps(odlNodes, indent = 2)
+# These JSON dumps were handy when trying to parse the responses 
+#print json.dumps(topo[0], indent = 2)
+
+
+# write json formatted data to use in visualization
+d = json_graph.node_link_data(graph)
+json.dump(d, open('topo.json','w'))
+print('Wrote node-link JSON data')