aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--framework/src/onos/cli/src/main/java/org/onosproject/cli/app/ApplicationsListCommand.java4
-rw-r--r--framework/src/onos/core/api/src/main/java/org/onosproject/app/ApplicationDescription.java7
-rw-r--r--framework/src/onos/core/api/src/main/java/org/onosproject/app/ApplicationStore.java2
-rw-r--r--framework/src/onos/core/api/src/main/java/org/onosproject/app/DefaultApplicationDescription.java12
-rw-r--r--framework/src/onos/core/api/src/main/java/org/onosproject/core/Application.java7
-rw-r--r--framework/src/onos/core/api/src/main/java/org/onosproject/core/DefaultApplication.java17
-rw-r--r--framework/src/onos/core/api/src/test/java/org/onosproject/app/ApplicationEventTest.java2
-rw-r--r--framework/src/onos/core/api/src/test/java/org/onosproject/app/DefaultApplicationDescriptionTest.java4
-rw-r--r--framework/src/onos/core/api/src/test/java/org/onosproject/core/DefaultApplicationTest.java11
-rw-r--r--framework/src/onos/core/common/src/main/java/org/onosproject/codec/impl/ApplicationCodec.java8
-rw-r--r--framework/src/onos/core/common/src/main/java/org/onosproject/common/app/ApplicationArchive.java13
-rw-r--r--framework/src/onos/core/common/src/test/java/org/onosproject/store/trivial/SimpleApplicationStore.java6
-rw-r--r--framework/src/onos/core/net/src/main/java/org/onosproject/app/impl/ApplicationManager.java4
-rw-r--r--framework/src/onos/core/net/src/test/java/org/onosproject/app/impl/ApplicationManagerTest.java8
-rw-r--r--framework/src/onos/core/store/dist/src/main/java/org/onosproject/store/app/GossipApplicationStore.java103
-rw-r--r--framework/src/onos/tools/package/maven-plugin/src/main/java/org/onosproject/maven/OnosAppMojo.java6
-rw-r--r--framework/src/onos/tools/package/maven-plugin/src/main/resources/org/onosproject/maven/app.xml2
-rw-r--r--framework/src/onos/utils/misc/src/main/java/org/onlab/util/DefaultHashMap.java42
-rw-r--r--framework/src/onos/utils/misc/src/test/java/org/onlab/util/DefaultHashMapTest.java81
-rw-r--r--framework/src/onos/web/api/src/test/java/org/onosproject/rest/ApplicationsResourceTest.java8
-rw-r--r--framework/src/onos/web/gui/src/main/java/org/onosproject/ui/impl/TopologyViewMessageHandlerBase.java57
-rw-r--r--framework/src/onos/web/gui/src/main/webapp/app/view/topo/topoEvent.js1
-rw-r--r--framework/src/onos/web/gui/src/main/webapp/app/view/topo/topoForce.js30
23 files changed, 368 insertions, 67 deletions
diff --git a/framework/src/onos/cli/src/main/java/org/onosproject/cli/app/ApplicationsListCommand.java b/framework/src/onos/cli/src/main/java/org/onosproject/cli/app/ApplicationsListCommand.java
index 17cf89e2..100f6823 100644
--- a/framework/src/onos/cli/src/main/java/org/onosproject/cli/app/ApplicationsListCommand.java
+++ b/framework/src/onos/cli/src/main/java/org/onosproject/cli/app/ApplicationsListCommand.java
@@ -41,7 +41,7 @@ public class ApplicationsListCommand extends AbstractShellCommand {
private static final String FMT =
"%s id=%d, name=%s, version=%s, origin=%s, description=%s, " +
- "features=%s, featuresRepo=%s, permissions=%s";
+ "features=%s, featuresRepo=%s, apps=%s, permissions=%s";
private static final String SHORT_FMT =
"%s %3d %-32s %-8s %s";
@@ -76,7 +76,7 @@ public class ApplicationsListCommand extends AbstractShellCommand {
app.id().id(), app.id().name(), app.version(), app.origin(),
app.description(), app.features(),
app.featuresRepo().isPresent() ? app.featuresRepo().get().toString() : "",
- app.permissions());
+ app.requiredApps(), app.permissions());
}
}
}
diff --git a/framework/src/onos/core/api/src/main/java/org/onosproject/app/ApplicationDescription.java b/framework/src/onos/core/api/src/main/java/org/onosproject/app/ApplicationDescription.java
index 2561280b..e8ff9ec4 100644
--- a/framework/src/onos/core/api/src/main/java/org/onosproject/app/ApplicationDescription.java
+++ b/framework/src/onos/core/api/src/main/java/org/onosproject/app/ApplicationDescription.java
@@ -86,4 +86,11 @@ public interface ApplicationDescription {
* @return application features
*/
List<String> features();
+
+ /**
+ * Returns list of required application names.
+ *
+ * @return list of application names
+ */
+ List<String> requiredApps();
}
diff --git a/framework/src/onos/core/api/src/main/java/org/onosproject/app/ApplicationStore.java b/framework/src/onos/core/api/src/main/java/org/onosproject/app/ApplicationStore.java
index b3cdc43e..0a1f0727 100644
--- a/framework/src/onos/core/api/src/main/java/org/onosproject/app/ApplicationStore.java
+++ b/framework/src/onos/core/api/src/main/java/org/onosproject/app/ApplicationStore.java
@@ -76,7 +76,7 @@ public interface ApplicationStore extends Store<ApplicationEvent, ApplicationSto
void remove(ApplicationId appId);
/**
- * Mark the application as actived.
+ * Mark the application as active.
*
* @param appId application identifier
*/
diff --git a/framework/src/onos/core/api/src/main/java/org/onosproject/app/DefaultApplicationDescription.java b/framework/src/onos/core/api/src/main/java/org/onosproject/app/DefaultApplicationDescription.java
index 710d0f9c..569183a7 100644
--- a/framework/src/onos/core/api/src/main/java/org/onosproject/app/DefaultApplicationDescription.java
+++ b/framework/src/onos/core/api/src/main/java/org/onosproject/app/DefaultApplicationDescription.java
@@ -41,6 +41,7 @@ public class DefaultApplicationDescription implements ApplicationDescription {
private final Set<Permission> permissions;
private final Optional<URI> featuresRepo;
private final List<String> features;
+ private final List<String> requiredApps;
/**
* Creates a new application descriptor using the supplied data.
@@ -53,11 +54,13 @@ public class DefaultApplicationDescription implements ApplicationDescription {
* @param permissions requested permissions
* @param featuresRepo optional features repo URI
* @param features application features
+ * @param requiredApps list of required application names
*/
public DefaultApplicationDescription(String name, Version version,
String description, String origin,
ApplicationRole role, Set<Permission> permissions,
- URI featuresRepo, List<String> features) {
+ URI featuresRepo, List<String> features,
+ List<String> requiredApps) {
this.name = checkNotNull(name, "Name cannot be null");
this.version = checkNotNull(version, "Version cannot be null");
this.description = checkNotNull(description, "Description cannot be null");
@@ -66,6 +69,7 @@ public class DefaultApplicationDescription implements ApplicationDescription {
this.permissions = checkNotNull(permissions, "Permissions cannot be null");
this.featuresRepo = Optional.ofNullable(featuresRepo);
this.features = checkNotNull(features, "Features cannot be null");
+ this.requiredApps = checkNotNull(requiredApps, "Required apps cannot be null");
checkArgument(!features.isEmpty(), "There must be at least one feature");
}
@@ -110,6 +114,11 @@ public class DefaultApplicationDescription implements ApplicationDescription {
}
@Override
+ public List<String> requiredApps() {
+ return requiredApps;
+ }
+
+ @Override
public String toString() {
return toStringHelper(this)
.add("name", name)
@@ -120,6 +129,7 @@ public class DefaultApplicationDescription implements ApplicationDescription {
.add("permissions", permissions)
.add("featuresRepo", featuresRepo)
.add("features", features)
+ .add("requiredApps", requiredApps)
.toString();
}
}
diff --git a/framework/src/onos/core/api/src/main/java/org/onosproject/core/Application.java b/framework/src/onos/core/api/src/main/java/org/onosproject/core/Application.java
index fca53843..ea2eab9b 100644
--- a/framework/src/onos/core/api/src/main/java/org/onosproject/core/Application.java
+++ b/framework/src/onos/core/api/src/main/java/org/onosproject/core/Application.java
@@ -84,4 +84,11 @@ public interface Application {
* @return application features
*/
List<String> features();
+
+ /**
+ * Returns list of required application names.
+ *
+ * @return list of application names
+ */
+ List<String> requiredApps();
}
diff --git a/framework/src/onos/core/api/src/main/java/org/onosproject/core/DefaultApplication.java b/framework/src/onos/core/api/src/main/java/org/onosproject/core/DefaultApplication.java
index d8062ddf..c3515638 100644
--- a/framework/src/onos/core/api/src/main/java/org/onosproject/core/DefaultApplication.java
+++ b/framework/src/onos/core/api/src/main/java/org/onosproject/core/DefaultApplication.java
@@ -40,6 +40,7 @@ public class DefaultApplication implements Application {
private final Set<Permission> permissions;
private final Optional<URI> featuresRepo;
private final List<String> features;
+ private final List<String> requiredApps;
/**
* Creates a new application descriptor using the supplied data.
@@ -52,11 +53,13 @@ public class DefaultApplication implements Application {
* @param permissions requested permissions
* @param featuresRepo optional features repo URI
* @param features application features
+ * @param requiredApps list of required application names
*/
public DefaultApplication(ApplicationId appId, Version version,
String description, String origin,
ApplicationRole role, Set<Permission> permissions,
- Optional<URI> featuresRepo, List<String> features) {
+ Optional<URI> featuresRepo, List<String> features,
+ List<String> requiredApps) {
this.appId = checkNotNull(appId, "ID cannot be null");
this.version = checkNotNull(version, "Version cannot be null");
this.description = checkNotNull(description, "Description cannot be null");
@@ -65,6 +68,7 @@ public class DefaultApplication implements Application {
this.permissions = checkNotNull(permissions, "Permissions cannot be null");
this.featuresRepo = checkNotNull(featuresRepo, "Features repo cannot be null");
this.features = checkNotNull(features, "Features cannot be null");
+ this.requiredApps = checkNotNull(requiredApps, "Required apps cannot be null");
checkArgument(!features.isEmpty(), "There must be at least one feature");
}
@@ -109,9 +113,14 @@ public class DefaultApplication implements Application {
}
@Override
+ public List<String> requiredApps() {
+ return requiredApps;
+ }
+
+ @Override
public int hashCode() {
return Objects.hash(appId, version, description, origin, role, permissions,
- featuresRepo, features);
+ featuresRepo, features, requiredApps);
}
@Override
@@ -130,7 +139,8 @@ public class DefaultApplication implements Application {
Objects.equals(this.role, other.role) &&
Objects.equals(this.permissions, other.permissions) &&
Objects.equals(this.featuresRepo, other.featuresRepo) &&
- Objects.equals(this.features, other.features);
+ Objects.equals(this.features, other.features) &&
+ Objects.equals(this.requiredApps, other.requiredApps);
}
@Override
@@ -144,6 +154,7 @@ public class DefaultApplication implements Application {
.add("permissions", permissions)
.add("featuresRepo", featuresRepo)
.add("features", features)
+ .add("requiredApps", requiredApps)
.toString();
}
}
diff --git a/framework/src/onos/core/api/src/test/java/org/onosproject/app/ApplicationEventTest.java b/framework/src/onos/core/api/src/test/java/org/onosproject/app/ApplicationEventTest.java
index d31cc268..34c593c4 100644
--- a/framework/src/onos/core/api/src/test/java/org/onosproject/app/ApplicationEventTest.java
+++ b/framework/src/onos/core/api/src/test/java/org/onosproject/app/ApplicationEventTest.java
@@ -33,7 +33,7 @@ public class ApplicationEventTest extends AbstractEventTest {
private Application createApp() {
return new DefaultApplication(APP_ID, VER, DESC, ORIGIN, ROLE,
- PERMS, Optional.of(FURL), FEATURES);
+ PERMS, Optional.of(FURL), FEATURES, APPS);
}
@Test
diff --git a/framework/src/onos/core/api/src/test/java/org/onosproject/app/DefaultApplicationDescriptionTest.java b/framework/src/onos/core/api/src/test/java/org/onosproject/app/DefaultApplicationDescriptionTest.java
index d40d3fea..0e93c1fe 100644
--- a/framework/src/onos/core/api/src/test/java/org/onosproject/app/DefaultApplicationDescriptionTest.java
+++ b/framework/src/onos/core/api/src/test/java/org/onosproject/app/DefaultApplicationDescriptionTest.java
@@ -46,12 +46,13 @@ public class DefaultApplicationDescriptionTest {
new Permission(AppPermission.class.getName(), "FLOWRULE_READ"));
public static final URI FURL = URI.create("mvn:org.foo-features/1.2a/xml/features");
public static final List<String> FEATURES = ImmutableList.of("foo", "bar");
+ public static final List<String> APPS = ImmutableList.of("fifi");
@Test
public void basics() {
ApplicationDescription app =
new DefaultApplicationDescription(APP_NAME, VER, DESC, ORIGIN,
- ROLE, PERMS, FURL, FEATURES);
+ ROLE, PERMS, FURL, FEATURES, APPS);
assertEquals("incorrect id", APP_NAME, app.name());
assertEquals("incorrect version", VER, app.version());
assertEquals("incorrect description", DESC, app.description());
@@ -60,6 +61,7 @@ public class DefaultApplicationDescriptionTest {
assertEquals("incorrect permissions", PERMS, app.permissions());
assertEquals("incorrect features repo", FURL, app.featuresRepo().get());
assertEquals("incorrect features", FEATURES, app.features());
+ assertEquals("incorrect apps", APPS, app.requiredApps());
assertTrue("incorrect toString", app.toString().contains(APP_NAME));
}
diff --git a/framework/src/onos/core/api/src/test/java/org/onosproject/core/DefaultApplicationTest.java b/framework/src/onos/core/api/src/test/java/org/onosproject/core/DefaultApplicationTest.java
index cbedb79c..77b3812b 100644
--- a/framework/src/onos/core/api/src/test/java/org/onosproject/core/DefaultApplicationTest.java
+++ b/framework/src/onos/core/api/src/test/java/org/onosproject/core/DefaultApplicationTest.java
@@ -34,7 +34,7 @@ public class DefaultApplicationTest {
@Test
public void basics() {
Application app = new DefaultApplication(APP_ID, VER, DESC, ORIGIN, ROLE,
- PERMS, Optional.of(FURL), FEATURES);
+ PERMS, Optional.of(FURL), FEATURES, APPS);
assertEquals("incorrect id", APP_ID, app.id());
assertEquals("incorrect version", VER, app.version());
assertEquals("incorrect description", DESC, app.description());
@@ -43,19 +43,20 @@ public class DefaultApplicationTest {
assertEquals("incorrect permissions", PERMS, app.permissions());
assertEquals("incorrect features repo", FURL, app.featuresRepo().get());
assertEquals("incorrect features", FEATURES, app.features());
+ assertEquals("incorrect apps", APPS, app.requiredApps());
assertTrue("incorrect toString", app.toString().contains(APP_NAME));
}
@Test
public void testEquality() {
Application a1 = new DefaultApplication(APP_ID, VER, DESC, ORIGIN, ROLE,
- PERMS, Optional.of(FURL), FEATURES);
+ PERMS, Optional.of(FURL), FEATURES, APPS);
Application a2 = new DefaultApplication(APP_ID, VER, DESC, ORIGIN, ROLE,
- PERMS, Optional.of(FURL), FEATURES);
+ PERMS, Optional.of(FURL), FEATURES, APPS);
Application a3 = new DefaultApplication(APP_ID, VER, DESC, ORIGIN, ROLE,
- PERMS, Optional.empty(), FEATURES);
+ PERMS, Optional.empty(), FEATURES, APPS);
Application a4 = new DefaultApplication(APP_ID, VER, DESC, ORIGIN + "asd", ROLE,
- PERMS, Optional.of(FURL), FEATURES);
+ PERMS, Optional.of(FURL), FEATURES, APPS);
new EqualsTester().addEqualityGroup(a1, a2)
.addEqualityGroup(a3).addEqualityGroup(a4).testEquals();
}
diff --git a/framework/src/onos/core/common/src/main/java/org/onosproject/codec/impl/ApplicationCodec.java b/framework/src/onos/core/common/src/main/java/org/onosproject/codec/impl/ApplicationCodec.java
index b2cab094..a09c0bdb 100644
--- a/framework/src/onos/core/common/src/main/java/org/onosproject/codec/impl/ApplicationCodec.java
+++ b/framework/src/onos/core/common/src/main/java/org/onosproject/codec/impl/ApplicationCodec.java
@@ -32,18 +32,18 @@ public final class ApplicationCodec extends JsonCodec<Application> {
public ObjectNode encode(Application app, CodecContext context) {
checkNotNull(app, "Application cannot be null");
ApplicationService service = context.getService(ApplicationService.class);
- ObjectNode result = context.mapper().createObjectNode()
+ return context.mapper().createObjectNode()
.put("name", app.id().name())
.put("id", app.id().id())
.put("version", app.version().toString())
.put("description", app.description())
.put("origin", app.origin())
- .put("permissions", app.permissions().toString())
+ .put("permissions", app.permissions().toString()) // FIXME: change to an array
.put("featuresRepo", app.featuresRepo().isPresent() ?
app.featuresRepo().get().toString() : "")
- .put("features", app.features().toString())
+ .put("features", app.features().toString()) // FIXME: change to an array
+ .put("requiredApps", app.requiredApps().toString()) // FIXME: change to an array
.put("state", service.getState(app.id()).toString());
- return result;
}
}
diff --git a/framework/src/onos/core/common/src/main/java/org/onosproject/common/app/ApplicationArchive.java b/framework/src/onos/core/common/src/main/java/org/onosproject/common/app/ApplicationArchive.java
index 54f0fb89..37cdbdfc 100644
--- a/framework/src/onos/core/common/src/main/java/org/onosproject/common/app/ApplicationArchive.java
+++ b/framework/src/onos/core/common/src/main/java/org/onosproject/common/app/ApplicationArchive.java
@@ -17,6 +17,7 @@ package org.onosproject.common.app;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.ImmutableSet;
+import com.google.common.collect.Lists;
import com.google.common.io.ByteStreams;
import com.google.common.io.Files;
import org.apache.commons.configuration.ConfigurationException;
@@ -33,7 +34,6 @@ import org.onosproject.core.Version;
import org.onosproject.security.AppPermission;
import org.onosproject.security.Permission;
import org.onosproject.store.AbstractStore;
-
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@@ -46,7 +46,6 @@ import java.io.InputStream;
import java.net.URI;
import java.nio.charset.Charset;
import java.nio.file.NoSuchFileException;
-import java.util.ArrayList;
import java.util.List;
import java.util.Locale;
import java.util.Set;
@@ -79,6 +78,7 @@ public class ApplicationArchive
private static final String VERSION = "[@version]";
private static final String FEATURES_REPO = "[@featuresRepo]";
private static final String FEATURES = "[@features]";
+ private static final String APPS = "[@apps]";
private static final String DESCRIPTION = "description";
private static final String ROLE = "security.role";
@@ -291,8 +291,13 @@ public class ApplicationArchive
URI featuresRepo = featRepo != null ? URI.create(featRepo) : null;
List<String> features = ImmutableList.copyOf(cfg.getString(FEATURES).split(","));
+ String apps = cfg.getString(APPS, "");
+ List<String> requiredApps = apps.isEmpty() ?
+ ImmutableList.of() : ImmutableList.copyOf(apps.split(","));
+
return new DefaultApplicationDescription(name, version, desc, origin, role,
- perms, featuresRepo, features);
+ perms, featuresRepo, features,
+ requiredApps);
}
// Expands the specified ZIP stream into app-specific directory.
@@ -390,7 +395,7 @@ public class ApplicationArchive
// Returns the set of Permissions specified in the app.xml file
private ImmutableSet<Permission> getPermissions(XMLConfiguration cfg) {
- List<Permission> permissionList = new ArrayList();
+ List<Permission> permissionList = Lists.newArrayList();
for (Object o : cfg.getList(APP_PERMISSIONS)) {
String name = (String) o;
diff --git a/framework/src/onos/core/common/src/test/java/org/onosproject/store/trivial/SimpleApplicationStore.java b/framework/src/onos/core/common/src/test/java/org/onosproject/store/trivial/SimpleApplicationStore.java
index ea9a773e..d9f5285c 100644
--- a/framework/src/onos/core/common/src/test/java/org/onosproject/store/trivial/SimpleApplicationStore.java
+++ b/framework/src/onos/core/common/src/test/java/org/onosproject/store/trivial/SimpleApplicationStore.java
@@ -75,7 +75,8 @@ public class SimpleApplicationStore extends ApplicationArchive implements Applic
new DefaultApplication(appId, appDesc.version(),
appDesc.description(), appDesc.origin(),
appDesc.role(), appDesc.permissions(),
- appDesc.featuresRepo(), appDesc.features());
+ appDesc.featuresRepo(), appDesc.features(),
+ appDesc.requiredApps());
apps.put(appId, app);
states.put(appId, isActive(name) ? INSTALLED : ACTIVE);
// load app permissions
@@ -117,7 +118,8 @@ public class SimpleApplicationStore extends ApplicationArchive implements Applic
DefaultApplication app =
new DefaultApplication(appId, appDesc.version(), appDesc.description(),
appDesc.origin(), appDesc.role(), appDesc.permissions(),
- appDesc.featuresRepo(), appDesc.features());
+ appDesc.featuresRepo(), appDesc.features(),
+ appDesc.requiredApps());
apps.put(appId, app);
states.put(appId, INSTALLED);
delegate.notify(new ApplicationEvent(APP_INSTALLED, app));
diff --git a/framework/src/onos/core/net/src/main/java/org/onosproject/app/impl/ApplicationManager.java b/framework/src/onos/core/net/src/main/java/org/onosproject/app/impl/ApplicationManager.java
index a9e928e5..d09eb1f1 100644
--- a/framework/src/onos/core/net/src/main/java/org/onosproject/app/impl/ApplicationManager.java
+++ b/framework/src/onos/core/net/src/main/java/org/onosproject/app/impl/ApplicationManager.java
@@ -212,6 +212,7 @@ public class ApplicationManager
// The following methods are fully synchronized to guard against remote vs.
// locally induced feature service interactions.
+ // Installs all feature repositories required by the specified app.
private synchronized boolean installAppArtifacts(Application app) throws Exception {
if (app.featuresRepo().isPresent() &&
featuresService.getRepository(app.featuresRepo().get()) == null) {
@@ -221,6 +222,7 @@ public class ApplicationManager
return false;
}
+ // Uninstalls all the feature repositories required by the specified app.
private synchronized boolean uninstallAppArtifacts(Application app) throws Exception {
if (app.featuresRepo().isPresent() &&
featuresService.getRepository(app.featuresRepo().get()) != null) {
@@ -230,6 +232,7 @@ public class ApplicationManager
return false;
}
+ // Installs all features that define the specified app.
private synchronized boolean installAppFeatures(Application app) throws Exception {
boolean changed = false;
for (String name : app.features()) {
@@ -246,6 +249,7 @@ public class ApplicationManager
return changed;
}
+ // Uninstalls all features that define the specified app.
private synchronized boolean uninstallAppFeatures(Application app) throws Exception {
boolean changed = false;
invokeHook(deactivateHooks.get(app.id().name()), app.id());
diff --git a/framework/src/onos/core/net/src/test/java/org/onosproject/app/impl/ApplicationManagerTest.java b/framework/src/onos/core/net/src/test/java/org/onosproject/app/impl/ApplicationManagerTest.java
index 5461cf01..a99fd216 100644
--- a/framework/src/onos/core/net/src/test/java/org/onosproject/app/impl/ApplicationManagerTest.java
+++ b/framework/src/onos/core/net/src/test/java/org/onosproject/app/impl/ApplicationManagerTest.java
@@ -15,6 +15,7 @@
*/
package org.onosproject.app.impl;
+import com.google.common.collect.ImmutableList;
import com.google.common.collect.ImmutableSet;
import org.junit.After;
import org.junit.Before;
@@ -138,7 +139,7 @@ public class ApplicationManagerTest {
@Override
public Application create(InputStream appDescStream) {
app = new DefaultApplication(APP_ID, VER, DESC, ORIGIN, ROLE, PERMS,
- Optional.of(FURL), FEATURES);
+ Optional.of(FURL), FEATURES, ImmutableList.of());
state = INSTALLED;
delegate.notify(new ApplicationEvent(APP_INSTALLED, app));
return app;
@@ -177,6 +178,11 @@ public class ApplicationManagerTest {
state = INSTALLED;
delegate.notify(new ApplicationEvent(APP_DEACTIVATED, app));
}
+
+ @Override
+ public ApplicationId getId(String name) {
+ return new DefaultApplicationId(0, name);
+ }
}
private class TestFeaturesService extends FeaturesServiceAdapter {
diff --git a/framework/src/onos/core/store/dist/src/main/java/org/onosproject/store/app/GossipApplicationStore.java b/framework/src/onos/core/store/dist/src/main/java/org/onosproject/store/app/GossipApplicationStore.java
index 6764c222..dda820ae 100644
--- a/framework/src/onos/core/store/dist/src/main/java/org/onosproject/store/app/GossipApplicationStore.java
+++ b/framework/src/onos/core/store/dist/src/main/java/org/onosproject/store/app/GossipApplicationStore.java
@@ -17,7 +17,9 @@ package org.onosproject.store.app;
import com.google.common.base.Charsets;
import com.google.common.collect.ImmutableSet;
-
+import com.google.common.collect.Maps;
+import com.google.common.collect.Multimap;
+import com.google.common.collect.Sets;
import org.apache.felix.scr.annotations.Activate;
import org.apache.felix.scr.annotations.Component;
import org.apache.felix.scr.annotations.Deactivate;
@@ -37,6 +39,7 @@ import org.onosproject.common.app.ApplicationArchive;
import org.onosproject.core.Application;
import org.onosproject.core.ApplicationId;
import org.onosproject.core.ApplicationIdStore;
+import org.onosproject.core.CoreService;
import org.onosproject.core.DefaultApplication;
import org.onosproject.security.Permission;
import org.onosproject.store.cluster.messaging.ClusterCommunicationService;
@@ -61,6 +64,8 @@ import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService;
import java.util.function.Function;
+import static com.google.common.collect.Multimaps.newSetMultimap;
+import static com.google.common.collect.Multimaps.synchronizedSetMultimap;
import static com.google.common.io.ByteStreams.toByteArray;
import static java.util.concurrent.TimeUnit.MILLISECONDS;
import static org.onlab.util.Tools.groupedThreads;
@@ -115,6 +120,14 @@ public class GossipApplicationStore extends ApplicationArchive
@Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
protected ApplicationIdStore idStore;
+ // Multimap to track which apps are required by others apps
+ // app -> { required-by, ... }
+ // Apps explicitly activated will be required by the CORE app
+ private final Multimap<ApplicationId, ApplicationId> requiredBy =
+ synchronizedSetMultimap(newSetMultimap(Maps.newHashMap(), Sets::newHashSet));
+
+ private ApplicationId coreAppId;
+
@Activate
public void activate() {
KryoNamespace.Builder serializer = KryoNamespace.newBuilder()
@@ -128,16 +141,16 @@ public class GossipApplicationStore extends ApplicationArchive
groupedThreads("onos/store/app", "message-handler"));
clusterCommunicator.<String, byte[]>addSubscriber(APP_BITS_REQUEST,
- bytes -> new String(bytes, Charsets.UTF_8),
- name -> {
- try {
- return toByteArray(getApplicationInputStream(name));
- } catch (IOException e) {
- throw new StorageException(e);
- }
- },
- Function.identity(),
- messageHandlingExecutor);
+ bytes -> new String(bytes, Charsets.UTF_8),
+ name -> {
+ try {
+ return toByteArray(getApplicationInputStream(name));
+ } catch (IOException e) {
+ throw new StorageException(e);
+ }
+ },
+ Function.identity(),
+ messageHandlingExecutor);
// FIXME: Consider consolidating into a single map.
@@ -161,6 +174,7 @@ public class GossipApplicationStore extends ApplicationArchive
.withTimestampProvider((k, v) -> clockService.getTimestamp())
.build();
+ coreAppId = getId(CoreService.CORE_APP_NAME);
log.info("Started");
}
@@ -174,6 +188,7 @@ public class GossipApplicationStore extends ApplicationArchive
try {
Application app = create(getApplicationDescription(name), false);
if (app != null && isActive(app.id().name())) {
+ requiredBy.put(app.id(), coreAppId);
activate(app.id(), false);
// load app permissions
}
@@ -200,7 +215,6 @@ public class GossipApplicationStore extends ApplicationArchive
public void setDelegate(ApplicationStoreDelegate delegate) {
super.setDelegate(delegate);
loadFromDisk();
-// executor.schedule(this::pruneUninstalledApps, LOAD_TIMEOUT_MS, MILLISECONDS);
}
@Override
@@ -229,7 +243,15 @@ public class GossipApplicationStore extends ApplicationArchive
@Override
public Application create(InputStream appDescStream) {
ApplicationDescription appDesc = saveApplication(appDescStream);
- return create(appDesc, true);
+ if (hasPrerequisites(appDesc)) {
+ return create(appDesc, true);
+ }
+ throw new ApplicationException("Missing dependencies for app " + appDesc.name());
+ }
+
+ private boolean hasPrerequisites(ApplicationDescription app) {
+ return !app.requiredApps().stream().map(n -> getId(n))
+ .anyMatch(id -> id == null || getApplication(id) == null);
}
private Application create(ApplicationDescription appDesc, boolean updateTime) {
@@ -246,36 +268,80 @@ public class GossipApplicationStore extends ApplicationArchive
public void remove(ApplicationId appId) {
Application app = apps.get(appId);
if (app != null) {
+ uninstallDependentApps(app);
apps.remove(appId);
states.remove(app);
permissions.remove(app);
}
}
+ // Uninstalls all apps that depend on the given app.
+ private void uninstallDependentApps(Application app) {
+ getApplications().stream()
+ .filter(a -> a.requiredApps().contains(app.id().name()))
+ .forEach(a -> remove(a.id()));
+ }
+
@Override
public void activate(ApplicationId appId) {
+ activate(appId, coreAppId);
+ }
+
+ private void activate(ApplicationId appId, ApplicationId forAppId) {
+ requiredBy.put(appId, forAppId);
activate(appId, true);
}
+
private void activate(ApplicationId appId, boolean updateTime) {
Application app = apps.get(appId);
if (app != null) {
if (updateTime) {
updateTime(appId.name());
}
+ activateRequiredApps(app);
states.put(app, ACTIVATED);
}
}
+ // Activates all apps required by this application.
+ private void activateRequiredApps(Application app) {
+ app.requiredApps().stream().map(this::getId).forEach(id -> activate(id, app.id()));
+ }
+
@Override
public void deactivate(ApplicationId appId) {
- Application app = apps.get(appId);
- if (app != null) {
- updateTime(appId.name());
- states.put(app, DEACTIVATED);
+ deactivateDependentApps(getApplication(appId));
+ deactivate(appId, coreAppId);
+ }
+
+ private void deactivate(ApplicationId appId, ApplicationId forAppId) {
+ requiredBy.remove(appId, forAppId);
+ if (requiredBy.get(appId).isEmpty()) {
+ Application app = apps.get(appId);
+ if (app != null) {
+ updateTime(appId.name());
+ states.put(app, DEACTIVATED);
+ deactivateRequiredApps(app);
+ }
}
}
+ // Deactivates all apps that require this application.
+ private void deactivateDependentApps(Application app) {
+ getApplications().stream()
+ .filter(a -> states.get(a) == ACTIVATED)
+ .filter(a -> a.requiredApps().contains(app.id().name()))
+ .forEach(a -> deactivate(a.id()));
+ }
+
+ // Deactivates all apps required by this application.
+ private void deactivateRequiredApps(Application app) {
+ app.requiredApps().stream().map(this::getId).map(this::getApplication)
+ .filter(a -> states.get(a) == ACTIVATED)
+ .forEach(a -> deactivate(a.id(), app.id()));
+ }
+
@Override
public Set<Permission> getPermissions(ApplicationId appId) {
Application app = apps.get(appId);
@@ -424,6 +490,7 @@ public class GossipApplicationStore extends ApplicationArchive
ApplicationId appId = idStore.registerApplication(appDesc.name());
return new DefaultApplication(appId, appDesc.version(), appDesc.description(),
appDesc.origin(), appDesc.role(), appDesc.permissions(),
- appDesc.featuresRepo(), appDesc.features());
+ appDesc.featuresRepo(), appDesc.features(),
+ appDesc.requiredApps());
}
}
diff --git a/framework/src/onos/tools/package/maven-plugin/src/main/java/org/onosproject/maven/OnosAppMojo.java b/framework/src/onos/tools/package/maven-plugin/src/main/java/org/onosproject/maven/OnosAppMojo.java
index bfc6127a..5558b13a 100644
--- a/framework/src/onos/tools/package/maven-plugin/src/main/java/org/onosproject/maven/OnosAppMojo.java
+++ b/framework/src/onos/tools/package/maven-plugin/src/main/java/org/onosproject/maven/OnosAppMojo.java
@@ -62,6 +62,7 @@ public class OnosAppMojo extends AbstractMojo {
private static final String ONOS_APP_NAME = "onos.app.name";
private static final String ONOS_APP_ORIGIN = "onos.app.origin";
+ private static final String ONOS_APP_REQUIRES = "onos.app.requires";
private static final String JAR = "jar";
private static final String XML = "xml";
@@ -80,6 +81,7 @@ public class OnosAppMojo extends AbstractMojo {
private String name;
private String origin;
+ private String requiredApps;
private String version = DEFAULT_VERSION;
private String featuresRepo = DEFAULT_FEATURES_REPO;
private List<String> artifacts;
@@ -160,6 +162,9 @@ public class OnosAppMojo extends AbstractMojo {
origin = (String) project.getProperties().get(ONOS_APP_ORIGIN);
origin = origin != null ? origin : DEFAULT_ORIGIN;
+ requiredApps = (String) project.getProperties().get(ONOS_APP_REQUIRES);
+ requiredApps = requiredApps == null ? "" : requiredApps;
+
if (appFile.exists()) {
loadAppFile(appFile);
} else {
@@ -338,6 +343,7 @@ public class OnosAppMojo extends AbstractMojo {
return string == null ? null :
string.replaceAll("\\$\\{onos.app.name\\}", name)
.replaceAll("\\$\\{onos.app.origin\\}", origin)
+ .replaceAll("\\$\\{onos.app.requires\\}", requiredApps)
.replaceAll("\\$\\{project.groupId\\}", projectGroupId)
.replaceAll("\\$\\{project.artifactId\\}", projectArtifactId)
.replaceAll("\\$\\{project.version\\}", projectVersion)
diff --git a/framework/src/onos/tools/package/maven-plugin/src/main/resources/org/onosproject/maven/app.xml b/framework/src/onos/tools/package/maven-plugin/src/main/resources/org/onosproject/maven/app.xml
index 0f3133d3..84998807 100644
--- a/framework/src/onos/tools/package/maven-plugin/src/main/resources/org/onosproject/maven/app.xml
+++ b/framework/src/onos/tools/package/maven-plugin/src/main/resources/org/onosproject/maven/app.xml
@@ -16,7 +16,7 @@
-->
<app name="${onos.app.name}" origin="${onos.app.origin}" version="${project.version}"
featuresRepo="mvn:${project.groupId}/${project.artifactId}/${project.version}/xml/features"
- features="${project.artifactId}">
+ features="${project.artifactId}" apps="${onos.app.requires}">
<description>${project.description}</description>
<artifact>mvn:${project.groupId}/${project.artifactId}/${project.version}</artifact>
</app>
diff --git a/framework/src/onos/utils/misc/src/main/java/org/onlab/util/DefaultHashMap.java b/framework/src/onos/utils/misc/src/main/java/org/onlab/util/DefaultHashMap.java
new file mode 100644
index 00000000..f9d878ab
--- /dev/null
+++ b/framework/src/onos/utils/misc/src/main/java/org/onlab/util/DefaultHashMap.java
@@ -0,0 +1,42 @@
+/*
+ * Copyright 2015 Open Networking Laboratory
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.onlab.util;
+
+import java.util.HashMap;
+
+/**
+ * HashMap that returns a default value for unmapped keys.
+ */
+public class DefaultHashMap<K, V> extends HashMap<K, V> {
+
+ /** Default value to return when no key binding exists. */
+ protected V defaultValue;
+
+ /**
+ * Constructs an empty map with the given default value.
+ *
+ * @param defaultValue the default value
+ */
+ public DefaultHashMap(V defaultValue) {
+ this.defaultValue = defaultValue;
+ }
+
+ @Override
+ public V get(Object k) {
+ return containsKey(k) ? super.get(k) : defaultValue;
+ }
+} \ No newline at end of file
diff --git a/framework/src/onos/utils/misc/src/test/java/org/onlab/util/DefaultHashMapTest.java b/framework/src/onos/utils/misc/src/test/java/org/onlab/util/DefaultHashMapTest.java
new file mode 100644
index 00000000..db6b5fb7
--- /dev/null
+++ b/framework/src/onos/utils/misc/src/test/java/org/onlab/util/DefaultHashMapTest.java
@@ -0,0 +1,81 @@
+/*
+ * Copyright 2015 Open Networking Laboratory
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.onlab.util;
+
+import org.junit.Test;
+
+import static org.junit.Assert.assertEquals;
+
+/**
+ * Unit tests for {@link DefaultHashMap}.
+ */
+public class DefaultHashMapTest {
+
+ private static final String ONE = "one";
+ private static final String TWO = "two";
+ private static final String THREE = "three";
+ private static final String FOUR = "four";
+
+ private static final String ALPHA = "Alpha";
+ private static final String BETA = "Beta";
+ private static final String OMEGA = "Omega";
+
+ private DefaultHashMap<String, Integer> map;
+ private DefaultHashMap<String, String> chartis;
+
+ private void loadMap() {
+ map.put(ONE, 1);
+ map.put(TWO, 2);
+ }
+
+ private void fortioCharti() {
+ chartis.put(ONE, ALPHA);
+ chartis.put(TWO, BETA);
+ }
+
+ @Test
+ public void nullDefaultIsAllowed() {
+ // but makes this class behave no different than HashMap
+ map = new DefaultHashMap<>(null);
+ loadMap();
+ assertEquals("missing 1", 1, (int) map.get(ONE));
+ assertEquals("missing 2", 2, (int) map.get(TWO));
+ assertEquals("three?", null, map.get(THREE));
+ assertEquals("four?", null, map.get(FOUR));
+ }
+
+ @Test
+ public void defaultToFive() {
+ map = new DefaultHashMap<>(5);
+ loadMap();
+ assertEquals("missing 1", 1, (int) map.get(ONE));
+ assertEquals("missing 2", 2, (int) map.get(TWO));
+ assertEquals("three?", 5, (int) map.get(THREE));
+ assertEquals("four?", 5, (int) map.get(FOUR));
+ }
+
+ @Test
+ public void defaultToOmega() {
+ chartis = new DefaultHashMap<>(OMEGA);
+ fortioCharti();
+ assertEquals("missing 1", ALPHA, chartis.get(ONE));
+ assertEquals("missing 2", BETA, chartis.get(TWO));
+ assertEquals("three?", OMEGA, chartis.get(THREE));
+ assertEquals("four?", OMEGA, chartis.get(FOUR));
+ }
+
+}
diff --git a/framework/src/onos/web/api/src/test/java/org/onosproject/rest/ApplicationsResourceTest.java b/framework/src/onos/web/api/src/test/java/org/onosproject/rest/ApplicationsResourceTest.java
index 6fee43ed..3e72f18d 100644
--- a/framework/src/onos/web/api/src/test/java/org/onosproject/rest/ApplicationsResourceTest.java
+++ b/framework/src/onos/web/api/src/test/java/org/onosproject/rest/ApplicationsResourceTest.java
@@ -85,19 +85,19 @@ public class ApplicationsResourceTest extends ResourceTest {
private Application app1 =
new DefaultApplication(id1, VER,
"app1", "origin1", ApplicationRole.ADMIN, ImmutableSet.of(), Optional.of(FURL),
- ImmutableList.of("My Feature"));
+ ImmutableList.of("My Feature"), ImmutableList.of());
private Application app2 =
new DefaultApplication(id2, VER,
"app2", "origin2", ApplicationRole.ADMIN, ImmutableSet.of(), Optional.of(FURL),
- ImmutableList.of("My Feature"));
+ ImmutableList.of("My Feature"), ImmutableList.of());
private Application app3 =
new DefaultApplication(id3, VER,
"app3", "origin3", ApplicationRole.ADMIN, ImmutableSet.of(), Optional.of(FURL),
- ImmutableList.of("My Feature"));
+ ImmutableList.of("My Feature"), ImmutableList.of());
private Application app4 =
new DefaultApplication(id4, VER,
"app4", "origin4", ApplicationRole.ADMIN, ImmutableSet.of(), Optional.of(FURL),
- ImmutableList.of("My Feature"));
+ ImmutableList.of("My Feature"), ImmutableList.of());
/**
* Hamcrest matcher to check that an application representation in JSON matches
diff --git a/framework/src/onos/web/gui/src/main/java/org/onosproject/ui/impl/TopologyViewMessageHandlerBase.java b/framework/src/onos/web/gui/src/main/java/org/onosproject/ui/impl/TopologyViewMessageHandlerBase.java
index 840e89f3..8da81016 100644
--- a/framework/src/onos/web/gui/src/main/java/org/onosproject/ui/impl/TopologyViewMessageHandlerBase.java
+++ b/framework/src/onos/web/gui/src/main/java/org/onosproject/ui/impl/TopologyViewMessageHandlerBase.java
@@ -20,6 +20,7 @@ import com.fasterxml.jackson.databind.node.ArrayNode;
import com.fasterxml.jackson.databind.node.ObjectNode;
import org.onlab.osgi.ServiceDirectory;
import org.onlab.packet.IpAddress;
+import org.onlab.util.DefaultHashMap;
import org.onosproject.cluster.ClusterEvent;
import org.onosproject.cluster.ClusterService;
import org.onosproject.cluster.ControllerNode;
@@ -80,17 +81,9 @@ import java.util.concurrent.ConcurrentHashMap;
import static com.google.common.base.Preconditions.checkNotNull;
import static com.google.common.base.Strings.isNullOrEmpty;
-import static org.onosproject.cluster.ClusterEvent.Type.INSTANCE_ADDED;
-import static org.onosproject.cluster.ClusterEvent.Type.INSTANCE_REMOVED;
import static org.onosproject.cluster.ControllerNode.State.ACTIVE;
import static org.onosproject.net.DefaultEdgeLink.createEdgeLink;
import static org.onosproject.net.PortNumber.portNumber;
-import static org.onosproject.net.device.DeviceEvent.Type.DEVICE_ADDED;
-import static org.onosproject.net.device.DeviceEvent.Type.DEVICE_REMOVED;
-import static org.onosproject.net.host.HostEvent.Type.HOST_ADDED;
-import static org.onosproject.net.host.HostEvent.Type.HOST_REMOVED;
-import static org.onosproject.net.link.LinkEvent.Type.LINK_ADDED;
-import static org.onosproject.net.link.LinkEvent.Type.LINK_REMOVED;
import static org.onosproject.ui.topo.TopoConstants.CoreButtons;
import static org.onosproject.ui.topo.TopoConstants.Properties;
import static org.onosproject.ui.topo.TopoUtils.compactLinkString;
@@ -100,6 +93,33 @@ import static org.onosproject.ui.topo.TopoUtils.compactLinkString;
*/
public abstract class TopologyViewMessageHandlerBase extends UiMessageHandler {
+ // default to an "add" event...
+ private static final DefaultHashMap<ClusterEvent.Type, String> CLUSTER_EVENT =
+ new DefaultHashMap<>("addInstance");
+
+ // default to an "update" event...
+ private static final DefaultHashMap<DeviceEvent.Type, String> DEVICE_EVENT =
+ new DefaultHashMap<>("updateDevice");
+ private static final DefaultHashMap<LinkEvent.Type, String> LINK_EVENT =
+ new DefaultHashMap<>("updateLink");
+ private static final DefaultHashMap<HostEvent.Type, String> HOST_EVENT =
+ new DefaultHashMap<>("updateHost");
+
+ // but call out specific events that we care to differentiate...
+ static {
+ CLUSTER_EVENT.put(ClusterEvent.Type.INSTANCE_REMOVED, "removeInstance");
+
+ DEVICE_EVENT.put(DeviceEvent.Type.DEVICE_ADDED, "addDevice");
+ DEVICE_EVENT.put(DeviceEvent.Type.DEVICE_REMOVED, "removeDevice");
+
+ LINK_EVENT.put(LinkEvent.Type.LINK_ADDED, "addLink");
+ LINK_EVENT.put(LinkEvent.Type.LINK_REMOVED, "removeLink");
+
+ HOST_EVENT.put(HostEvent.Type.HOST_ADDED, "addHost");
+ HOST_EVENT.put(HostEvent.Type.HOST_REMOVED, "removeHost");
+ HOST_EVENT.put(HostEvent.Type.HOST_MOVED, "moveHost");
+ }
+
protected static final Logger log =
LoggerFactory.getLogger(TopologyViewMessageHandlerBase.class);
@@ -204,7 +224,7 @@ public abstract class TopologyViewMessageHandlerBase extends UiMessageHandler {
}
// Produces a cluster instance message to the client.
- protected ObjectNode instanceMessage(ClusterEvent event, String messageType) {
+ protected ObjectNode instanceMessage(ClusterEvent event, String msgType) {
ControllerNode node = event.subject();
int switchCount = mastershipService.getDevicesOf(node.id()).size();
ObjectNode payload = objectNode()
@@ -222,10 +242,7 @@ public abstract class TopologyViewMessageHandlerBase extends UiMessageHandler {
payload.set("labels", labels);
addMetaUi(node.id().toString(), payload);
- String type = messageType != null ? messageType :
- ((event.type() == INSTANCE_ADDED) ? "addInstance" :
- ((event.type() == INSTANCE_REMOVED ? "removeInstance" :
- "addInstance")));
+ String type = msgType != null ? msgType : CLUSTER_EVENT.get(event.type());
return JsonUtils.envelope(type, 0, payload);
}
@@ -251,8 +268,7 @@ public abstract class TopologyViewMessageHandlerBase extends UiMessageHandler {
addGeoLocation(device, payload);
addMetaUi(device.id().toString(), payload);
- String type = (event.type() == DEVICE_ADDED) ? "addDevice" :
- ((event.type() == DEVICE_REMOVED) ? "removeDevice" : "updateDevice");
+ String type = DEVICE_EVENT.get(event.type());
return JsonUtils.envelope(type, 0, payload);
}
@@ -268,8 +284,7 @@ public abstract class TopologyViewMessageHandlerBase extends UiMessageHandler {
.put("srcPort", link.src().port().toString())
.put("dst", link.dst().deviceId().toString())
.put("dstPort", link.dst().port().toString());
- String type = (event.type() == LINK_ADDED) ? "addLink" :
- ((event.type() == LINK_REMOVED) ? "removeLink" : "updateLink");
+ String type = LINK_EVENT.get(event.type());
return JsonUtils.envelope(type, 0, payload);
}
@@ -277,20 +292,24 @@ public abstract class TopologyViewMessageHandlerBase extends UiMessageHandler {
protected ObjectNode hostMessage(HostEvent event) {
Host host = event.subject();
String hostType = host.annotations().value(AnnotationKeys.TYPE);
+ HostLocation prevLoc = event.prevLocation();
+
ObjectNode payload = objectNode()
.put("id", host.id().toString())
.put("type", isNullOrEmpty(hostType) ? "endstation" : hostType)
.put("ingress", compactLinkString(edgeLink(host, true)))
.put("egress", compactLinkString(edgeLink(host, false)));
payload.set("cp", hostConnect(host.location()));
+ if (prevLoc != null) {
+ payload.set("prevCp", hostConnect(event.prevLocation()));
+ }
payload.set("labels", labels(ip(host.ipAddresses()),
host.mac().toString()));
payload.set("props", props(host.annotations()));
addGeoLocation(host, payload);
addMetaUi(host.id().toString(), payload);
- String type = (event.type() == HOST_ADDED) ? "addHost" :
- ((event.type() == HOST_REMOVED) ? "removeHost" : "updateHost");
+ String type = HOST_EVENT.get(event.type());
return JsonUtils.envelope(type, 0, payload);
}
diff --git a/framework/src/onos/web/gui/src/main/webapp/app/view/topo/topoEvent.js b/framework/src/onos/web/gui/src/main/webapp/app/view/topo/topoEvent.js
index 2957629a..9b07f878 100644
--- a/framework/src/onos/web/gui/src/main/webapp/app/view/topo/topoEvent.js
+++ b/framework/src/onos/web/gui/src/main/webapp/app/view/topo/topoEvent.js
@@ -55,6 +55,7 @@
removeDevice: tfs,
addHost: tfs,
updateHost: tfs,
+ moveHost: tfs,
removeHost: tfs,
addLink: tfs,
updateLink: tfs,
diff --git a/framework/src/onos/web/gui/src/main/webapp/app/view/topo/topoForce.js b/framework/src/onos/web/gui/src/main/webapp/app/view/topo/topoForce.js
index 844d7dc9..175ee796 100644
--- a/framework/src/onos/web/gui/src/main/webapp/app/view/topo/topoForce.js
+++ b/framework/src/onos/web/gui/src/main/webapp/app/view/topo/topoForce.js
@@ -187,6 +187,35 @@
}
}
+ function moveHost(data) {
+ var id = data.id,
+ d = lu[id],
+ lnk;
+ if (d) {
+ // first remove the old host link
+ removeLinkElement(d.linkData);
+
+ // merge new data
+ angular.extend(d, data);
+ if (tms.positionNode(d, true)) {
+ sendUpdateMeta(d);
+ }
+
+ // now create a new host link
+ lnk = tms.createHostLink(data);
+ if (lnk) {
+ d.linkData = lnk;
+ network.links.push(lnk);
+ lu[d.ingress] = lnk;
+ lu[d.egress] = lnk;
+ }
+
+ updateNodes();
+ updateLinks();
+ fResume();
+ }
+ }
+
function removeHost(data) {
var id = data.id,
d = lu[id];
@@ -1142,6 +1171,7 @@
removeDevice: removeDevice,
addHost: addHost,
updateHost: updateHost,
+ moveHost: moveHost,
removeHost: removeHost,
addLink: addLink,
updateLink: updateLink,