Committed by
Gerrit Code Review
ONOS-1684 Added support for app dependencies.
Change-Id: Iae318c24c3c9bd43d84318c79ac420fc85d5d599
Showing
18 changed files
with
161 additions
and
33 deletions
... | @@ -41,7 +41,7 @@ public class ApplicationsListCommand extends AbstractShellCommand { | ... | @@ -41,7 +41,7 @@ public class ApplicationsListCommand extends AbstractShellCommand { |
41 | 41 | ||
42 | private static final String FMT = | 42 | private static final String FMT = |
43 | "%s id=%d, name=%s, version=%s, origin=%s, description=%s, " + | 43 | "%s id=%d, name=%s, version=%s, origin=%s, description=%s, " + |
44 | - "features=%s, featuresRepo=%s, permissions=%s"; | 44 | + "features=%s, featuresRepo=%s, apps=%s, permissions=%s"; |
45 | 45 | ||
46 | private static final String SHORT_FMT = | 46 | private static final String SHORT_FMT = |
47 | "%s %3d %-32s %-8s %s"; | 47 | "%s %3d %-32s %-8s %s"; |
... | @@ -76,7 +76,7 @@ public class ApplicationsListCommand extends AbstractShellCommand { | ... | @@ -76,7 +76,7 @@ public class ApplicationsListCommand extends AbstractShellCommand { |
76 | app.id().id(), app.id().name(), app.version(), app.origin(), | 76 | app.id().id(), app.id().name(), app.version(), app.origin(), |
77 | app.description(), app.features(), | 77 | app.description(), app.features(), |
78 | app.featuresRepo().isPresent() ? app.featuresRepo().get().toString() : "", | 78 | app.featuresRepo().isPresent() ? app.featuresRepo().get().toString() : "", |
79 | - app.permissions()); | 79 | + app.requiredApps(), app.permissions()); |
80 | } | 80 | } |
81 | } | 81 | } |
82 | } | 82 | } | ... | ... |
... | @@ -86,4 +86,11 @@ public interface ApplicationDescription { | ... | @@ -86,4 +86,11 @@ public interface ApplicationDescription { |
86 | * @return application features | 86 | * @return application features |
87 | */ | 87 | */ |
88 | List<String> features(); | 88 | List<String> features(); |
89 | + | ||
90 | + /** | ||
91 | + * Returns list of required application names. | ||
92 | + * | ||
93 | + * @return list of application names | ||
94 | + */ | ||
95 | + List<String> requiredApps(); | ||
89 | } | 96 | } | ... | ... |
... | @@ -76,7 +76,7 @@ public interface ApplicationStore extends Store<ApplicationEvent, ApplicationSto | ... | @@ -76,7 +76,7 @@ public interface ApplicationStore extends Store<ApplicationEvent, ApplicationSto |
76 | void remove(ApplicationId appId); | 76 | void remove(ApplicationId appId); |
77 | 77 | ||
78 | /** | 78 | /** |
79 | - * Mark the application as actived. | 79 | + * Mark the application as active. |
80 | * | 80 | * |
81 | * @param appId application identifier | 81 | * @param appId application identifier |
82 | */ | 82 | */ | ... | ... |
... | @@ -41,6 +41,7 @@ public class DefaultApplicationDescription implements ApplicationDescription { | ... | @@ -41,6 +41,7 @@ public class DefaultApplicationDescription implements ApplicationDescription { |
41 | private final Set<Permission> permissions; | 41 | private final Set<Permission> permissions; |
42 | private final Optional<URI> featuresRepo; | 42 | private final Optional<URI> featuresRepo; |
43 | private final List<String> features; | 43 | private final List<String> features; |
44 | + private final List<String> requiredApps; | ||
44 | 45 | ||
45 | /** | 46 | /** |
46 | * Creates a new application descriptor using the supplied data. | 47 | * Creates a new application descriptor using the supplied data. |
... | @@ -53,11 +54,13 @@ public class DefaultApplicationDescription implements ApplicationDescription { | ... | @@ -53,11 +54,13 @@ public class DefaultApplicationDescription implements ApplicationDescription { |
53 | * @param permissions requested permissions | 54 | * @param permissions requested permissions |
54 | * @param featuresRepo optional features repo URI | 55 | * @param featuresRepo optional features repo URI |
55 | * @param features application features | 56 | * @param features application features |
57 | + * @param requiredApps list of required application names | ||
56 | */ | 58 | */ |
57 | public DefaultApplicationDescription(String name, Version version, | 59 | public DefaultApplicationDescription(String name, Version version, |
58 | String description, String origin, | 60 | String description, String origin, |
59 | ApplicationRole role, Set<Permission> permissions, | 61 | ApplicationRole role, Set<Permission> permissions, |
60 | - URI featuresRepo, List<String> features) { | 62 | + URI featuresRepo, List<String> features, |
63 | + List<String> requiredApps) { | ||
61 | this.name = checkNotNull(name, "Name cannot be null"); | 64 | this.name = checkNotNull(name, "Name cannot be null"); |
62 | this.version = checkNotNull(version, "Version cannot be null"); | 65 | this.version = checkNotNull(version, "Version cannot be null"); |
63 | this.description = checkNotNull(description, "Description cannot be null"); | 66 | this.description = checkNotNull(description, "Description cannot be null"); |
... | @@ -66,6 +69,7 @@ public class DefaultApplicationDescription implements ApplicationDescription { | ... | @@ -66,6 +69,7 @@ public class DefaultApplicationDescription implements ApplicationDescription { |
66 | this.permissions = checkNotNull(permissions, "Permissions cannot be null"); | 69 | this.permissions = checkNotNull(permissions, "Permissions cannot be null"); |
67 | this.featuresRepo = Optional.ofNullable(featuresRepo); | 70 | this.featuresRepo = Optional.ofNullable(featuresRepo); |
68 | this.features = checkNotNull(features, "Features cannot be null"); | 71 | this.features = checkNotNull(features, "Features cannot be null"); |
72 | + this.requiredApps = checkNotNull(requiredApps, "Required apps cannot be null"); | ||
69 | checkArgument(!features.isEmpty(), "There must be at least one feature"); | 73 | checkArgument(!features.isEmpty(), "There must be at least one feature"); |
70 | } | 74 | } |
71 | 75 | ||
... | @@ -110,6 +114,11 @@ public class DefaultApplicationDescription implements ApplicationDescription { | ... | @@ -110,6 +114,11 @@ public class DefaultApplicationDescription implements ApplicationDescription { |
110 | } | 114 | } |
111 | 115 | ||
112 | @Override | 116 | @Override |
117 | + public List<String> requiredApps() { | ||
118 | + return requiredApps; | ||
119 | + } | ||
120 | + | ||
121 | + @Override | ||
113 | public String toString() { | 122 | public String toString() { |
114 | return toStringHelper(this) | 123 | return toStringHelper(this) |
115 | .add("name", name) | 124 | .add("name", name) |
... | @@ -120,6 +129,7 @@ public class DefaultApplicationDescription implements ApplicationDescription { | ... | @@ -120,6 +129,7 @@ public class DefaultApplicationDescription implements ApplicationDescription { |
120 | .add("permissions", permissions) | 129 | .add("permissions", permissions) |
121 | .add("featuresRepo", featuresRepo) | 130 | .add("featuresRepo", featuresRepo) |
122 | .add("features", features) | 131 | .add("features", features) |
132 | + .add("requiredApps", requiredApps) | ||
123 | .toString(); | 133 | .toString(); |
124 | } | 134 | } |
125 | } | 135 | } | ... | ... |
... | @@ -84,4 +84,11 @@ public interface Application { | ... | @@ -84,4 +84,11 @@ public interface Application { |
84 | * @return application features | 84 | * @return application features |
85 | */ | 85 | */ |
86 | List<String> features(); | 86 | List<String> features(); |
87 | + | ||
88 | + /** | ||
89 | + * Returns list of required application names. | ||
90 | + * | ||
91 | + * @return list of application names | ||
92 | + */ | ||
93 | + List<String> requiredApps(); | ||
87 | } | 94 | } | ... | ... |
... | @@ -40,6 +40,7 @@ public class DefaultApplication implements Application { | ... | @@ -40,6 +40,7 @@ public class DefaultApplication implements Application { |
40 | private final Set<Permission> permissions; | 40 | private final Set<Permission> permissions; |
41 | private final Optional<URI> featuresRepo; | 41 | private final Optional<URI> featuresRepo; |
42 | private final List<String> features; | 42 | private final List<String> features; |
43 | + private final List<String> requiredApps; | ||
43 | 44 | ||
44 | /** | 45 | /** |
45 | * Creates a new application descriptor using the supplied data. | 46 | * Creates a new application descriptor using the supplied data. |
... | @@ -52,11 +53,13 @@ public class DefaultApplication implements Application { | ... | @@ -52,11 +53,13 @@ public class DefaultApplication implements Application { |
52 | * @param permissions requested permissions | 53 | * @param permissions requested permissions |
53 | * @param featuresRepo optional features repo URI | 54 | * @param featuresRepo optional features repo URI |
54 | * @param features application features | 55 | * @param features application features |
56 | + * @param requiredApps list of required application names | ||
55 | */ | 57 | */ |
56 | public DefaultApplication(ApplicationId appId, Version version, | 58 | public DefaultApplication(ApplicationId appId, Version version, |
57 | String description, String origin, | 59 | String description, String origin, |
58 | ApplicationRole role, Set<Permission> permissions, | 60 | ApplicationRole role, Set<Permission> permissions, |
59 | - Optional<URI> featuresRepo, List<String> features) { | 61 | + Optional<URI> featuresRepo, List<String> features, |
62 | + List<String> requiredApps) { | ||
60 | this.appId = checkNotNull(appId, "ID cannot be null"); | 63 | this.appId = checkNotNull(appId, "ID cannot be null"); |
61 | this.version = checkNotNull(version, "Version cannot be null"); | 64 | this.version = checkNotNull(version, "Version cannot be null"); |
62 | this.description = checkNotNull(description, "Description cannot be null"); | 65 | this.description = checkNotNull(description, "Description cannot be null"); |
... | @@ -65,6 +68,7 @@ public class DefaultApplication implements Application { | ... | @@ -65,6 +68,7 @@ public class DefaultApplication implements Application { |
65 | this.permissions = checkNotNull(permissions, "Permissions cannot be null"); | 68 | this.permissions = checkNotNull(permissions, "Permissions cannot be null"); |
66 | this.featuresRepo = checkNotNull(featuresRepo, "Features repo cannot be null"); | 69 | this.featuresRepo = checkNotNull(featuresRepo, "Features repo cannot be null"); |
67 | this.features = checkNotNull(features, "Features cannot be null"); | 70 | this.features = checkNotNull(features, "Features cannot be null"); |
71 | + this.requiredApps = checkNotNull(requiredApps, "Required apps cannot be null"); | ||
68 | checkArgument(!features.isEmpty(), "There must be at least one feature"); | 72 | checkArgument(!features.isEmpty(), "There must be at least one feature"); |
69 | } | 73 | } |
70 | 74 | ||
... | @@ -109,9 +113,14 @@ public class DefaultApplication implements Application { | ... | @@ -109,9 +113,14 @@ public class DefaultApplication implements Application { |
109 | } | 113 | } |
110 | 114 | ||
111 | @Override | 115 | @Override |
116 | + public List<String> requiredApps() { | ||
117 | + return requiredApps; | ||
118 | + } | ||
119 | + | ||
120 | + @Override | ||
112 | public int hashCode() { | 121 | public int hashCode() { |
113 | return Objects.hash(appId, version, description, origin, role, permissions, | 122 | return Objects.hash(appId, version, description, origin, role, permissions, |
114 | - featuresRepo, features); | 123 | + featuresRepo, features, requiredApps); |
115 | } | 124 | } |
116 | 125 | ||
117 | @Override | 126 | @Override |
... | @@ -130,7 +139,8 @@ public class DefaultApplication implements Application { | ... | @@ -130,7 +139,8 @@ public class DefaultApplication implements Application { |
130 | Objects.equals(this.role, other.role) && | 139 | Objects.equals(this.role, other.role) && |
131 | Objects.equals(this.permissions, other.permissions) && | 140 | Objects.equals(this.permissions, other.permissions) && |
132 | Objects.equals(this.featuresRepo, other.featuresRepo) && | 141 | Objects.equals(this.featuresRepo, other.featuresRepo) && |
133 | - Objects.equals(this.features, other.features); | 142 | + Objects.equals(this.features, other.features) && |
143 | + Objects.equals(this.requiredApps, other.requiredApps); | ||
134 | } | 144 | } |
135 | 145 | ||
136 | @Override | 146 | @Override |
... | @@ -144,6 +154,7 @@ public class DefaultApplication implements Application { | ... | @@ -144,6 +154,7 @@ public class DefaultApplication implements Application { |
144 | .add("permissions", permissions) | 154 | .add("permissions", permissions) |
145 | .add("featuresRepo", featuresRepo) | 155 | .add("featuresRepo", featuresRepo) |
146 | .add("features", features) | 156 | .add("features", features) |
157 | + .add("requiredApps", requiredApps) | ||
147 | .toString(); | 158 | .toString(); |
148 | } | 159 | } |
149 | } | 160 | } | ... | ... |
... | @@ -33,7 +33,7 @@ public class ApplicationEventTest extends AbstractEventTest { | ... | @@ -33,7 +33,7 @@ public class ApplicationEventTest extends AbstractEventTest { |
33 | 33 | ||
34 | private Application createApp() { | 34 | private Application createApp() { |
35 | return new DefaultApplication(APP_ID, VER, DESC, ORIGIN, ROLE, | 35 | return new DefaultApplication(APP_ID, VER, DESC, ORIGIN, ROLE, |
36 | - PERMS, Optional.of(FURL), FEATURES); | 36 | + PERMS, Optional.of(FURL), FEATURES, APPS); |
37 | } | 37 | } |
38 | 38 | ||
39 | @Test | 39 | @Test | ... | ... |
... | @@ -46,12 +46,13 @@ public class DefaultApplicationDescriptionTest { | ... | @@ -46,12 +46,13 @@ public class DefaultApplicationDescriptionTest { |
46 | new Permission(AppPermission.class.getName(), "FLOWRULE_READ")); | 46 | new Permission(AppPermission.class.getName(), "FLOWRULE_READ")); |
47 | public static final URI FURL = URI.create("mvn:org.foo-features/1.2a/xml/features"); | 47 | public static final URI FURL = URI.create("mvn:org.foo-features/1.2a/xml/features"); |
48 | public static final List<String> FEATURES = ImmutableList.of("foo", "bar"); | 48 | public static final List<String> FEATURES = ImmutableList.of("foo", "bar"); |
49 | + public static final List<String> APPS = ImmutableList.of("fifi"); | ||
49 | 50 | ||
50 | @Test | 51 | @Test |
51 | public void basics() { | 52 | public void basics() { |
52 | ApplicationDescription app = | 53 | ApplicationDescription app = |
53 | new DefaultApplicationDescription(APP_NAME, VER, DESC, ORIGIN, | 54 | new DefaultApplicationDescription(APP_NAME, VER, DESC, ORIGIN, |
54 | - ROLE, PERMS, FURL, FEATURES); | 55 | + ROLE, PERMS, FURL, FEATURES, APPS); |
55 | assertEquals("incorrect id", APP_NAME, app.name()); | 56 | assertEquals("incorrect id", APP_NAME, app.name()); |
56 | assertEquals("incorrect version", VER, app.version()); | 57 | assertEquals("incorrect version", VER, app.version()); |
57 | assertEquals("incorrect description", DESC, app.description()); | 58 | assertEquals("incorrect description", DESC, app.description()); |
... | @@ -60,6 +61,7 @@ public class DefaultApplicationDescriptionTest { | ... | @@ -60,6 +61,7 @@ public class DefaultApplicationDescriptionTest { |
60 | assertEquals("incorrect permissions", PERMS, app.permissions()); | 61 | assertEquals("incorrect permissions", PERMS, app.permissions()); |
61 | assertEquals("incorrect features repo", FURL, app.featuresRepo().get()); | 62 | assertEquals("incorrect features repo", FURL, app.featuresRepo().get()); |
62 | assertEquals("incorrect features", FEATURES, app.features()); | 63 | assertEquals("incorrect features", FEATURES, app.features()); |
64 | + assertEquals("incorrect apps", APPS, app.requiredApps()); | ||
63 | assertTrue("incorrect toString", app.toString().contains(APP_NAME)); | 65 | assertTrue("incorrect toString", app.toString().contains(APP_NAME)); |
64 | } | 66 | } |
65 | 67 | ... | ... |
... | @@ -34,7 +34,7 @@ public class DefaultApplicationTest { | ... | @@ -34,7 +34,7 @@ public class DefaultApplicationTest { |
34 | @Test | 34 | @Test |
35 | public void basics() { | 35 | public void basics() { |
36 | Application app = new DefaultApplication(APP_ID, VER, DESC, ORIGIN, ROLE, | 36 | Application app = new DefaultApplication(APP_ID, VER, DESC, ORIGIN, ROLE, |
37 | - PERMS, Optional.of(FURL), FEATURES); | 37 | + PERMS, Optional.of(FURL), FEATURES, APPS); |
38 | assertEquals("incorrect id", APP_ID, app.id()); | 38 | assertEquals("incorrect id", APP_ID, app.id()); |
39 | assertEquals("incorrect version", VER, app.version()); | 39 | assertEquals("incorrect version", VER, app.version()); |
40 | assertEquals("incorrect description", DESC, app.description()); | 40 | assertEquals("incorrect description", DESC, app.description()); |
... | @@ -43,19 +43,20 @@ public class DefaultApplicationTest { | ... | @@ -43,19 +43,20 @@ public class DefaultApplicationTest { |
43 | assertEquals("incorrect permissions", PERMS, app.permissions()); | 43 | assertEquals("incorrect permissions", PERMS, app.permissions()); |
44 | assertEquals("incorrect features repo", FURL, app.featuresRepo().get()); | 44 | assertEquals("incorrect features repo", FURL, app.featuresRepo().get()); |
45 | assertEquals("incorrect features", FEATURES, app.features()); | 45 | assertEquals("incorrect features", FEATURES, app.features()); |
46 | + assertEquals("incorrect apps", APPS, app.requiredApps()); | ||
46 | assertTrue("incorrect toString", app.toString().contains(APP_NAME)); | 47 | assertTrue("incorrect toString", app.toString().contains(APP_NAME)); |
47 | } | 48 | } |
48 | 49 | ||
49 | @Test | 50 | @Test |
50 | public void testEquality() { | 51 | public void testEquality() { |
51 | Application a1 = new DefaultApplication(APP_ID, VER, DESC, ORIGIN, ROLE, | 52 | Application a1 = new DefaultApplication(APP_ID, VER, DESC, ORIGIN, ROLE, |
52 | - PERMS, Optional.of(FURL), FEATURES); | 53 | + PERMS, Optional.of(FURL), FEATURES, APPS); |
53 | Application a2 = new DefaultApplication(APP_ID, VER, DESC, ORIGIN, ROLE, | 54 | Application a2 = new DefaultApplication(APP_ID, VER, DESC, ORIGIN, ROLE, |
54 | - PERMS, Optional.of(FURL), FEATURES); | 55 | + PERMS, Optional.of(FURL), FEATURES, APPS); |
55 | Application a3 = new DefaultApplication(APP_ID, VER, DESC, ORIGIN, ROLE, | 56 | Application a3 = new DefaultApplication(APP_ID, VER, DESC, ORIGIN, ROLE, |
56 | - PERMS, Optional.empty(), FEATURES); | 57 | + PERMS, Optional.empty(), FEATURES, APPS); |
57 | Application a4 = new DefaultApplication(APP_ID, VER, DESC, ORIGIN + "asd", ROLE, | 58 | Application a4 = new DefaultApplication(APP_ID, VER, DESC, ORIGIN + "asd", ROLE, |
58 | - PERMS, Optional.of(FURL), FEATURES); | 59 | + PERMS, Optional.of(FURL), FEATURES, APPS); |
59 | new EqualsTester().addEqualityGroup(a1, a2) | 60 | new EqualsTester().addEqualityGroup(a1, a2) |
60 | .addEqualityGroup(a3).addEqualityGroup(a4).testEquals(); | 61 | .addEqualityGroup(a3).addEqualityGroup(a4).testEquals(); |
61 | } | 62 | } | ... | ... |
... | @@ -32,18 +32,18 @@ public final class ApplicationCodec extends JsonCodec<Application> { | ... | @@ -32,18 +32,18 @@ public final class ApplicationCodec extends JsonCodec<Application> { |
32 | public ObjectNode encode(Application app, CodecContext context) { | 32 | public ObjectNode encode(Application app, CodecContext context) { |
33 | checkNotNull(app, "Application cannot be null"); | 33 | checkNotNull(app, "Application cannot be null"); |
34 | ApplicationService service = context.getService(ApplicationService.class); | 34 | ApplicationService service = context.getService(ApplicationService.class); |
35 | - ObjectNode result = context.mapper().createObjectNode() | 35 | + return context.mapper().createObjectNode() |
36 | .put("name", app.id().name()) | 36 | .put("name", app.id().name()) |
37 | .put("id", app.id().id()) | 37 | .put("id", app.id().id()) |
38 | .put("version", app.version().toString()) | 38 | .put("version", app.version().toString()) |
39 | .put("description", app.description()) | 39 | .put("description", app.description()) |
40 | .put("origin", app.origin()) | 40 | .put("origin", app.origin()) |
41 | - .put("permissions", app.permissions().toString()) | 41 | + .put("permissions", app.permissions().toString()) // FIXME: change to an array |
42 | .put("featuresRepo", app.featuresRepo().isPresent() ? | 42 | .put("featuresRepo", app.featuresRepo().isPresent() ? |
43 | app.featuresRepo().get().toString() : "") | 43 | app.featuresRepo().get().toString() : "") |
44 | - .put("features", app.features().toString()) | 44 | + .put("features", app.features().toString()) // FIXME: change to an array |
45 | + .put("requiredApps", app.requiredApps().toString()) // FIXME: change to an array | ||
45 | .put("state", service.getState(app.id()).toString()); | 46 | .put("state", service.getState(app.id()).toString()); |
46 | - return result; | ||
47 | } | 47 | } |
48 | 48 | ||
49 | } | 49 | } | ... | ... |
... | @@ -17,6 +17,7 @@ package org.onosproject.common.app; | ... | @@ -17,6 +17,7 @@ package org.onosproject.common.app; |
17 | 17 | ||
18 | import com.google.common.collect.ImmutableList; | 18 | import com.google.common.collect.ImmutableList; |
19 | import com.google.common.collect.ImmutableSet; | 19 | import com.google.common.collect.ImmutableSet; |
20 | +import com.google.common.collect.Lists; | ||
20 | import com.google.common.io.ByteStreams; | 21 | import com.google.common.io.ByteStreams; |
21 | import com.google.common.io.Files; | 22 | import com.google.common.io.Files; |
22 | import org.apache.commons.configuration.ConfigurationException; | 23 | import org.apache.commons.configuration.ConfigurationException; |
... | @@ -33,7 +34,6 @@ import org.onosproject.core.Version; | ... | @@ -33,7 +34,6 @@ import org.onosproject.core.Version; |
33 | import org.onosproject.security.AppPermission; | 34 | import org.onosproject.security.AppPermission; |
34 | import org.onosproject.security.Permission; | 35 | import org.onosproject.security.Permission; |
35 | import org.onosproject.store.AbstractStore; | 36 | import org.onosproject.store.AbstractStore; |
36 | - | ||
37 | import org.slf4j.Logger; | 37 | import org.slf4j.Logger; |
38 | import org.slf4j.LoggerFactory; | 38 | import org.slf4j.LoggerFactory; |
39 | 39 | ||
... | @@ -46,7 +46,6 @@ import java.io.InputStream; | ... | @@ -46,7 +46,6 @@ import java.io.InputStream; |
46 | import java.net.URI; | 46 | import java.net.URI; |
47 | import java.nio.charset.Charset; | 47 | import java.nio.charset.Charset; |
48 | import java.nio.file.NoSuchFileException; | 48 | import java.nio.file.NoSuchFileException; |
49 | -import java.util.ArrayList; | ||
50 | import java.util.List; | 49 | import java.util.List; |
51 | import java.util.Locale; | 50 | import java.util.Locale; |
52 | import java.util.Set; | 51 | import java.util.Set; |
... | @@ -79,6 +78,7 @@ public class ApplicationArchive | ... | @@ -79,6 +78,7 @@ public class ApplicationArchive |
79 | private static final String VERSION = "[@version]"; | 78 | private static final String VERSION = "[@version]"; |
80 | private static final String FEATURES_REPO = "[@featuresRepo]"; | 79 | private static final String FEATURES_REPO = "[@featuresRepo]"; |
81 | private static final String FEATURES = "[@features]"; | 80 | private static final String FEATURES = "[@features]"; |
81 | + private static final String APPS = "[@apps]"; | ||
82 | private static final String DESCRIPTION = "description"; | 82 | private static final String DESCRIPTION = "description"; |
83 | 83 | ||
84 | private static final String ROLE = "security.role"; | 84 | private static final String ROLE = "security.role"; |
... | @@ -291,8 +291,13 @@ public class ApplicationArchive | ... | @@ -291,8 +291,13 @@ public class ApplicationArchive |
291 | URI featuresRepo = featRepo != null ? URI.create(featRepo) : null; | 291 | URI featuresRepo = featRepo != null ? URI.create(featRepo) : null; |
292 | List<String> features = ImmutableList.copyOf(cfg.getString(FEATURES).split(",")); | 292 | List<String> features = ImmutableList.copyOf(cfg.getString(FEATURES).split(",")); |
293 | 293 | ||
294 | + String apps = cfg.getString(APPS, ""); | ||
295 | + List<String> requiredApps = apps.isEmpty() ? | ||
296 | + ImmutableList.of() : ImmutableList.copyOf(apps.split(",")); | ||
297 | + | ||
294 | return new DefaultApplicationDescription(name, version, desc, origin, role, | 298 | return new DefaultApplicationDescription(name, version, desc, origin, role, |
295 | - perms, featuresRepo, features); | 299 | + perms, featuresRepo, features, |
300 | + requiredApps); | ||
296 | } | 301 | } |
297 | 302 | ||
298 | // Expands the specified ZIP stream into app-specific directory. | 303 | // Expands the specified ZIP stream into app-specific directory. |
... | @@ -390,7 +395,7 @@ public class ApplicationArchive | ... | @@ -390,7 +395,7 @@ public class ApplicationArchive |
390 | 395 | ||
391 | // Returns the set of Permissions specified in the app.xml file | 396 | // Returns the set of Permissions specified in the app.xml file |
392 | private ImmutableSet<Permission> getPermissions(XMLConfiguration cfg) { | 397 | private ImmutableSet<Permission> getPermissions(XMLConfiguration cfg) { |
393 | - List<Permission> permissionList = new ArrayList(); | 398 | + List<Permission> permissionList = Lists.newArrayList(); |
394 | 399 | ||
395 | for (Object o : cfg.getList(APP_PERMISSIONS)) { | 400 | for (Object o : cfg.getList(APP_PERMISSIONS)) { |
396 | String name = (String) o; | 401 | String name = (String) o; | ... | ... |
... | @@ -75,7 +75,8 @@ public class SimpleApplicationStore extends ApplicationArchive implements Applic | ... | @@ -75,7 +75,8 @@ public class SimpleApplicationStore extends ApplicationArchive implements Applic |
75 | new DefaultApplication(appId, appDesc.version(), | 75 | new DefaultApplication(appId, appDesc.version(), |
76 | appDesc.description(), appDesc.origin(), | 76 | appDesc.description(), appDesc.origin(), |
77 | appDesc.role(), appDesc.permissions(), | 77 | appDesc.role(), appDesc.permissions(), |
78 | - appDesc.featuresRepo(), appDesc.features()); | 78 | + appDesc.featuresRepo(), appDesc.features(), |
79 | + appDesc.requiredApps()); | ||
79 | apps.put(appId, app); | 80 | apps.put(appId, app); |
80 | states.put(appId, isActive(name) ? INSTALLED : ACTIVE); | 81 | states.put(appId, isActive(name) ? INSTALLED : ACTIVE); |
81 | // load app permissions | 82 | // load app permissions |
... | @@ -117,7 +118,8 @@ public class SimpleApplicationStore extends ApplicationArchive implements Applic | ... | @@ -117,7 +118,8 @@ public class SimpleApplicationStore extends ApplicationArchive implements Applic |
117 | DefaultApplication app = | 118 | DefaultApplication app = |
118 | new DefaultApplication(appId, appDesc.version(), appDesc.description(), | 119 | new DefaultApplication(appId, appDesc.version(), appDesc.description(), |
119 | appDesc.origin(), appDesc.role(), appDesc.permissions(), | 120 | appDesc.origin(), appDesc.role(), appDesc.permissions(), |
120 | - appDesc.featuresRepo(), appDesc.features()); | 121 | + appDesc.featuresRepo(), appDesc.features(), |
122 | + appDesc.requiredApps()); | ||
121 | apps.put(appId, app); | 123 | apps.put(appId, app); |
122 | states.put(appId, INSTALLED); | 124 | states.put(appId, INSTALLED); |
123 | delegate.notify(new ApplicationEvent(APP_INSTALLED, app)); | 125 | delegate.notify(new ApplicationEvent(APP_INSTALLED, app)); | ... | ... |
... | @@ -212,6 +212,7 @@ public class ApplicationManager | ... | @@ -212,6 +212,7 @@ public class ApplicationManager |
212 | // The following methods are fully synchronized to guard against remote vs. | 212 | // The following methods are fully synchronized to guard against remote vs. |
213 | // locally induced feature service interactions. | 213 | // locally induced feature service interactions. |
214 | 214 | ||
215 | + // Installs all feature repositories required by the specified app. | ||
215 | private synchronized boolean installAppArtifacts(Application app) throws Exception { | 216 | private synchronized boolean installAppArtifacts(Application app) throws Exception { |
216 | if (app.featuresRepo().isPresent() && | 217 | if (app.featuresRepo().isPresent() && |
217 | featuresService.getRepository(app.featuresRepo().get()) == null) { | 218 | featuresService.getRepository(app.featuresRepo().get()) == null) { |
... | @@ -221,6 +222,7 @@ public class ApplicationManager | ... | @@ -221,6 +222,7 @@ public class ApplicationManager |
221 | return false; | 222 | return false; |
222 | } | 223 | } |
223 | 224 | ||
225 | + // Uninstalls all the feature repositories required by the specified app. | ||
224 | private synchronized boolean uninstallAppArtifacts(Application app) throws Exception { | 226 | private synchronized boolean uninstallAppArtifacts(Application app) throws Exception { |
225 | if (app.featuresRepo().isPresent() && | 227 | if (app.featuresRepo().isPresent() && |
226 | featuresService.getRepository(app.featuresRepo().get()) != null) { | 228 | featuresService.getRepository(app.featuresRepo().get()) != null) { |
... | @@ -230,6 +232,7 @@ public class ApplicationManager | ... | @@ -230,6 +232,7 @@ public class ApplicationManager |
230 | return false; | 232 | return false; |
231 | } | 233 | } |
232 | 234 | ||
235 | + // Installs all features that define the specified app. | ||
233 | private synchronized boolean installAppFeatures(Application app) throws Exception { | 236 | private synchronized boolean installAppFeatures(Application app) throws Exception { |
234 | boolean changed = false; | 237 | boolean changed = false; |
235 | for (String name : app.features()) { | 238 | for (String name : app.features()) { |
... | @@ -246,6 +249,7 @@ public class ApplicationManager | ... | @@ -246,6 +249,7 @@ public class ApplicationManager |
246 | return changed; | 249 | return changed; |
247 | } | 250 | } |
248 | 251 | ||
252 | + // Uninstalls all features that define the specified app. | ||
249 | private synchronized boolean uninstallAppFeatures(Application app) throws Exception { | 253 | private synchronized boolean uninstallAppFeatures(Application app) throws Exception { |
250 | boolean changed = false; | 254 | boolean changed = false; |
251 | invokeHook(deactivateHooks.get(app.id().name()), app.id()); | 255 | invokeHook(deactivateHooks.get(app.id().name()), app.id()); | ... | ... |
... | @@ -15,6 +15,7 @@ | ... | @@ -15,6 +15,7 @@ |
15 | */ | 15 | */ |
16 | package org.onosproject.app.impl; | 16 | package org.onosproject.app.impl; |
17 | 17 | ||
18 | +import com.google.common.collect.ImmutableList; | ||
18 | import com.google.common.collect.ImmutableSet; | 19 | import com.google.common.collect.ImmutableSet; |
19 | import org.junit.After; | 20 | import org.junit.After; |
20 | import org.junit.Before; | 21 | import org.junit.Before; |
... | @@ -138,7 +139,7 @@ public class ApplicationManagerTest { | ... | @@ -138,7 +139,7 @@ public class ApplicationManagerTest { |
138 | @Override | 139 | @Override |
139 | public Application create(InputStream appDescStream) { | 140 | public Application create(InputStream appDescStream) { |
140 | app = new DefaultApplication(APP_ID, VER, DESC, ORIGIN, ROLE, PERMS, | 141 | app = new DefaultApplication(APP_ID, VER, DESC, ORIGIN, ROLE, PERMS, |
141 | - Optional.of(FURL), FEATURES); | 142 | + Optional.of(FURL), FEATURES, ImmutableList.of()); |
142 | state = INSTALLED; | 143 | state = INSTALLED; |
143 | delegate.notify(new ApplicationEvent(APP_INSTALLED, app)); | 144 | delegate.notify(new ApplicationEvent(APP_INSTALLED, app)); |
144 | return app; | 145 | return app; |
... | @@ -177,6 +178,11 @@ public class ApplicationManagerTest { | ... | @@ -177,6 +178,11 @@ public class ApplicationManagerTest { |
177 | state = INSTALLED; | 178 | state = INSTALLED; |
178 | delegate.notify(new ApplicationEvent(APP_DEACTIVATED, app)); | 179 | delegate.notify(new ApplicationEvent(APP_DEACTIVATED, app)); |
179 | } | 180 | } |
181 | + | ||
182 | + @Override | ||
183 | + public ApplicationId getId(String name) { | ||
184 | + return new DefaultApplicationId(0, name); | ||
185 | + } | ||
180 | } | 186 | } |
181 | 187 | ||
182 | private class TestFeaturesService extends FeaturesServiceAdapter { | 188 | private class TestFeaturesService extends FeaturesServiceAdapter { | ... | ... |
... | @@ -17,7 +17,9 @@ package org.onosproject.store.app; | ... | @@ -17,7 +17,9 @@ package org.onosproject.store.app; |
17 | 17 | ||
18 | import com.google.common.base.Charsets; | 18 | import com.google.common.base.Charsets; |
19 | import com.google.common.collect.ImmutableSet; | 19 | import com.google.common.collect.ImmutableSet; |
20 | - | 20 | +import com.google.common.collect.Maps; |
21 | +import com.google.common.collect.Multimap; | ||
22 | +import com.google.common.collect.Sets; | ||
21 | import org.apache.felix.scr.annotations.Activate; | 23 | import org.apache.felix.scr.annotations.Activate; |
22 | import org.apache.felix.scr.annotations.Component; | 24 | import org.apache.felix.scr.annotations.Component; |
23 | import org.apache.felix.scr.annotations.Deactivate; | 25 | import org.apache.felix.scr.annotations.Deactivate; |
... | @@ -37,6 +39,7 @@ import org.onosproject.common.app.ApplicationArchive; | ... | @@ -37,6 +39,7 @@ import org.onosproject.common.app.ApplicationArchive; |
37 | import org.onosproject.core.Application; | 39 | import org.onosproject.core.Application; |
38 | import org.onosproject.core.ApplicationId; | 40 | import org.onosproject.core.ApplicationId; |
39 | import org.onosproject.core.ApplicationIdStore; | 41 | import org.onosproject.core.ApplicationIdStore; |
42 | +import org.onosproject.core.CoreService; | ||
40 | import org.onosproject.core.DefaultApplication; | 43 | import org.onosproject.core.DefaultApplication; |
41 | import org.onosproject.security.Permission; | 44 | import org.onosproject.security.Permission; |
42 | import org.onosproject.store.cluster.messaging.ClusterCommunicationService; | 45 | import org.onosproject.store.cluster.messaging.ClusterCommunicationService; |
... | @@ -61,6 +64,8 @@ import java.util.concurrent.Executors; | ... | @@ -61,6 +64,8 @@ import java.util.concurrent.Executors; |
61 | import java.util.concurrent.ScheduledExecutorService; | 64 | import java.util.concurrent.ScheduledExecutorService; |
62 | import java.util.function.Function; | 65 | import java.util.function.Function; |
63 | 66 | ||
67 | +import static com.google.common.collect.Multimaps.newSetMultimap; | ||
68 | +import static com.google.common.collect.Multimaps.synchronizedSetMultimap; | ||
64 | import static com.google.common.io.ByteStreams.toByteArray; | 69 | import static com.google.common.io.ByteStreams.toByteArray; |
65 | import static java.util.concurrent.TimeUnit.MILLISECONDS; | 70 | import static java.util.concurrent.TimeUnit.MILLISECONDS; |
66 | import static org.onlab.util.Tools.groupedThreads; | 71 | import static org.onlab.util.Tools.groupedThreads; |
... | @@ -115,6 +120,14 @@ public class GossipApplicationStore extends ApplicationArchive | ... | @@ -115,6 +120,14 @@ public class GossipApplicationStore extends ApplicationArchive |
115 | @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY) | 120 | @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY) |
116 | protected ApplicationIdStore idStore; | 121 | protected ApplicationIdStore idStore; |
117 | 122 | ||
123 | + // Multimap to track which apps are required by others apps | ||
124 | + // app -> { required-by, ... } | ||
125 | + // Apps explicitly activated will be required by the CORE app | ||
126 | + private final Multimap<ApplicationId, ApplicationId> requiredBy = | ||
127 | + synchronizedSetMultimap(newSetMultimap(Maps.newHashMap(), Sets::newHashSet)); | ||
128 | + | ||
129 | + private ApplicationId coreAppId; | ||
130 | + | ||
118 | @Activate | 131 | @Activate |
119 | public void activate() { | 132 | public void activate() { |
120 | KryoNamespace.Builder serializer = KryoNamespace.newBuilder() | 133 | KryoNamespace.Builder serializer = KryoNamespace.newBuilder() |
... | @@ -161,6 +174,7 @@ public class GossipApplicationStore extends ApplicationArchive | ... | @@ -161,6 +174,7 @@ public class GossipApplicationStore extends ApplicationArchive |
161 | .withTimestampProvider((k, v) -> clockService.getTimestamp()) | 174 | .withTimestampProvider((k, v) -> clockService.getTimestamp()) |
162 | .build(); | 175 | .build(); |
163 | 176 | ||
177 | + coreAppId = getId(CoreService.CORE_APP_NAME); | ||
164 | log.info("Started"); | 178 | log.info("Started"); |
165 | } | 179 | } |
166 | 180 | ||
... | @@ -174,6 +188,7 @@ public class GossipApplicationStore extends ApplicationArchive | ... | @@ -174,6 +188,7 @@ public class GossipApplicationStore extends ApplicationArchive |
174 | try { | 188 | try { |
175 | Application app = create(getApplicationDescription(name), false); | 189 | Application app = create(getApplicationDescription(name), false); |
176 | if (app != null && isActive(app.id().name())) { | 190 | if (app != null && isActive(app.id().name())) { |
191 | + requiredBy.put(app.id(), coreAppId); | ||
177 | activate(app.id(), false); | 192 | activate(app.id(), false); |
178 | // load app permissions | 193 | // load app permissions |
179 | } | 194 | } |
... | @@ -200,7 +215,6 @@ public class GossipApplicationStore extends ApplicationArchive | ... | @@ -200,7 +215,6 @@ public class GossipApplicationStore extends ApplicationArchive |
200 | public void setDelegate(ApplicationStoreDelegate delegate) { | 215 | public void setDelegate(ApplicationStoreDelegate delegate) { |
201 | super.setDelegate(delegate); | 216 | super.setDelegate(delegate); |
202 | loadFromDisk(); | 217 | loadFromDisk(); |
203 | -// executor.schedule(this::pruneUninstalledApps, LOAD_TIMEOUT_MS, MILLISECONDS); | ||
204 | } | 218 | } |
205 | 219 | ||
206 | @Override | 220 | @Override |
... | @@ -229,8 +243,16 @@ public class GossipApplicationStore extends ApplicationArchive | ... | @@ -229,8 +243,16 @@ public class GossipApplicationStore extends ApplicationArchive |
229 | @Override | 243 | @Override |
230 | public Application create(InputStream appDescStream) { | 244 | public Application create(InputStream appDescStream) { |
231 | ApplicationDescription appDesc = saveApplication(appDescStream); | 245 | ApplicationDescription appDesc = saveApplication(appDescStream); |
246 | + if (hasPrerequisites(appDesc)) { | ||
232 | return create(appDesc, true); | 247 | return create(appDesc, true); |
233 | } | 248 | } |
249 | + throw new ApplicationException("Missing dependencies for app " + appDesc.name()); | ||
250 | + } | ||
251 | + | ||
252 | + private boolean hasPrerequisites(ApplicationDescription app) { | ||
253 | + return !app.requiredApps().stream().map(n -> getId(n)) | ||
254 | + .anyMatch(id -> id == null || getApplication(id) == null); | ||
255 | + } | ||
234 | 256 | ||
235 | private Application create(ApplicationDescription appDesc, boolean updateTime) { | 257 | private Application create(ApplicationDescription appDesc, boolean updateTime) { |
236 | Application app = registerApp(appDesc); | 258 | Application app = registerApp(appDesc); |
... | @@ -246,35 +268,79 @@ public class GossipApplicationStore extends ApplicationArchive | ... | @@ -246,35 +268,79 @@ public class GossipApplicationStore extends ApplicationArchive |
246 | public void remove(ApplicationId appId) { | 268 | public void remove(ApplicationId appId) { |
247 | Application app = apps.get(appId); | 269 | Application app = apps.get(appId); |
248 | if (app != null) { | 270 | if (app != null) { |
271 | + uninstallDependentApps(app); | ||
249 | apps.remove(appId); | 272 | apps.remove(appId); |
250 | states.remove(app); | 273 | states.remove(app); |
251 | permissions.remove(app); | 274 | permissions.remove(app); |
252 | } | 275 | } |
253 | } | 276 | } |
254 | 277 | ||
278 | + // Uninstalls all apps that depend on the given app. | ||
279 | + private void uninstallDependentApps(Application app) { | ||
280 | + getApplications().stream() | ||
281 | + .filter(a -> a.requiredApps().contains(app.id().name())) | ||
282 | + .forEach(a -> remove(a.id())); | ||
283 | + } | ||
284 | + | ||
255 | @Override | 285 | @Override |
256 | public void activate(ApplicationId appId) { | 286 | public void activate(ApplicationId appId) { |
287 | + activate(appId, coreAppId); | ||
288 | + } | ||
289 | + | ||
290 | + private void activate(ApplicationId appId, ApplicationId forAppId) { | ||
291 | + requiredBy.put(appId, forAppId); | ||
257 | activate(appId, true); | 292 | activate(appId, true); |
258 | } | 293 | } |
259 | 294 | ||
295 | + | ||
260 | private void activate(ApplicationId appId, boolean updateTime) { | 296 | private void activate(ApplicationId appId, boolean updateTime) { |
261 | Application app = apps.get(appId); | 297 | Application app = apps.get(appId); |
262 | if (app != null) { | 298 | if (app != null) { |
263 | if (updateTime) { | 299 | if (updateTime) { |
264 | updateTime(appId.name()); | 300 | updateTime(appId.name()); |
265 | } | 301 | } |
302 | + activateRequiredApps(app); | ||
266 | states.put(app, ACTIVATED); | 303 | states.put(app, ACTIVATED); |
267 | } | 304 | } |
268 | } | 305 | } |
269 | 306 | ||
307 | + // Activates all apps required by this application. | ||
308 | + private void activateRequiredApps(Application app) { | ||
309 | + app.requiredApps().stream().map(this::getId).forEach(id -> activate(id, app.id())); | ||
310 | + } | ||
311 | + | ||
270 | @Override | 312 | @Override |
271 | public void deactivate(ApplicationId appId) { | 313 | public void deactivate(ApplicationId appId) { |
314 | + deactivateDependentApps(getApplication(appId)); | ||
315 | + deactivate(appId, coreAppId); | ||
316 | + } | ||
317 | + | ||
318 | + private void deactivate(ApplicationId appId, ApplicationId forAppId) { | ||
319 | + requiredBy.remove(appId, forAppId); | ||
320 | + if (requiredBy.get(appId).isEmpty()) { | ||
272 | Application app = apps.get(appId); | 321 | Application app = apps.get(appId); |
273 | if (app != null) { | 322 | if (app != null) { |
274 | updateTime(appId.name()); | 323 | updateTime(appId.name()); |
275 | states.put(app, DEACTIVATED); | 324 | states.put(app, DEACTIVATED); |
325 | + deactivateRequiredApps(app); | ||
276 | } | 326 | } |
277 | } | 327 | } |
328 | + } | ||
329 | + | ||
330 | + // Deactivates all apps that require this application. | ||
331 | + private void deactivateDependentApps(Application app) { | ||
332 | + getApplications().stream() | ||
333 | + .filter(a -> states.get(a) == ACTIVATED) | ||
334 | + .filter(a -> a.requiredApps().contains(app.id().name())) | ||
335 | + .forEach(a -> deactivate(a.id())); | ||
336 | + } | ||
337 | + | ||
338 | + // Deactivates all apps required by this application. | ||
339 | + private void deactivateRequiredApps(Application app) { | ||
340 | + app.requiredApps().stream().map(this::getId).map(this::getApplication) | ||
341 | + .filter(a -> states.get(a) == ACTIVATED) | ||
342 | + .forEach(a -> deactivate(a.id(), app.id())); | ||
343 | + } | ||
278 | 344 | ||
279 | @Override | 345 | @Override |
280 | public Set<Permission> getPermissions(ApplicationId appId) { | 346 | public Set<Permission> getPermissions(ApplicationId appId) { |
... | @@ -424,6 +490,7 @@ public class GossipApplicationStore extends ApplicationArchive | ... | @@ -424,6 +490,7 @@ public class GossipApplicationStore extends ApplicationArchive |
424 | ApplicationId appId = idStore.registerApplication(appDesc.name()); | 490 | ApplicationId appId = idStore.registerApplication(appDesc.name()); |
425 | return new DefaultApplication(appId, appDesc.version(), appDesc.description(), | 491 | return new DefaultApplication(appId, appDesc.version(), appDesc.description(), |
426 | appDesc.origin(), appDesc.role(), appDesc.permissions(), | 492 | appDesc.origin(), appDesc.role(), appDesc.permissions(), |
427 | - appDesc.featuresRepo(), appDesc.features()); | 493 | + appDesc.featuresRepo(), appDesc.features(), |
494 | + appDesc.requiredApps()); | ||
428 | } | 495 | } |
429 | } | 496 | } | ... | ... |
... | @@ -62,6 +62,7 @@ public class OnosAppMojo extends AbstractMojo { | ... | @@ -62,6 +62,7 @@ public class OnosAppMojo extends AbstractMojo { |
62 | 62 | ||
63 | private static final String ONOS_APP_NAME = "onos.app.name"; | 63 | private static final String ONOS_APP_NAME = "onos.app.name"; |
64 | private static final String ONOS_APP_ORIGIN = "onos.app.origin"; | 64 | private static final String ONOS_APP_ORIGIN = "onos.app.origin"; |
65 | + private static final String ONOS_APP_REQUIRES = "onos.app.requires"; | ||
65 | 66 | ||
66 | private static final String JAR = "jar"; | 67 | private static final String JAR = "jar"; |
67 | private static final String XML = "xml"; | 68 | private static final String XML = "xml"; |
... | @@ -80,6 +81,7 @@ public class OnosAppMojo extends AbstractMojo { | ... | @@ -80,6 +81,7 @@ public class OnosAppMojo extends AbstractMojo { |
80 | 81 | ||
81 | private String name; | 82 | private String name; |
82 | private String origin; | 83 | private String origin; |
84 | + private String requiredApps; | ||
83 | private String version = DEFAULT_VERSION; | 85 | private String version = DEFAULT_VERSION; |
84 | private String featuresRepo = DEFAULT_FEATURES_REPO; | 86 | private String featuresRepo = DEFAULT_FEATURES_REPO; |
85 | private List<String> artifacts; | 87 | private List<String> artifacts; |
... | @@ -160,6 +162,9 @@ public class OnosAppMojo extends AbstractMojo { | ... | @@ -160,6 +162,9 @@ public class OnosAppMojo extends AbstractMojo { |
160 | origin = (String) project.getProperties().get(ONOS_APP_ORIGIN); | 162 | origin = (String) project.getProperties().get(ONOS_APP_ORIGIN); |
161 | origin = origin != null ? origin : DEFAULT_ORIGIN; | 163 | origin = origin != null ? origin : DEFAULT_ORIGIN; |
162 | 164 | ||
165 | + requiredApps = (String) project.getProperties().get(ONOS_APP_REQUIRES); | ||
166 | + requiredApps = requiredApps == null ? "" : requiredApps; | ||
167 | + | ||
163 | if (appFile.exists()) { | 168 | if (appFile.exists()) { |
164 | loadAppFile(appFile); | 169 | loadAppFile(appFile); |
165 | } else { | 170 | } else { |
... | @@ -338,6 +343,7 @@ public class OnosAppMojo extends AbstractMojo { | ... | @@ -338,6 +343,7 @@ public class OnosAppMojo extends AbstractMojo { |
338 | return string == null ? null : | 343 | return string == null ? null : |
339 | string.replaceAll("\\$\\{onos.app.name\\}", name) | 344 | string.replaceAll("\\$\\{onos.app.name\\}", name) |
340 | .replaceAll("\\$\\{onos.app.origin\\}", origin) | 345 | .replaceAll("\\$\\{onos.app.origin\\}", origin) |
346 | + .replaceAll("\\$\\{onos.app.requires\\}", requiredApps) | ||
341 | .replaceAll("\\$\\{project.groupId\\}", projectGroupId) | 347 | .replaceAll("\\$\\{project.groupId\\}", projectGroupId) |
342 | .replaceAll("\\$\\{project.artifactId\\}", projectArtifactId) | 348 | .replaceAll("\\$\\{project.artifactId\\}", projectArtifactId) |
343 | .replaceAll("\\$\\{project.version\\}", projectVersion) | 349 | .replaceAll("\\$\\{project.version\\}", projectVersion) | ... | ... |
... | @@ -16,7 +16,7 @@ | ... | @@ -16,7 +16,7 @@ |
16 | --> | 16 | --> |
17 | <app name="${onos.app.name}" origin="${onos.app.origin}" version="${project.version}" | 17 | <app name="${onos.app.name}" origin="${onos.app.origin}" version="${project.version}" |
18 | featuresRepo="mvn:${project.groupId}/${project.artifactId}/${project.version}/xml/features" | 18 | featuresRepo="mvn:${project.groupId}/${project.artifactId}/${project.version}/xml/features" |
19 | - features="${project.artifactId}"> | 19 | + features="${project.artifactId}" apps="${onos.app.requires}"> |
20 | <description>${project.description}</description> | 20 | <description>${project.description}</description> |
21 | <artifact>mvn:${project.groupId}/${project.artifactId}/${project.version}</artifact> | 21 | <artifact>mvn:${project.groupId}/${project.artifactId}/${project.version}</artifact> |
22 | </app> | 22 | </app> | ... | ... |
... | @@ -85,19 +85,19 @@ public class ApplicationsResourceTest extends ResourceTest { | ... | @@ -85,19 +85,19 @@ public class ApplicationsResourceTest extends ResourceTest { |
85 | private Application app1 = | 85 | private Application app1 = |
86 | new DefaultApplication(id1, VER, | 86 | new DefaultApplication(id1, VER, |
87 | "app1", "origin1", ApplicationRole.ADMIN, ImmutableSet.of(), Optional.of(FURL), | 87 | "app1", "origin1", ApplicationRole.ADMIN, ImmutableSet.of(), Optional.of(FURL), |
88 | - ImmutableList.of("My Feature")); | 88 | + ImmutableList.of("My Feature"), ImmutableList.of()); |
89 | private Application app2 = | 89 | private Application app2 = |
90 | new DefaultApplication(id2, VER, | 90 | new DefaultApplication(id2, VER, |
91 | "app2", "origin2", ApplicationRole.ADMIN, ImmutableSet.of(), Optional.of(FURL), | 91 | "app2", "origin2", ApplicationRole.ADMIN, ImmutableSet.of(), Optional.of(FURL), |
92 | - ImmutableList.of("My Feature")); | 92 | + ImmutableList.of("My Feature"), ImmutableList.of()); |
93 | private Application app3 = | 93 | private Application app3 = |
94 | new DefaultApplication(id3, VER, | 94 | new DefaultApplication(id3, VER, |
95 | "app3", "origin3", ApplicationRole.ADMIN, ImmutableSet.of(), Optional.of(FURL), | 95 | "app3", "origin3", ApplicationRole.ADMIN, ImmutableSet.of(), Optional.of(FURL), |
96 | - ImmutableList.of("My Feature")); | 96 | + ImmutableList.of("My Feature"), ImmutableList.of()); |
97 | private Application app4 = | 97 | private Application app4 = |
98 | new DefaultApplication(id4, VER, | 98 | new DefaultApplication(id4, VER, |
99 | "app4", "origin4", ApplicationRole.ADMIN, ImmutableSet.of(), Optional.of(FURL), | 99 | "app4", "origin4", ApplicationRole.ADMIN, ImmutableSet.of(), Optional.of(FURL), |
100 | - ImmutableList.of("My Feature")); | 100 | + ImmutableList.of("My Feature"), ImmutableList.of()); |
101 | 101 | ||
102 | /** | 102 | /** |
103 | * Hamcrest matcher to check that an application representation in JSON matches | 103 | * Hamcrest matcher to check that an application representation in JSON matches | ... | ... |
-
Please register or login to post a comment