diff --git a/cli/src/main/java/org/onosproject/cli/app/ApplicationsListCommand.java b/cli/src/main/java/org/onosproject/cli/app/ApplicationsListCommand.java index 24b2da17b1..806449e954 100644 --- a/cli/src/main/java/org/onosproject/cli/app/ApplicationsListCommand.java +++ b/cli/src/main/java/org/onosproject/cli/app/ApplicationsListCommand.java @@ -62,16 +62,23 @@ public class ApplicationsListCommand extends AbstractShellCommand { private boolean sortByName = false; + @Option(name = "-r", aliases = "--regapps", description = "Get Registered Apps for Runtime Version") + private boolean getRegisteredApps = false; + @Override protected void doExecute() { ApplicationService service = get(ApplicationService.class); - List apps = newArrayList(service.getApplications()); + List apps; + if (getRegisteredApps) { + apps = newArrayList(service.getRegisteredApplications()); + } else { + apps = newArrayList(service.getApplications()); + } if (sortByName) { apps.sort(Comparator.comparing(app -> app.id().name())); } else { Collections.sort(apps, Comparators.APP_COMPARATOR); } - if (outputJson()) { print("%s", json(service, apps)); } else { diff --git a/core/api/src/main/java/org/onosproject/core/Application.java b/core/api/src/main/java/org/onosproject/core/Application.java index b898cb6078..84279dc90b 100644 --- a/core/api/src/main/java/org/onosproject/core/Application.java +++ b/core/api/src/main/java/org/onosproject/core/Application.java @@ -21,6 +21,7 @@ import java.net.URI; import java.util.List; import java.util.Optional; import java.util.Set; +import java.net.URL; /** * Abstraction of a network control/management application. @@ -132,4 +133,11 @@ public interface Application { * @return list of application names */ List requiredApps(); -} + + /** + * Returns binary image URL. + * + * @return URL of binary image + */ + URL imageUrl(); +} \ No newline at end of file diff --git a/core/api/src/main/java/org/onosproject/core/DefaultApplication.java b/core/api/src/main/java/org/onosproject/core/DefaultApplication.java index 2df2f8ffcc..793ab7017f 100644 --- a/core/api/src/main/java/org/onosproject/core/DefaultApplication.java +++ b/core/api/src/main/java/org/onosproject/core/DefaultApplication.java @@ -26,6 +26,7 @@ import java.util.Set; import java.util.Optional; import java.util.List; import java.util.Objects; +import java.net.URL; import static com.google.common.base.MoreObjects.toStringHelper; import static com.google.common.base.Preconditions.checkArgument; @@ -50,7 +51,7 @@ public final class DefaultApplication implements Application { private final Optional featuresRepo; private final List features; private final List requiredApps; - + private final URL imageUrl; /** * Default constructor is hidden to prevent calls to new. */ @@ -69,6 +70,7 @@ public final class DefaultApplication implements Application { featuresRepo = Optional.empty(); features = ImmutableList.of(); requiredApps = ImmutableList.of(); + imageUrl = null; } /** @@ -88,13 +90,14 @@ public final class DefaultApplication implements Application { * @param featuresRepo optional features repo URI * @param features application features * @param requiredApps list of required application names + * @param imageUrl url of oar file */ - private DefaultApplication(ApplicationId appId, Version version, String title, + public DefaultApplication(ApplicationId appId, Version version, String title, String description, String origin, String category, String url, String readme, byte[] icon, ApplicationRole role, Set permissions, Optional featuresRepo, List features, - List requiredApps) { + List requiredApps, URL imageUrl) { this.appId = appId; this.version = version; this.title = title; @@ -109,8 +112,8 @@ public final class DefaultApplication implements Application { this.featuresRepo = featuresRepo; this.features = ImmutableList.copyOf(features); this.requiredApps = ImmutableList.copyOf(requiredApps); + this.imageUrl = imageUrl; } - @Override public ApplicationId id() { return appId; @@ -181,6 +184,11 @@ public final class DefaultApplication implements Application { return requiredApps; } + @Override + public URL imageUrl() { + return imageUrl; + } + @Override public int hashCode() { return Objects.hash(appId, version, title, description, origin, category, url, @@ -230,6 +238,7 @@ public final class DefaultApplication implements Application { .add("featuresRepo", featuresRepo) .add("features", features) .add("requiredApps", requiredApps) + .add("imageURL", imageUrl) .toString(); } @@ -277,7 +286,6 @@ public final class DefaultApplication implements Application { * Default application builder. */ public static final class Builder { - private ApplicationId appId; private Version version; private String title; @@ -285,13 +293,14 @@ public final class DefaultApplication implements Application { private String category; private String url; private String readme; - private byte[] icon; + private byte[] icon = new byte[0]; private String origin; - private ApplicationRole role; - private Set permissions; - private Optional featuresRepo; - private List features; - private List requiredApps; + private ApplicationRole role = ApplicationRole.ADMIN; + private Set permissions = ImmutableSet.of(); + private Optional featuresRepo = Optional.empty(); + private List features = ImmutableList.of(); + private List requiredApps = ImmutableList.of(); + private URL imageUrl; /** * Default constructor for the builder. @@ -517,6 +526,17 @@ public final class DefaultApplication implements Application { return this; } + /** + * Adds a Binary Image URL. + * + * @param imageUrl url of oar file + * @return builder + */ + public Builder withImageUrl(URL imageUrl) { + this.imageUrl = imageUrl; + return this; + } + /** * Builds a default application object from the gathered parameters. * @@ -542,7 +562,7 @@ public final class DefaultApplication implements Application { url, readme, icon, role, permissions, featuresRepo, features, - requiredApps); + requiredApps, imageUrl); } } -} +} \ No newline at end of file diff --git a/core/api/src/test/java/org/onosproject/core/DefaultApplicationTest.java b/core/api/src/test/java/org/onosproject/core/DefaultApplicationTest.java index b52312608d..98dccece6d 100644 --- a/core/api/src/test/java/org/onosproject/core/DefaultApplicationTest.java +++ b/core/api/src/test/java/org/onosproject/core/DefaultApplicationTest.java @@ -49,20 +49,20 @@ public class DefaultApplicationTest { public static final ApplicationId APP_ID = new DefaultApplicationId(2, APP_NAME); private Builder baseBuilder = DefaultApplication.builder() - .withAppId(APP_ID) - .withVersion(VER) - .withTitle(TITLE) - .withDescription(DESC) - .withOrigin(ORIGIN) - .withCategory(CATEGORY) - .withUrl(URL) - .withReadme(README) - .withIcon(ICON) - .withRole(ROLE) - .withPermissions(PERMS) - .withFeaturesRepo(Optional.of(FURL)) - .withFeatures(FEATURES) - .withRequiredApps(APPS); + .withAppId(APP_ID) + .withVersion(VER) + .withTitle(TITLE) + .withDescription(DESC) + .withOrigin(ORIGIN) + .withCategory(CATEGORY) + .withUrl(URL) + .withReadme(README) + .withIcon(ICON) + .withRole(ROLE) + .withPermissions(PERMS) + .withFeaturesRepo(Optional.of(FURL)) + .withFeatures(FEATURES) + .withRequiredApps(APPS); @Test public void basics() { @@ -77,8 +77,8 @@ public class DefaultApplicationTest { assertEquals("incorrect URL", URL, app.url()); assertEquals("incorrect readme", README, app.readme()); assertArrayEquals("incorrect icon", ICON, app.icon()); - assertEquals("incorrect role", ROLE, app.role()); assertEquals("incorrect permissions", PERMS, app.permissions()); + assertEquals("incorrect role", ROLE, app.role()); assertEquals("incorrect features repo", FURL, app.featuresRepo().get()); assertEquals("incorrect features", FEATURES, app.features()); assertEquals("incorrect apps", APPS, app.requiredApps()); @@ -88,7 +88,7 @@ public class DefaultApplicationTest { @Test public void testEquality() { Application a1 = baseBuilder.build(); - Application a2 = DefaultApplication.builder(a1) + Application a2 = DefaultApplication.builder(a1) .build(); Application a3 = DefaultApplication.builder(baseBuilder) .withFeaturesRepo(Optional.empty()) @@ -227,4 +227,4 @@ public class DefaultApplicationTest { assertNotNull("null icon", icon); assertEquals("unexpected size", 0, icon.length); } -} +} \ No newline at end of file diff --git a/core/net/src/main/java/org/onosproject/app/impl/ApplicationManager.java b/core/net/src/main/java/org/onosproject/app/impl/ApplicationManager.java index 2bb9c117b0..7ea40d4fc0 100644 --- a/core/net/src/main/java/org/onosproject/app/impl/ApplicationManager.java +++ b/core/net/src/main/java/org/onosproject/app/impl/ApplicationManager.java @@ -15,9 +15,15 @@ */ package org.onosproject.app.impl; +import com.fasterxml.jackson.databind.JsonNode; +import com.fasterxml.jackson.databind.ObjectMapper; +import com.fasterxml.jackson.databind.node.ArrayNode; +import com.fasterxml.jackson.databind.node.ObjectNode; import com.google.common.cache.Cache; import com.google.common.cache.CacheBuilder; import com.google.common.collect.HashMultimap; +import com.google.common.collect.ImmutableList; +import com.google.common.collect.ImmutableSet; import com.google.common.collect.Multimap; import com.google.common.util.concurrent.Uninterruptibles; import org.apache.karaf.features.Feature; @@ -31,6 +37,10 @@ import org.onosproject.app.ApplicationStore; import org.onosproject.app.ApplicationStoreDelegate; import org.onosproject.core.Application; import org.onosproject.core.ApplicationId; +import org.onosproject.core.DefaultApplication; +import org.onosproject.core.DefaultApplicationId; +import org.onosproject.core.Version; +import org.onosproject.core.VersionService; import org.onosproject.event.AbstractListenerManager; import org.onosproject.security.Permission; import org.onosproject.security.SecurityUtil; @@ -41,17 +51,19 @@ import org.osgi.service.component.annotations.Reference; import org.osgi.service.component.annotations.ReferenceCardinality; import org.slf4j.Logger; +import java.io.IOException; import java.io.InputStream; +import java.net.HttpURLConnection; +import java.net.MalformedURLException; +import java.net.URL; +import java.util.Iterator; import java.util.Set; import java.util.concurrent.CountDownLatch; import java.util.concurrent.TimeUnit; import java.util.function.Consumer; import static com.google.common.base.Preconditions.checkNotNull; -import static org.onosproject.app.ApplicationEvent.Type.APP_ACTIVATED; -import static org.onosproject.app.ApplicationEvent.Type.APP_DEACTIVATED; -import static org.onosproject.app.ApplicationEvent.Type.APP_INSTALLED; -import static org.onosproject.app.ApplicationEvent.Type.APP_UNINSTALLED; +import static org.onosproject.app.ApplicationEvent.Type.*; import static org.onosproject.security.AppGuard.checkPermission; import static org.onosproject.security.AppPermission.Type.APP_READ; import static org.slf4j.LoggerFactory.getLogger; @@ -66,9 +78,10 @@ public class ApplicationManager private final Logger log = getLogger(getClass()); + private static final String APP_REGISTRY_URL = "http://api.onosproject.org:8080/api/applications"; + private static final String APP_ID_NULL = "Application ID cannot be null"; private static final long DEFAULT_OPERATION_TIMEOUT_MILLIS = 2000; - private final ApplicationStoreDelegate delegate = new InternalStoreDelegate(); @Reference(cardinality = ReferenceCardinality.MANDATORY) @@ -77,12 +90,15 @@ public class ApplicationManager @Reference(cardinality = ReferenceCardinality.MANDATORY) protected FeaturesService featuresService; + @Reference(cardinality = ReferenceCardinality.MANDATORY) + protected VersionService versionService; + // Application supplied hooks for pre-activation processing. private final Multimap deactivateHooks = HashMultimap.create(); private final Cache pendingOperations = CacheBuilder.newBuilder() - .expireAfterWrite(DEFAULT_OPERATION_TIMEOUT_MILLIS * 2, TimeUnit.MILLISECONDS) - .build(); + .expireAfterWrite(DEFAULT_OPERATION_TIMEOUT_MILLIS * 2, TimeUnit.MILLISECONDS) + .build(); @Activate public void activate() { @@ -303,7 +319,8 @@ public class ApplicationManager } // Invokes the specified function, if not null. - @java.lang.SuppressWarnings("squid:S1217") // We really do mean to call run() + @java.lang.SuppressWarnings("squid:S1217") + // We really do mean to call run() private void invokeHook(Runnable hook, ApplicationId appId) { if (hook != null) { try { @@ -315,4 +332,68 @@ public class ApplicationManager } } -} + @Override + public Set getRegisteredApplications() { + ImmutableSet.Builder builder = ImmutableSet.builder(); + ObjectMapper mapper = new ObjectMapper(); + + // Get input stream from the URL + try { + URL githubUrl = new URL(APP_REGISTRY_URL + "?onosVersion=" + versionService.version().toString()); + HttpURLConnection githubHttp = (HttpURLConnection) githubUrl.openConnection(); + InputStream githubStream = githubHttp.getInputStream(); + + // Read input stream into an ArrayNode + ArrayNode rootTree = (ArrayNode) mapper.readTree(githubStream); + + // Iterate over the array node for each object add each version as application object to the set + rootTree.forEach(n -> { + mapObject(builder, (ObjectNode) n); + }); + + //Iterate through Builder to remove unnecessary apps + Set apps = builder.build(); + + return apps; + } catch (MalformedURLException e) { + throw new IllegalStateException("Bad URL " + APP_REGISTRY_URL, e); + } catch (IOException e) { + throw new IllegalStateException("Unable to fetch URL " + APP_REGISTRY_URL, e); + } + } + + private void mapObject(ImmutableSet.Builder apps, ObjectNode node) { + String appIDs = node.get("id").asText(); + ApplicationId appID = new DefaultApplicationId(1, appIDs); + String title = node.get("title").asText(); + String readme = node.get("readme").asText(); + String category = node.get("category").asText(); + String url = node.get("url").asText(); + String origin = node.get("maintainer").asText(); + JsonNode it = node.get("versions"); + Iterator iterate = it.iterator(); + while (iterate.hasNext()) { + DefaultApplication.Builder app = new DefaultApplication.Builder(); + JsonNode jsonNode = (JsonNode) iterate.next(); + URL imageUrl = null; + try { + imageUrl = new URL(jsonNode.get("oarURL").asText()); + } catch (MalformedURLException e) { + e.printStackTrace(); + } + Version version1 = Version.version(jsonNode.get("onosVersion").asText()); + app.withImageUrl(imageUrl) + .withAppId(new DefaultApplicationId(1, node.get("id").asText())) + .withVersion(version1) + .withAppId(appID) + .withReadme(readme) + .withDescription(readme) + .withTitle(title) + .withFeatures(ImmutableList.of("none")) + .withCategory(category) + .withUrl(url) + .withOrigin(origin); + apps.add(app.build()); + } + } +} \ No newline at end of file diff --git a/core/net/src/test/java/org/onosproject/app/impl/ApplicationManagerTest.java b/core/net/src/test/java/org/onosproject/app/impl/ApplicationManagerTest.java index 5528f269a9..203abb7801 100644 --- a/core/net/src/test/java/org/onosproject/app/impl/ApplicationManagerTest.java +++ b/core/net/src/test/java/org/onosproject/app/impl/ApplicationManagerTest.java @@ -29,6 +29,8 @@ import org.onosproject.core.Application; import org.onosproject.core.ApplicationId; import org.onosproject.core.DefaultApplication; import org.onosproject.core.DefaultApplicationId; +import org.onosproject.core.Version; +import org.onosproject.core.VersionServiceAdapter; import java.io.InputStream; import java.net.URI; @@ -49,10 +51,13 @@ import static org.onosproject.net.NetTestTools.injectEventDispatcher; public class ApplicationManagerTest { public static final DefaultApplicationId APP_ID = new DefaultApplicationId(1, APP_NAME); + private static final Version CORE_VERSION = Version.version(2, 1, "0", ""); private ApplicationManager mgr = new ApplicationManager(); private ApplicationListener listener = new TestListener(); + + private boolean deactivated = false; @Before @@ -80,6 +85,22 @@ public class ApplicationManagerTest { assertEquals("incorrect features", FEATURES, app.features()); } + @Test + public void testGetRegisteredApps() { + mgr.versionService = new TestVersionService(); + Set apps = mgr.getRegisteredApplications(); + System.out.println(apps); + assertFalse("SET contains less Apps than it should", apps.size() < 158); + } + + private static class TestVersionService extends VersionServiceAdapter { + + @Override + public Version version() { + return CORE_VERSION; + } + } + @Test public void install() { InputStream stream = ApplicationArchive.class.getResourceAsStream("app.zip"); @@ -223,4 +244,4 @@ public class ApplicationManagerTest { } } -} +} \ No newline at end of file diff --git a/core/store/serializers/src/main/java/org/onosproject/store/serializers/KryoNamespaces.java b/core/store/serializers/src/main/java/org/onosproject/store/serializers/KryoNamespaces.java index 75187afdfc..2a07a61183 100644 --- a/core/store/serializers/src/main/java/org/onosproject/store/serializers/KryoNamespaces.java +++ b/core/store/serializers/src/main/java/org/onosproject/store/serializers/KryoNamespaces.java @@ -294,6 +294,7 @@ import org.onosproject.upgrade.Upgrade; import java.lang.invoke.SerializedLambda; import java.net.URI; +import java.net.URL; import java.time.Duration; import java.util.ArrayList; import java.util.Arrays; @@ -433,6 +434,7 @@ public final class KryoNamespaces { .register(MISC) .nextId(KryoNamespace.INITIAL_ID + BASIC_MAX_SIZE + MISC_MAX_SIZE) .register( + URL.class, Instructions.MeterInstruction.class, Instructions.StatTriggerInstruction.class, StatTriggerFlag.class,