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;
import org.slf4j.LoggerFactory;
import javax.imageio.ImageIO;
import java.awt.image.BufferedImage;
import java.awt.image.DataBufferByte;
import java.awt.image.WritableRaster;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
......@@ -97,8 +95,9 @@ public class ApplicationArchive
private static final String JAVA_PERMISSIONS = "security.permissions.java-perm";
private static final String OAR = ".oar";
private static final String PNG = "png";
private static final String APP_XML = "app.xml";
private static final String ICON_PNG = "icon.png";
private static final String APP_PNG = "app.png";
private static final String M2_PREFIX = "m2";
private static final String ROOT = "../";
......@@ -197,7 +196,7 @@ public class ApplicationArchive
ApplicationDescription desc = plainXml ?
parsePlainAppDescription(bis) : parseZippedAppDescription(bis);
checkState(!appFile(desc.name(), APP_XML).exists(),
"Application %s already installed", desc.name());
"Application %s already installed", desc.name());
if (plainXml) {
expandPlainApplication(cache, desc);
......@@ -412,6 +411,11 @@ public class ApplicationArchive
return new File(new File(appsDir, appName), fileName);
}
// Returns the icon file located under the specified app directory.
private File iconFile(String appName, String fileName) {
return new File(new File(appsDir, appName), fileName);
}
// Returns the set of Permissions specified in the app.xml file
private ImmutableSet<Permission> getPermissions(XMLConfiguration cfg) {
List<Permission> permissionList = Lists.newArrayList();
......@@ -441,29 +445,25 @@ public class ApplicationArchive
// Returns the byte stream from icon.png file in oar application archive.
private byte[] getApplicationIcon(String appName) {
// open image
File iconFile = appFile(appName, ICON_PNG);
if (!iconFile.exists()) {
iconFile = new File(appsDir, ICON_PNG);
}
byte[] icon = new byte[0];
File iconFile = iconFile(appName, APP_PNG);
if (!iconFile.exists()) {
return null;
// assume that we can always fallback to default icon
iconFile = new File(appsDir, APP_PNG);
}
BufferedImage bufferedImage = null;
try {
bufferedImage = ImageIO.read(iconFile);
ByteArrayOutputStream bos = new ByteArrayOutputStream();
ImageIO.write(ImageIO.read(iconFile), PNG, bos);
icon = bos.toByteArray();
bos.close();
} catch (IOException e) {
e.printStackTrace();
}
// get DataBufferBytes from Raster
WritableRaster raster = bufferedImage .getRaster();
DataBufferByte data = (DataBufferByte) raster.getDataBuffer();
return data.getData();
return icon;
}
// Returns application role type
......
......@@ -18,6 +18,7 @@ package org.onosproject.maven;
import com.google.common.collect.ImmutableList;
import org.apache.commons.configuration.ConfigurationException;
import org.apache.commons.configuration.XMLConfiguration;
import org.apache.commons.io.FileUtils;
import org.apache.commons.lang.StringUtils;
import org.apache.maven.artifact.repository.ArtifactRepository;
import org.apache.maven.plugin.AbstractMojo;
......@@ -61,7 +62,7 @@ public class OnosAppMojo extends AbstractMojo {
private static final String ARTIFACT = "artifact";
private static final String APP_XML = "app.xml";
private static final String ICON_PNG = "icon.png";
private static final String APP_PNG = "app.png";
private static final String FEATURES_XML = "features.xml";
private static final String MVN_URL = "mvn:";
......@@ -83,7 +84,7 @@ public class OnosAppMojo extends AbstractMojo {
private static final String DEFAULT_ORIGIN = "ON.Lab";
private static final String DEFAULT_VERSION = "${project.version}";
private static final String DEFAULT_CATEGORY = "Default";
private static final String DEFAULT_CATEGORY = "default";
private static final String DEFAULT_URL = "http://onosproject.org";
private static final String DEFAULT_FEATURES_REPO =
......@@ -161,6 +162,7 @@ public class OnosAppMojo extends AbstractMojo {
@Override
public void execute() throws MojoExecutionException {
File appFile = new File(baseDir, APP_XML);
File iconFile = new File(baseDir, APP_PNG);
File featuresFile = new File(baseDir, FEATURES_XML);
name = (String) project.getProperties().get(ONOS_APP_NAME);
......@@ -204,6 +206,7 @@ public class OnosAppMojo extends AbstractMojo {
if (stageDirectory.exists() || stageDirectory.mkdirs()) {
processAppXml(appFile);
processAppPng(iconFile);
processFeaturesXml(featuresFile);
processArtifacts();
generateAppPackage();
......@@ -259,6 +262,19 @@ public class OnosAppMojo extends AbstractMojo {
}
}
// Stages the app.png file of a specific application.
private void processAppPng(File iconFile) throws MojoExecutionException {
try {
File stagedIconFile = new File(stageDirectory, APP_PNG);
if (iconFile.exists()) {
FileUtils.copyFile(iconFile, stagedIconFile);
}
} catch (IOException e) {
throw new MojoExecutionException("Unable to copy app.png", e);
}
}
private void processFeaturesXml(File featuresFile) throws MojoExecutionException {
boolean specified = featuresRepo != null && featuresRepo.length() > 0;
......
......@@ -23,7 +23,10 @@ find $M2_REPO/org/onosproject/ -name "*.oar" -path "*/${ONOS_POM_VERSION}/*" | w
name=$(grep "name=" $AUX/app.xml | sed 's/<app name="//g;s/".*//g')
mkdir -p $APPS/$name
cp $AUX/app.xml $APPS/$name/app.xml
[ -f $AUX/app.png ] && cp $AUX/app.png $APPS/$name/app.png
cp $AUX/*.oar $APPS/$name/$name.oar
cp -rf $AUX/m2/* $KARAF_M2
rm -fr $AUX
done
cp $ONOS_ROOT/apps/app.png $APPS/app.png
......
......@@ -18,10 +18,15 @@ package org.onosproject.ui.impl;
import com.sun.jersey.multipart.FormDataParam;
import org.onlab.rest.BaseResource;
import org.onosproject.app.ApplicationAdminService;
import org.onosproject.core.Application;
import org.onosproject.core.ApplicationId;
import javax.ws.rs.Consumes;
import javax.ws.rs.GET;
import javax.ws.rs.POST;
import javax.ws.rs.Path;
import javax.ws.rs.PathParam;
import javax.ws.rs.Produces;
import javax.ws.rs.core.MediaType;
import javax.ws.rs.core.Response;
import java.io.IOException;
......@@ -41,4 +46,13 @@ public class ApplicationResource extends BaseResource {
return Response.ok().build();
}
@Path("{name}/icon")
@GET
@Produces("image/png")
public Response getIcon(@PathParam("name") String name) throws IOException {
ApplicationAdminService service = get(ApplicationAdminService.class);
ApplicationId appId = service.getId(name);
Application app = service.getApplication(appId);
return Response.ok(app.icon()).build();
}
}
......
......@@ -45,15 +45,18 @@ public class ApplicationViewMessageHandler extends UiMessageHandler {
private static final String STATE = "state";
private static final String STATE_IID = "_iconid_state";
private static final String ID = "id";
private static final String ICON = "icon";
private static final String VERSION = "version";
private static final String CATEGORY = "category";
private static final String ORIGIN = "origin";
private static final String DESC = "desc";
private static final String URL = "url";
private static final String ICON_ID_ACTIVE = "active";
private static final String ICON_ID_INACTIVE = "appInactive";
private static final String[] COL_IDS = {
STATE, STATE_IID, ID, VERSION, ORIGIN, DESC
STATE, STATE_IID, ID, ICON, VERSION, CATEGORY, ORIGIN, DESC, URL
};
@Override
......@@ -99,9 +102,12 @@ public class ApplicationViewMessageHandler extends UiMessageHandler {
row.cell(STATE, state)
.cell(STATE_IID, iconId)
.cell(ID, id.name())
.cell(ICON, id.name())
.cell(VERSION, app.version())
.cell(CATEGORY, app.category())
.cell(ORIGIN, app.origin())
.cell(DESC, app.description());
.cell(DESC, app.description())
.cell(URL, app.url());
}
}
......
......@@ -41,10 +41,13 @@
<table>
<tr>
<td colId="state" class="table-icon" sortable></td>
<td colId="icon" col-width="36px">Icon </td>
<td colId="id" sortable>App ID </td>
<td colId="version" sortable>Version </td>
<td colId="category" sortable>Category </td>
<td colId="origin" sortable>Origin </td>
<td colId="desc" col-width="475px">Description </td>
<td col-width="50px">URL </td>
</tr>
</table>
</div>
......@@ -64,10 +67,13 @@
<td class="table-icon">
<div icon icon-id="{{app._iconid_state}}"></div>
</td>
<td><img data-ng-src="./rs/applications/{{app.icon}}/icon" height="28px" width="28px" /></td>
<td>{{app.id}}</td>
<td>{{app.version}}</td>
<td>{{app.category}}</td>
<td>{{app.origin}}</td>
<td>{{app.desc}}</td>
<td><a href="{{app.url}}" target="_blank">LINK</a></td>
</tr>
</table>
</div>
......