Jian Li
Committed by Gerrit Code Review

[ONOS-3635] Implement List view for extended application properties

Change-Id: Ie8f985f9c2986857df92bcb47b5bdee876f37230
...@@ -39,10 +39,8 @@ import org.slf4j.Logger; ...@@ -39,10 +39,8 @@ import org.slf4j.Logger;
39 import org.slf4j.LoggerFactory; 39 import org.slf4j.LoggerFactory;
40 40
41 import javax.imageio.ImageIO; 41 import javax.imageio.ImageIO;
42 -import java.awt.image.BufferedImage;
43 -import java.awt.image.DataBufferByte;
44 -import java.awt.image.WritableRaster;
45 import java.io.ByteArrayInputStream; 42 import java.io.ByteArrayInputStream;
43 +import java.io.ByteArrayOutputStream;
46 import java.io.File; 44 import java.io.File;
47 import java.io.FileInputStream; 45 import java.io.FileInputStream;
48 import java.io.FileNotFoundException; 46 import java.io.FileNotFoundException;
...@@ -97,8 +95,9 @@ public class ApplicationArchive ...@@ -97,8 +95,9 @@ public class ApplicationArchive
97 private static final String JAVA_PERMISSIONS = "security.permissions.java-perm"; 95 private static final String JAVA_PERMISSIONS = "security.permissions.java-perm";
98 96
99 private static final String OAR = ".oar"; 97 private static final String OAR = ".oar";
98 + private static final String PNG = "png";
100 private static final String APP_XML = "app.xml"; 99 private static final String APP_XML = "app.xml";
101 - private static final String ICON_PNG = "icon.png"; 100 + private static final String APP_PNG = "app.png";
102 private static final String M2_PREFIX = "m2"; 101 private static final String M2_PREFIX = "m2";
103 102
104 private static final String ROOT = "../"; 103 private static final String ROOT = "../";
...@@ -412,6 +411,11 @@ public class ApplicationArchive ...@@ -412,6 +411,11 @@ public class ApplicationArchive
412 return new File(new File(appsDir, appName), fileName); 411 return new File(new File(appsDir, appName), fileName);
413 } 412 }
414 413
414 + // Returns the icon file located under the specified app directory.
415 + private File iconFile(String appName, String fileName) {
416 + return new File(new File(appsDir, appName), fileName);
417 + }
418 +
415 // Returns the set of Permissions specified in the app.xml file 419 // Returns the set of Permissions specified in the app.xml file
416 private ImmutableSet<Permission> getPermissions(XMLConfiguration cfg) { 420 private ImmutableSet<Permission> getPermissions(XMLConfiguration cfg) {
417 List<Permission> permissionList = Lists.newArrayList(); 421 List<Permission> permissionList = Lists.newArrayList();
...@@ -441,29 +445,25 @@ public class ApplicationArchive ...@@ -441,29 +445,25 @@ public class ApplicationArchive
441 445
442 // Returns the byte stream from icon.png file in oar application archive. 446 // Returns the byte stream from icon.png file in oar application archive.
443 private byte[] getApplicationIcon(String appName) { 447 private byte[] getApplicationIcon(String appName) {
444 - // open image
445 - File iconFile = appFile(appName, ICON_PNG);
446 448
447 - if (!iconFile.exists()) { 449 + byte[] icon = new byte[0];
448 - iconFile = new File(appsDir, ICON_PNG); 450 + File iconFile = iconFile(appName, APP_PNG);
449 - }
450 451
451 if (!iconFile.exists()) { 452 if (!iconFile.exists()) {
452 - return null; 453 + // assume that we can always fallback to default icon
454 + iconFile = new File(appsDir, APP_PNG);
453 } 455 }
454 456
455 - BufferedImage bufferedImage = null;
456 try { 457 try {
457 - bufferedImage = ImageIO.read(iconFile); 458 + ByteArrayOutputStream bos = new ByteArrayOutputStream();
459 + ImageIO.write(ImageIO.read(iconFile), PNG, bos);
460 + icon = bos.toByteArray();
461 + bos.close();
458 } catch (IOException e) { 462 } catch (IOException e) {
459 e.printStackTrace(); 463 e.printStackTrace();
460 } 464 }
461 465
462 - // get DataBufferBytes from Raster 466 + return icon;
463 - WritableRaster raster = bufferedImage .getRaster();
464 - DataBufferByte data = (DataBufferByte) raster.getDataBuffer();
465 -
466 - return data.getData();
467 } 467 }
468 468
469 // Returns application role type 469 // Returns application role type
......
...@@ -18,6 +18,7 @@ package org.onosproject.maven; ...@@ -18,6 +18,7 @@ package org.onosproject.maven;
18 import com.google.common.collect.ImmutableList; 18 import com.google.common.collect.ImmutableList;
19 import org.apache.commons.configuration.ConfigurationException; 19 import org.apache.commons.configuration.ConfigurationException;
20 import org.apache.commons.configuration.XMLConfiguration; 20 import org.apache.commons.configuration.XMLConfiguration;
21 +import org.apache.commons.io.FileUtils;
21 import org.apache.commons.lang.StringUtils; 22 import org.apache.commons.lang.StringUtils;
22 import org.apache.maven.artifact.repository.ArtifactRepository; 23 import org.apache.maven.artifact.repository.ArtifactRepository;
23 import org.apache.maven.plugin.AbstractMojo; 24 import org.apache.maven.plugin.AbstractMojo;
...@@ -61,7 +62,7 @@ public class OnosAppMojo extends AbstractMojo { ...@@ -61,7 +62,7 @@ public class OnosAppMojo extends AbstractMojo {
61 private static final String ARTIFACT = "artifact"; 62 private static final String ARTIFACT = "artifact";
62 63
63 private static final String APP_XML = "app.xml"; 64 private static final String APP_XML = "app.xml";
64 - private static final String ICON_PNG = "icon.png"; 65 + private static final String APP_PNG = "app.png";
65 private static final String FEATURES_XML = "features.xml"; 66 private static final String FEATURES_XML = "features.xml";
66 67
67 private static final String MVN_URL = "mvn:"; 68 private static final String MVN_URL = "mvn:";
...@@ -83,7 +84,7 @@ public class OnosAppMojo extends AbstractMojo { ...@@ -83,7 +84,7 @@ public class OnosAppMojo extends AbstractMojo {
83 private static final String DEFAULT_ORIGIN = "ON.Lab"; 84 private static final String DEFAULT_ORIGIN = "ON.Lab";
84 private static final String DEFAULT_VERSION = "${project.version}"; 85 private static final String DEFAULT_VERSION = "${project.version}";
85 86
86 - private static final String DEFAULT_CATEGORY = "Default"; 87 + private static final String DEFAULT_CATEGORY = "default";
87 private static final String DEFAULT_URL = "http://onosproject.org"; 88 private static final String DEFAULT_URL = "http://onosproject.org";
88 89
89 private static final String DEFAULT_FEATURES_REPO = 90 private static final String DEFAULT_FEATURES_REPO =
...@@ -161,6 +162,7 @@ public class OnosAppMojo extends AbstractMojo { ...@@ -161,6 +162,7 @@ public class OnosAppMojo extends AbstractMojo {
161 @Override 162 @Override
162 public void execute() throws MojoExecutionException { 163 public void execute() throws MojoExecutionException {
163 File appFile = new File(baseDir, APP_XML); 164 File appFile = new File(baseDir, APP_XML);
165 + File iconFile = new File(baseDir, APP_PNG);
164 File featuresFile = new File(baseDir, FEATURES_XML); 166 File featuresFile = new File(baseDir, FEATURES_XML);
165 167
166 name = (String) project.getProperties().get(ONOS_APP_NAME); 168 name = (String) project.getProperties().get(ONOS_APP_NAME);
...@@ -204,6 +206,7 @@ public class OnosAppMojo extends AbstractMojo { ...@@ -204,6 +206,7 @@ public class OnosAppMojo extends AbstractMojo {
204 206
205 if (stageDirectory.exists() || stageDirectory.mkdirs()) { 207 if (stageDirectory.exists() || stageDirectory.mkdirs()) {
206 processAppXml(appFile); 208 processAppXml(appFile);
209 + processAppPng(iconFile);
207 processFeaturesXml(featuresFile); 210 processFeaturesXml(featuresFile);
208 processArtifacts(); 211 processArtifacts();
209 generateAppPackage(); 212 generateAppPackage();
...@@ -259,6 +262,19 @@ public class OnosAppMojo extends AbstractMojo { ...@@ -259,6 +262,19 @@ public class OnosAppMojo extends AbstractMojo {
259 } 262 }
260 } 263 }
261 264
265 + // Stages the app.png file of a specific application.
266 + private void processAppPng(File iconFile) throws MojoExecutionException {
267 + try {
268 + File stagedIconFile = new File(stageDirectory, APP_PNG);
269 +
270 + if (iconFile.exists()) {
271 + FileUtils.copyFile(iconFile, stagedIconFile);
272 + }
273 + } catch (IOException e) {
274 + throw new MojoExecutionException("Unable to copy app.png", e);
275 + }
276 + }
277 +
262 private void processFeaturesXml(File featuresFile) throws MojoExecutionException { 278 private void processFeaturesXml(File featuresFile) throws MojoExecutionException {
263 boolean specified = featuresRepo != null && featuresRepo.length() > 0; 279 boolean specified = featuresRepo != null && featuresRepo.length() > 0;
264 280
......
...@@ -23,7 +23,10 @@ find $M2_REPO/org/onosproject/ -name "*.oar" -path "*/${ONOS_POM_VERSION}/*" | w ...@@ -23,7 +23,10 @@ find $M2_REPO/org/onosproject/ -name "*.oar" -path "*/${ONOS_POM_VERSION}/*" | w
23 name=$(grep "name=" $AUX/app.xml | sed 's/<app name="//g;s/".*//g') 23 name=$(grep "name=" $AUX/app.xml | sed 's/<app name="//g;s/".*//g')
24 mkdir -p $APPS/$name 24 mkdir -p $APPS/$name
25 cp $AUX/app.xml $APPS/$name/app.xml 25 cp $AUX/app.xml $APPS/$name/app.xml
26 + [ -f $AUX/app.png ] && cp $AUX/app.png $APPS/$name/app.png
26 cp $AUX/*.oar $APPS/$name/$name.oar 27 cp $AUX/*.oar $APPS/$name/$name.oar
27 cp -rf $AUX/m2/* $KARAF_M2 28 cp -rf $AUX/m2/* $KARAF_M2
28 rm -fr $AUX 29 rm -fr $AUX
29 done 30 done
31 +
32 +cp $ONOS_ROOT/apps/app.png $APPS/app.png
......
...@@ -18,10 +18,15 @@ package org.onosproject.ui.impl; ...@@ -18,10 +18,15 @@ package org.onosproject.ui.impl;
18 import com.sun.jersey.multipart.FormDataParam; 18 import com.sun.jersey.multipart.FormDataParam;
19 import org.onlab.rest.BaseResource; 19 import org.onlab.rest.BaseResource;
20 import org.onosproject.app.ApplicationAdminService; 20 import org.onosproject.app.ApplicationAdminService;
21 +import org.onosproject.core.Application;
22 +import org.onosproject.core.ApplicationId;
21 23
22 import javax.ws.rs.Consumes; 24 import javax.ws.rs.Consumes;
25 +import javax.ws.rs.GET;
23 import javax.ws.rs.POST; 26 import javax.ws.rs.POST;
24 import javax.ws.rs.Path; 27 import javax.ws.rs.Path;
28 +import javax.ws.rs.PathParam;
29 +import javax.ws.rs.Produces;
25 import javax.ws.rs.core.MediaType; 30 import javax.ws.rs.core.MediaType;
26 import javax.ws.rs.core.Response; 31 import javax.ws.rs.core.Response;
27 import java.io.IOException; 32 import java.io.IOException;
...@@ -41,4 +46,13 @@ public class ApplicationResource extends BaseResource { ...@@ -41,4 +46,13 @@ public class ApplicationResource extends BaseResource {
41 return Response.ok().build(); 46 return Response.ok().build();
42 } 47 }
43 48
49 + @Path("{name}/icon")
50 + @GET
51 + @Produces("image/png")
52 + public Response getIcon(@PathParam("name") String name) throws IOException {
53 + ApplicationAdminService service = get(ApplicationAdminService.class);
54 + ApplicationId appId = service.getId(name);
55 + Application app = service.getApplication(appId);
56 + return Response.ok(app.icon()).build();
57 + }
44 } 58 }
......
...@@ -45,15 +45,18 @@ public class ApplicationViewMessageHandler extends UiMessageHandler { ...@@ -45,15 +45,18 @@ public class ApplicationViewMessageHandler extends UiMessageHandler {
45 private static final String STATE = "state"; 45 private static final String STATE = "state";
46 private static final String STATE_IID = "_iconid_state"; 46 private static final String STATE_IID = "_iconid_state";
47 private static final String ID = "id"; 47 private static final String ID = "id";
48 + private static final String ICON = "icon";
48 private static final String VERSION = "version"; 49 private static final String VERSION = "version";
50 + private static final String CATEGORY = "category";
49 private static final String ORIGIN = "origin"; 51 private static final String ORIGIN = "origin";
50 private static final String DESC = "desc"; 52 private static final String DESC = "desc";
53 + private static final String URL = "url";
51 54
52 private static final String ICON_ID_ACTIVE = "active"; 55 private static final String ICON_ID_ACTIVE = "active";
53 private static final String ICON_ID_INACTIVE = "appInactive"; 56 private static final String ICON_ID_INACTIVE = "appInactive";
54 57
55 private static final String[] COL_IDS = { 58 private static final String[] COL_IDS = {
56 - STATE, STATE_IID, ID, VERSION, ORIGIN, DESC 59 + STATE, STATE_IID, ID, ICON, VERSION, CATEGORY, ORIGIN, DESC, URL
57 }; 60 };
58 61
59 @Override 62 @Override
...@@ -99,9 +102,12 @@ public class ApplicationViewMessageHandler extends UiMessageHandler { ...@@ -99,9 +102,12 @@ public class ApplicationViewMessageHandler extends UiMessageHandler {
99 row.cell(STATE, state) 102 row.cell(STATE, state)
100 .cell(STATE_IID, iconId) 103 .cell(STATE_IID, iconId)
101 .cell(ID, id.name()) 104 .cell(ID, id.name())
105 + .cell(ICON, id.name())
102 .cell(VERSION, app.version()) 106 .cell(VERSION, app.version())
107 + .cell(CATEGORY, app.category())
103 .cell(ORIGIN, app.origin()) 108 .cell(ORIGIN, app.origin())
104 - .cell(DESC, app.description()); 109 + .cell(DESC, app.description())
110 + .cell(URL, app.url());
105 } 111 }
106 } 112 }
107 113
......
...@@ -41,10 +41,13 @@ ...@@ -41,10 +41,13 @@
41 <table> 41 <table>
42 <tr> 42 <tr>
43 <td colId="state" class="table-icon" sortable></td> 43 <td colId="state" class="table-icon" sortable></td>
44 + <td colId="icon" col-width="36px">Icon </td>
44 <td colId="id" sortable>App ID </td> 45 <td colId="id" sortable>App ID </td>
45 <td colId="version" sortable>Version </td> 46 <td colId="version" sortable>Version </td>
47 + <td colId="category" sortable>Category </td>
46 <td colId="origin" sortable>Origin </td> 48 <td colId="origin" sortable>Origin </td>
47 <td colId="desc" col-width="475px">Description </td> 49 <td colId="desc" col-width="475px">Description </td>
50 + <td col-width="50px">URL </td>
48 </tr> 51 </tr>
49 </table> 52 </table>
50 </div> 53 </div>
...@@ -64,10 +67,13 @@ ...@@ -64,10 +67,13 @@
64 <td class="table-icon"> 67 <td class="table-icon">
65 <div icon icon-id="{{app._iconid_state}}"></div> 68 <div icon icon-id="{{app._iconid_state}}"></div>
66 </td> 69 </td>
70 + <td><img data-ng-src="./rs/applications/{{app.icon}}/icon" height="28px" width="28px" /></td>
67 <td>{{app.id}}</td> 71 <td>{{app.id}}</td>
68 <td>{{app.version}}</td> 72 <td>{{app.version}}</td>
73 + <td>{{app.category}}</td>
69 <td>{{app.origin}}</td> 74 <td>{{app.origin}}</td>
70 <td>{{app.desc}}</td> 75 <td>{{app.desc}}</td>
76 + <td><a href="{{app.url}}" target="_blank">LINK</a></td>
71 </tr> 77 </tr>
72 </table> 78 </table>
73 </div> 79 </div>
......