blob: 6d7dc317d1a8436c274785d1f923fb49bcd0537a [file] [log] [blame]
Thomas Vachuska02aeb032015-01-06 22:36:30 -08001/*
Jian Lic35415d2016-01-14 17:22:31 -08002 * Copyright 2015-2016 Open Networking Laboratory
Thomas Vachuska02aeb032015-01-06 22:36:30 -08003 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16package org.onosproject.common.app;
17
Thomas Vachuskaebf5e542015-02-03 19:38:13 -080018import com.google.common.collect.ImmutableList;
Thomas Vachuska02aeb032015-01-06 22:36:30 -080019import com.google.common.collect.ImmutableSet;
Thomas Vachuska761f0042015-11-11 19:10:17 -080020import com.google.common.collect.Lists;
Thomas Vachuska02aeb032015-01-06 22:36:30 -080021import com.google.common.io.ByteStreams;
22import com.google.common.io.Files;
23import org.apache.commons.configuration.ConfigurationException;
Changhoon Yoonb856b812015-08-10 03:47:19 +090024import org.apache.commons.configuration.HierarchicalConfiguration;
Thomas Vachuska02aeb032015-01-06 22:36:30 -080025import org.apache.commons.configuration.XMLConfiguration;
Jian Lic35415d2016-01-14 17:22:31 -080026import org.apache.commons.lang.StringUtils;
Thomas Vachuska02aeb032015-01-06 22:36:30 -080027import org.onlab.util.Tools;
28import org.onosproject.app.ApplicationDescription;
29import org.onosproject.app.ApplicationEvent;
30import org.onosproject.app.ApplicationException;
31import org.onosproject.app.ApplicationStoreDelegate;
32import org.onosproject.app.DefaultApplicationDescription;
Changhoon Yoonbdeb88a2015-05-12 20:35:31 +090033import org.onosproject.core.ApplicationRole;
Thomas Vachuska02aeb032015-01-06 22:36:30 -080034import org.onosproject.core.Version;
Changhoon Yoonb856b812015-08-10 03:47:19 +090035import org.onosproject.security.AppPermission;
36import org.onosproject.security.Permission;
Thomas Vachuska02aeb032015-01-06 22:36:30 -080037import org.onosproject.store.AbstractStore;
38import org.slf4j.Logger;
39import org.slf4j.LoggerFactory;
40
Jian Lic35415d2016-01-14 17:22:31 -080041import javax.imageio.ImageIO;
42import java.awt.image.BufferedImage;
43import java.awt.image.DataBufferByte;
44import java.awt.image.WritableRaster;
Thomas Vachuska02aeb032015-01-06 22:36:30 -080045import java.io.ByteArrayInputStream;
46import java.io.File;
47import java.io.FileInputStream;
48import java.io.FileNotFoundException;
49import java.io.IOException;
50import java.io.InputStream;
51import java.net.URI;
HIGUCHI Yuta436f8d52015-12-07 21:17:48 -080052import java.nio.charset.StandardCharsets;
Thomas Vachuska90b453f2015-01-30 18:57:14 -080053import java.nio.file.NoSuchFileException;
Thomas Vachuskaebf5e542015-02-03 19:38:13 -080054import java.util.List;
Changhoon Yoonbdeb88a2015-05-12 20:35:31 +090055import java.util.Locale;
Thomas Vachuska02aeb032015-01-06 22:36:30 -080056import java.util.Set;
57import java.util.zip.ZipEntry;
58import java.util.zip.ZipInputStream;
59
Thomas Vachuskae18a3302015-06-23 12:48:28 -070060import static com.google.common.base.Preconditions.checkState;
Thomas Vachuska02aeb032015-01-06 22:36:30 -080061import static com.google.common.io.ByteStreams.toByteArray;
62import static com.google.common.io.Files.createParentDirs;
63import static com.google.common.io.Files.write;
64
65/**
66 * Facility for reading application archive stream and managing application
67 * directory structure.
68 */
69public class ApplicationArchive
70 extends AbstractStore<ApplicationEvent, ApplicationStoreDelegate> {
71
Thomas Vachuskaa7a0f562015-04-14 23:27:44 -070072 private static Logger log = LoggerFactory.getLogger(ApplicationArchive.class);
73
Thomas Vachuska62ad95f2015-02-18 12:11:36 -080074 // Magic strings to search for at the beginning of the archive stream
75 private static final String XML_MAGIC = "<?xml ";
76
77 // Magic strings to search for and how deep to search it into the archive stream
78 private static final String APP_MAGIC = "<app ";
79 private static final int APP_MAGIC_DEPTH = 1024;
80
Thomas Vachuska02aeb032015-01-06 22:36:30 -080081 private static final String NAME = "[@name]";
82 private static final String ORIGIN = "[@origin]";
83 private static final String VERSION = "[@version]";
84 private static final String FEATURES_REPO = "[@featuresRepo]";
85 private static final String FEATURES = "[@features]";
Thomas Vachuska761f0042015-11-11 19:10:17 -080086 private static final String APPS = "[@apps]";
Thomas Vachuska02aeb032015-01-06 22:36:30 -080087 private static final String DESCRIPTION = "description";
88
Jian Lic35415d2016-01-14 17:22:31 -080089 private static final String CATEGORY = "[@category]";
90 private static final String URL = "[@url]";
Jian Lic35415d2016-01-14 17:22:31 -080091
Changhoon Yoonbdeb88a2015-05-12 20:35:31 +090092 private static final String ROLE = "security.role";
Changhoon Yoonb856b812015-08-10 03:47:19 +090093 private static final String APP_PERMISSIONS = "security.permissions.app-perm";
94 private static final String NET_PERMISSIONS = "security.permissions.net-perm";
95 private static final String JAVA_PERMISSIONS = "security.permissions.java-perm";
Changhoon Yoonbdeb88a2015-05-12 20:35:31 +090096
Thomas Vachuskaa7a0f562015-04-14 23:27:44 -070097 private static final String OAR = ".oar";
Thomas Vachuska02aeb032015-01-06 22:36:30 -080098 private static final String APP_XML = "app.xml";
Jian Lic35415d2016-01-14 17:22:31 -080099 private static final String ICON_PNG = "icon.png";
Thomas Vachuska90b453f2015-01-30 18:57:14 -0800100 private static final String M2_PREFIX = "m2";
101
Thomas Vachuska40a398b2015-04-03 22:26:30 -0700102 private static final String ROOT = "../";
Thomas Vachuska90b453f2015-01-30 18:57:14 -0800103 private static final String M2_ROOT = "system/";
Thomas Vachuskad5d9bcb2015-03-18 17:46:20 -0700104 private static final String APPS_ROOT = "apps/";
Thomas Vachuska02aeb032015-01-06 22:36:30 -0800105
Thomas Vachuska40a398b2015-04-03 22:26:30 -0700106 private File root = new File(ROOT);
107 private File appsDir = new File(root, APPS_ROOT);
108 private File m2Dir = new File(M2_ROOT);
Thomas Vachuska02aeb032015-01-06 22:36:30 -0800109
110 /**
Thomas Vachuska40a398b2015-04-03 22:26:30 -0700111 * Sets the root directory where apps directory is contained.
Thomas Vachuska02aeb032015-01-06 22:36:30 -0800112 *
Thomas Vachuska40a398b2015-04-03 22:26:30 -0700113 * @param root top-level directory path
Thomas Vachuska02aeb032015-01-06 22:36:30 -0800114 */
Thomas Vachuska40a398b2015-04-03 22:26:30 -0700115 protected void setRootPath(String root) {
116 this.root = new File(root);
117 this.appsDir = new File(this.root, APPS_ROOT);
118 this.m2Dir = new File(M2_ROOT);
Thomas Vachuska02aeb032015-01-06 22:36:30 -0800119 }
120
121 /**
Thomas Vachuska40a398b2015-04-03 22:26:30 -0700122 * Returns the root directory where apps directory is contained.
Thomas Vachuska02aeb032015-01-06 22:36:30 -0800123 *
Thomas Vachuska40a398b2015-04-03 22:26:30 -0700124 * @return top-level directory path
Thomas Vachuska02aeb032015-01-06 22:36:30 -0800125 */
Thomas Vachuskae18a3302015-06-23 12:48:28 -0700126 public String getRootPath() {
Thomas Vachuska40a398b2015-04-03 22:26:30 -0700127 return root.getPath();
Thomas Vachuska02aeb032015-01-06 22:36:30 -0800128 }
129
130 /**
131 * Returns the set of installed application names.
132 *
133 * @return installed application names
134 */
135 public Set<String> getApplicationNames() {
136 ImmutableSet.Builder<String> names = ImmutableSet.builder();
137 File[] files = appsDir.listFiles(File::isDirectory);
138 if (files != null) {
139 for (File file : files) {
140 names.add(file.getName());
141 }
142 }
143 return names.build();
144 }
145
146 /**
Thomas Vachuskacf960112015-03-06 22:36:51 -0800147 * Returns the timestamp in millis since start of epoch, of when the
148 * specified application was last modified or changed state.
149 *
150 * @param appName application name
151 * @return number of millis since start of epoch
152 */
153 public long getUpdateTime(String appName) {
154 return appFile(appName, APP_XML).lastModified();
155 }
156
157 /**
Thomas Vachuska02aeb032015-01-06 22:36:30 -0800158 * Loads the application descriptor from the specified application archive
159 * stream and saves the stream in the appropriate application archive
160 * directory.
161 *
162 * @param appName application name
163 * @return application descriptor
164 * @throws org.onosproject.app.ApplicationException if unable to read application description
165 */
166 public ApplicationDescription getApplicationDescription(String appName) {
167 try {
Thomas Vachuskaad35c342015-06-11 17:25:36 -0700168 XMLConfiguration cfg = new XMLConfiguration();
169 cfg.setAttributeSplittingDisabled(true);
170 cfg.setDelimiterParsingDisabled(true);
171 cfg.load(appFile(appName, APP_XML));
172 return loadAppDescription(cfg);
Thomas Vachuska02aeb032015-01-06 22:36:30 -0800173 } catch (Exception e) {
174 throw new ApplicationException("Unable to get app description", e);
175 }
176 }
177
178 /**
179 * Loads the application descriptor from the specified application archive
180 * stream and saves the stream in the appropriate application archive
181 * directory.
182 *
183 * @param stream application archive stream
184 * @return application descriptor
185 * @throws org.onosproject.app.ApplicationException if unable to read the
186 * archive stream or store
187 * the application archive
188 */
Thomas Vachuska0249b532015-02-20 16:46:18 -0800189 public synchronized ApplicationDescription saveApplication(InputStream stream) {
Thomas Vachuska02aeb032015-01-06 22:36:30 -0800190 try (InputStream ais = stream) {
191 byte[] cache = toByteArray(ais);
192 InputStream bis = new ByteArrayInputStream(cache);
Thomas Vachuska02aeb032015-01-06 22:36:30 -0800193
Thomas Vachuska62ad95f2015-02-18 12:11:36 -0800194 boolean plainXml = isPlainXml(cache);
195 ApplicationDescription desc = plainXml ?
196 parsePlainAppDescription(bis) : parseZippedAppDescription(bis);
Thomas Vachuskae18a3302015-06-23 12:48:28 -0700197 checkState(!appFile(desc.name(), APP_XML).exists(),
198 "Application %s already installed", desc.name());
Thomas Vachuska02aeb032015-01-06 22:36:30 -0800199
Thomas Vachuska62ad95f2015-02-18 12:11:36 -0800200 if (plainXml) {
201 expandPlainApplication(cache, desc);
202 } else {
203 bis.reset();
204 expandZippedApplication(bis, desc);
205
206 bis.reset();
207 saveApplication(bis, desc);
208 }
209
Thomas Vachuska02aeb032015-01-06 22:36:30 -0800210 installArtifacts(desc);
211 return desc;
212 } catch (IOException e) {
213 throw new ApplicationException("Unable to save application", e);
214 }
215 }
216
Thomas Vachuska62ad95f2015-02-18 12:11:36 -0800217 // Indicates whether the stream encoded in the given bytes is plain XML.
218 private boolean isPlainXml(byte[] bytes) {
219 return substring(bytes, XML_MAGIC.length()).equals(XML_MAGIC) ||
220 substring(bytes, APP_MAGIC_DEPTH).contains(APP_MAGIC);
221 }
222
223 // Returns the substring of maximum possible length from the specified bytes.
224 private String substring(byte[] bytes, int length) {
HIGUCHI Yuta436f8d52015-12-07 21:17:48 -0800225 return new String(bytes, 0, Math.min(bytes.length, length), StandardCharsets.UTF_8);
Thomas Vachuska62ad95f2015-02-18 12:11:36 -0800226 }
227
Thomas Vachuska02aeb032015-01-06 22:36:30 -0800228 /**
229 * Purges the application archive directory.
230 *
231 * @param appName application name
232 */
Thomas Vachuska0249b532015-02-20 16:46:18 -0800233 public synchronized void purgeApplication(String appName) {
Thomas Vachuska62ad95f2015-02-18 12:11:36 -0800234 File appDir = new File(appsDir, appName);
Thomas Vachuska02aeb032015-01-06 22:36:30 -0800235 try {
Thomas Vachuska62ad95f2015-02-18 12:11:36 -0800236 Tools.removeDirectory(appDir);
Thomas Vachuska02aeb032015-01-06 22:36:30 -0800237 } catch (IOException e) {
238 throw new ApplicationException("Unable to purge application " + appName, e);
239 }
Thomas Vachuska62ad95f2015-02-18 12:11:36 -0800240 if (appDir.exists()) {
241 throw new ApplicationException("Unable to purge application " + appName);
242 }
Thomas Vachuska02aeb032015-01-06 22:36:30 -0800243 }
244
245 /**
Thomas Vachuska62ad95f2015-02-18 12:11:36 -0800246 * Returns application archive stream for the specified application. This
247 * will be either the application ZIP file or the application XML file.
Thomas Vachuska02aeb032015-01-06 22:36:30 -0800248 *
249 * @param appName application name
250 * @return application archive stream
251 */
Thomas Vachuska0249b532015-02-20 16:46:18 -0800252 public synchronized InputStream getApplicationInputStream(String appName) {
Thomas Vachuska02aeb032015-01-06 22:36:30 -0800253 try {
Thomas Vachuskaa7a0f562015-04-14 23:27:44 -0700254 File appFile = appFile(appName, appName + OAR);
Thomas Vachuska62ad95f2015-02-18 12:11:36 -0800255 return new FileInputStream(appFile.exists() ? appFile : appFile(appName, APP_XML));
Thomas Vachuska02aeb032015-01-06 22:36:30 -0800256 } catch (FileNotFoundException e) {
257 throw new ApplicationException("Application " + appName + " not found");
258 }
259 }
260
261 // Scans the specified ZIP stream for app.xml entry and parses it producing
262 // an application descriptor.
Thomas Vachuska62ad95f2015-02-18 12:11:36 -0800263 private ApplicationDescription parseZippedAppDescription(InputStream stream)
Thomas Vachuska02aeb032015-01-06 22:36:30 -0800264 throws IOException {
265 try (ZipInputStream zis = new ZipInputStream(stream)) {
266 ZipEntry entry;
267 while ((entry = zis.getNextEntry()) != null) {
268 if (entry.getName().equals(APP_XML)) {
Thomas Vachuskaebf5e542015-02-03 19:38:13 -0800269 byte[] data = ByteStreams.toByteArray(zis);
Thomas Vachuska62ad95f2015-02-18 12:11:36 -0800270 return parsePlainAppDescription(new ByteArrayInputStream(data));
Thomas Vachuska02aeb032015-01-06 22:36:30 -0800271 }
272 zis.closeEntry();
273 }
274 }
275 throw new IOException("Unable to locate " + APP_XML);
276 }
277
Thomas Vachuska62ad95f2015-02-18 12:11:36 -0800278 // Scans the specified XML stream and parses it producing an application descriptor.
279 private ApplicationDescription parsePlainAppDescription(InputStream stream)
280 throws IOException {
281 XMLConfiguration cfg = new XMLConfiguration();
Thomas Vachuskaad35c342015-06-11 17:25:36 -0700282 cfg.setAttributeSplittingDisabled(true);
283 cfg.setDelimiterParsingDisabled(true);
Thomas Vachuska62ad95f2015-02-18 12:11:36 -0800284 try {
285 cfg.load(stream);
286 return loadAppDescription(cfg);
287 } catch (ConfigurationException e) {
288 throw new IOException("Unable to parse " + APP_XML, e);
289 }
290 }
291
Thomas Vachuska02aeb032015-01-06 22:36:30 -0800292 private ApplicationDescription loadAppDescription(XMLConfiguration cfg) {
Thomas Vachuska02aeb032015-01-06 22:36:30 -0800293 String name = cfg.getString(NAME);
294 Version version = Version.version(cfg.getString(VERSION));
Thomas Vachuska02aeb032015-01-06 22:36:30 -0800295 String origin = cfg.getString(ORIGIN);
Jian Lic35415d2016-01-14 17:22:31 -0800296 String category = cfg.getString(CATEGORY);
297 String url = cfg.getString(URL);
298 byte[] icon = getApplicationIcon(name);
Changhoon Yoonbdeb88a2015-05-12 20:35:31 +0900299 ApplicationRole role = getRole(cfg.getString(ROLE));
300 Set<Permission> perms = getPermissions(cfg);
Thomas Vachuska02aeb032015-01-06 22:36:30 -0800301 String featRepo = cfg.getString(FEATURES_REPO);
302 URI featuresRepo = featRepo != null ? URI.create(featRepo) : null;
Thomas Vachuskaad35c342015-06-11 17:25:36 -0700303 List<String> features = ImmutableList.copyOf(cfg.getString(FEATURES).split(","));
Thomas Vachuska02aeb032015-01-06 22:36:30 -0800304
Thomas Vachuska761f0042015-11-11 19:10:17 -0800305 String apps = cfg.getString(APPS, "");
306 List<String> requiredApps = apps.isEmpty() ?
307 ImmutableList.of() : ImmutableList.copyOf(apps.split(","));
308
Jian Li8bcb4f22016-01-20 10:36:18 -0800309 // put full description to readme field
310 String readme = cfg.getString(DESCRIPTION);
Jian Lic35415d2016-01-14 17:22:31 -0800311
Jian Li8bcb4f22016-01-20 10:36:18 -0800312 // put short description to description field
313 String desc = compactDescription(readme);
Jian Lic35415d2016-01-14 17:22:31 -0800314
315 return new DefaultApplicationDescription(name, version, desc, origin,
Jian Li8bcb4f22016-01-20 10:36:18 -0800316 category, url, readme, icon,
317 role, perms, featuresRepo,
318 features, requiredApps);
Thomas Vachuska02aeb032015-01-06 22:36:30 -0800319 }
320
321 // Expands the specified ZIP stream into app-specific directory.
Thomas Vachuska62ad95f2015-02-18 12:11:36 -0800322 private void expandZippedApplication(InputStream stream, ApplicationDescription desc)
Thomas Vachuska02aeb032015-01-06 22:36:30 -0800323 throws IOException {
324 ZipInputStream zis = new ZipInputStream(stream);
325 ZipEntry entry;
326 File appDir = new File(appsDir, desc.name());
327 while ((entry = zis.getNextEntry()) != null) {
Thomas Vachuskaebf5e542015-02-03 19:38:13 -0800328 if (!entry.isDirectory()) {
329 byte[] data = ByteStreams.toByteArray(zis);
330 zis.closeEntry();
Thomas Vachuskaebf5e542015-02-03 19:38:13 -0800331 File file = new File(appDir, entry.getName());
332 createParentDirs(file);
333 write(data, file);
334 }
Thomas Vachuska02aeb032015-01-06 22:36:30 -0800335 }
336 zis.close();
337 }
338
Thomas Vachuska62ad95f2015-02-18 12:11:36 -0800339 // Saves the specified XML stream into app-specific directory.
340 private void expandPlainApplication(byte[] stream, ApplicationDescription desc)
341 throws IOException {
342 File file = appFile(desc.name(), APP_XML);
Thomas Vachuskae18a3302015-06-23 12:48:28 -0700343 checkState(!file.getParentFile().exists(), "Application already installed");
Thomas Vachuska62ad95f2015-02-18 12:11:36 -0800344 createParentDirs(file);
345 write(stream, file);
346 }
347
348
Thomas Vachuska02aeb032015-01-06 22:36:30 -0800349 // Saves the specified ZIP stream into a file under app-specific directory.
350 private void saveApplication(InputStream stream, ApplicationDescription desc)
351 throws IOException {
Thomas Vachuskaa7a0f562015-04-14 23:27:44 -0700352 Files.write(toByteArray(stream), appFile(desc.name(), desc.name() + OAR));
Thomas Vachuska02aeb032015-01-06 22:36:30 -0800353 }
354
355 // Installs application artifacts into M2 repository.
Thomas Vachuska90b453f2015-01-30 18:57:14 -0800356 private void installArtifacts(ApplicationDescription desc) throws IOException {
357 try {
358 Tools.copyDirectory(appFile(desc.name(), M2_PREFIX), m2Dir);
359 } catch (NoSuchFileException e) {
360 log.debug("Application {} has no M2 artifacts", desc.name());
361 }
Thomas Vachuska02aeb032015-01-06 22:36:30 -0800362 }
363
Thomas Vachuska90b453f2015-01-30 18:57:14 -0800364 /**
365 * Marks the app as active by creating token file in the app directory.
366 *
367 * @param appName application name
368 * @return true if file was created
369 */
Thomas Vachuska02aeb032015-01-06 22:36:30 -0800370 protected boolean setActive(String appName) {
371 try {
Thomas Vachuskacf960112015-03-06 22:36:51 -0800372 return appFile(appName, "active").createNewFile() && updateTime(appName);
Thomas Vachuska02aeb032015-01-06 22:36:30 -0800373 } catch (IOException e) {
374 throw new ApplicationException("Unable to mark app as active", e);
375 }
376 }
377
Thomas Vachuska90b453f2015-01-30 18:57:14 -0800378 /**
379 * Clears the app as active by deleting token file in the app directory.
380 *
381 * @param appName application name
382 * @return true if file was deleted
383 */
Thomas Vachuska02aeb032015-01-06 22:36:30 -0800384 protected boolean clearActive(String appName) {
Thomas Vachuskacf960112015-03-06 22:36:51 -0800385 return appFile(appName, "active").delete() && updateTime(appName);
386 }
387
388 /**
389 * Updates the time-stamp of the app descriptor file.
390 *
391 * @param appName application name
392 * @return true if the app descriptor was updated
393 */
Thomas Vachuska161baf52015-03-27 16:15:39 -0700394 protected boolean updateTime(String appName) {
Thomas Vachuskacf960112015-03-06 22:36:51 -0800395 return appFile(appName, APP_XML).setLastModified(System.currentTimeMillis());
Thomas Vachuska02aeb032015-01-06 22:36:30 -0800396 }
397
Thomas Vachuska90b453f2015-01-30 18:57:14 -0800398 /**
399 * Indicates whether the app was marked as active by checking for token file.
400 *
401 * @param appName application name
402 * @return true if the app is marked as active
403 */
Thomas Vachuska02aeb032015-01-06 22:36:30 -0800404 protected boolean isActive(String appName) {
405 return appFile(appName, "active").exists();
406 }
407
Thomas Vachuska02aeb032015-01-06 22:36:30 -0800408 // Returns the name of the file located under the specified app directory.
409 private File appFile(String appName, String fileName) {
410 return new File(new File(appsDir, appName), fileName);
411 }
412
Changhoon Yoonbdeb88a2015-05-12 20:35:31 +0900413 // Returns the set of Permissions specified in the app.xml file
414 private ImmutableSet<Permission> getPermissions(XMLConfiguration cfg) {
Thomas Vachuska761f0042015-11-11 19:10:17 -0800415 List<Permission> permissionList = Lists.newArrayList();
Changhoon Yoonb856b812015-08-10 03:47:19 +0900416
417 for (Object o : cfg.getList(APP_PERMISSIONS)) {
Changhoon Yoona7841ed2015-05-15 02:51:08 +0900418 String name = (String) o;
Changhoon Yoonb856b812015-08-10 03:47:19 +0900419 permissionList.add(new Permission(AppPermission.class.getName(), name));
420 }
421 for (Object o : cfg.getList(NET_PERMISSIONS)) {
422 //TODO: TO BE FLESHED OUT WHEN NETWORK PERMISSIONS ARE SUPPORTED
423 break;
424 }
425
426 List<HierarchicalConfiguration> fields =
427 cfg.configurationsAt(JAVA_PERMISSIONS);
428 for (HierarchicalConfiguration sub : fields) {
429 String classname = sub.getString("classname");
430 String name = sub.getString("name");
431 String actions = sub.getString("actions");
432
433 if (classname != null && name != null) {
434 permissionList.add(new Permission(classname, name, actions));
Changhoon Yoonbdeb88a2015-05-12 20:35:31 +0900435 }
436 }
Changhoon Yoona7841ed2015-05-15 02:51:08 +0900437 return ImmutableSet.copyOf(permissionList);
Changhoon Yoonbdeb88a2015-05-12 20:35:31 +0900438 }
439
Jian Lic35415d2016-01-14 17:22:31 -0800440 // Returns the byte stream from icon.png file in oar application archive.
441 private byte[] getApplicationIcon(String appName) {
442 // open image
443 File iconFile = appFile(appName, ICON_PNG);
444
445 if (!iconFile.exists()) {
446 iconFile = new File(appsDir, ICON_PNG);
447 }
448
449 if (!iconFile.exists()) {
450 return null;
451 }
452
453 BufferedImage bufferedImage = null;
454 try {
455 bufferedImage = ImageIO.read(iconFile);
456 } catch (IOException e) {
457 e.printStackTrace();
458 }
459
460 // get DataBufferBytes from Raster
461 WritableRaster raster = bufferedImage .getRaster();
462 DataBufferByte data = (DataBufferByte) raster.getDataBuffer();
463
464 return data.getData();
465 }
466
Changhoon Yoonbdeb88a2015-05-12 20:35:31 +0900467 // Returns application role type
468 public ApplicationRole getRole(String value) {
469 if (value == null) {
470 return ApplicationRole.UNSPECIFIED;
471 } else {
472 try {
473 return ApplicationRole.valueOf(value.toUpperCase(Locale.ENGLISH));
474 } catch (IllegalArgumentException e) {
475 log.debug("Unknown role value: %s", value);
476 return ApplicationRole.UNSPECIFIED;
477 }
478 }
479 }
Jian Lic35415d2016-01-14 17:22:31 -0800480
481 // Returns the first sentence of the given sentence
482 private String compactDescription(String sentence) {
483 if (StringUtils.isNotEmpty(sentence)) {
484 if (StringUtils.contains(sentence, ".")) {
485 return StringUtils.substringBefore(sentence, ".") + ".";
486 } else {
Jian Li8bcb4f22016-01-20 10:36:18 -0800487 return sentence;
Jian Lic35415d2016-01-14 17:22:31 -0800488 }
489 }
490 return sentence;
491 }
Thomas Vachuska02aeb032015-01-06 22:36:30 -0800492}