blob: fe47927bab3ccd5c9a98de96fcca712e85019332 [file] [log] [blame]
Thomas Vachuska8c8b0372015-03-10 11:11:24 -07001/*
Brian O'Connor5ab426f2016-04-09 01:19:45 -07002 * Copyright 2015-present Open Networking Laboratory
Thomas Vachuska8c8b0372015-03-10 11:11:24 -07003 *
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.maven;
17
Thomas Vachuska586afd82015-04-17 11:06:53 -070018import com.google.common.collect.ImmutableList;
Thomas Vachuskaa98ae7f2015-04-14 14:00:36 -070019import org.apache.commons.configuration.ConfigurationException;
20import org.apache.commons.configuration.XMLConfiguration;
Jian Li97d6b2d2016-01-20 10:13:43 -080021import org.apache.commons.io.FileUtils;
Jian Lic35415d2016-01-14 17:22:31 -080022import org.apache.commons.lang.StringUtils;
Brian O'Connorbf7eca52015-04-15 16:25:46 -070023import org.apache.maven.artifact.repository.ArtifactRepository;
Thomas Vachuska8c8b0372015-03-10 11:11:24 -070024import org.apache.maven.plugin.AbstractMojo;
25import org.apache.maven.plugin.MojoExecutionException;
Thomas Vachuskaa98ae7f2015-04-14 14:00:36 -070026import org.apache.maven.plugins.annotations.Component;
Thomas Vachuska8c8b0372015-03-10 11:11:24 -070027import org.apache.maven.plugins.annotations.LifecyclePhase;
28import org.apache.maven.plugins.annotations.Mojo;
29import org.apache.maven.plugins.annotations.Parameter;
Thomas Vachuskaa98ae7f2015-04-14 14:00:36 -070030import org.apache.maven.project.MavenProject;
31import org.apache.maven.project.MavenProjectHelper;
Thomas Vachuska8c8b0372015-03-10 11:11:24 -070032
Jian Lic35415d2016-01-14 17:22:31 -080033import javax.imageio.ImageIO;
34import javax.xml.bind.annotation.adapters.XmlJavaTypeAdapter;
35import java.awt.image.BufferedImage;
36import java.awt.image.DataBufferByte;
37import java.awt.image.WritableRaster;
Thomas Vachuskaa98ae7f2015-04-14 14:00:36 -070038import java.io.File;
39import java.io.FileInputStream;
40import java.io.FileNotFoundException;
41import java.io.FileOutputStream;
42import java.io.IOException;
43import java.io.InputStream;
Thomas Vachuska8c8b0372015-03-10 11:11:24 -070044import java.util.List;
Thomas Vachuskaa98ae7f2015-04-14 14:00:36 -070045import java.util.stream.Collectors;
46import java.util.zip.ZipEntry;
47import java.util.zip.ZipOutputStream;
48
Thomas Vachuska586afd82015-04-17 11:06:53 -070049import static com.google.common.io.ByteStreams.toByteArray;
Thomas Vachuskaa98ae7f2015-04-14 14:00:36 -070050import static org.codehaus.plexus.util.FileUtils.*;
Thomas Vachuska8c8b0372015-03-10 11:11:24 -070051
52/**
Thomas Vachuskaa98ae7f2015-04-14 14:00:36 -070053 * Produces ONOS application archive using the app.xml file information.
Thomas Vachuska8c8b0372015-03-10 11:11:24 -070054 */
55@Mojo(name = "app", defaultPhase = LifecyclePhase.PACKAGE)
56public class OnosAppMojo extends AbstractMojo {
57
Thomas Vachuskaa98ae7f2015-04-14 14:00:36 -070058 private static final String APP = "app";
59 private static final String NAME = "[@name]";
60 private static final String VERSION = "[@version]";
61 private static final String FEATURES_REPO = "[@featuresRepo]";
Thomas Vachuskaa98ae7f2015-04-14 14:00:36 -070062 private static final String ARTIFACT = "artifact";
Thomas Vachuska8c8b0372015-03-10 11:11:24 -070063
Thomas Vachuskaa98ae7f2015-04-14 14:00:36 -070064 private static final String APP_XML = "app.xml";
Jian Li97d6b2d2016-01-20 10:13:43 -080065 private static final String APP_PNG = "app.png";
Thomas Vachuskaa98ae7f2015-04-14 14:00:36 -070066 private static final String FEATURES_XML = "features.xml";
Thomas Vachuska8c8b0372015-03-10 11:11:24 -070067
Thomas Vachuskaa98ae7f2015-04-14 14:00:36 -070068 private static final String MVN_URL = "mvn:";
Thomas Vachuskaa98ae7f2015-04-14 14:00:36 -070069 private static final String M2_PREFIX = "m2";
Thomas Vachuska8c8b0372015-03-10 11:11:24 -070070
Thomas Vachuska586afd82015-04-17 11:06:53 -070071 private static final String ONOS_APP_NAME = "onos.app.name";
72 private static final String ONOS_APP_ORIGIN = "onos.app.origin";
Thomas Vachuska761f0042015-11-11 19:10:17 -080073 private static final String ONOS_APP_REQUIRES = "onos.app.requires";
Thomas Vachuska586afd82015-04-17 11:06:53 -070074
Jian Lic35415d2016-01-14 17:22:31 -080075 private static final String ONOS_APP_CATEGORY = "onos.app.category";
76 private static final String ONOS_APP_URL = "onos.app.url";
Simon Huntafae2f72016-03-04 21:18:23 -080077 private static final String ONOS_APP_TITLE = "onos.app.title";
Jian Lic35415d2016-01-14 17:22:31 -080078 private static final String ONOS_APP_README = "onos.app.readme";
79
Thomas Vachuskaa98ae7f2015-04-14 14:00:36 -070080 private static final String JAR = "jar";
81 private static final String XML = "xml";
82 private static final String APP_ZIP = "oar";
83 private static final String PACKAGE_DIR = "oar";
Thomas Vachuska8c8b0372015-03-10 11:11:24 -070084
Thomas Vachuska586afd82015-04-17 11:06:53 -070085 private static final String DEFAULT_ORIGIN = "ON.Lab";
Thomas Vachuska41e8c182015-04-21 11:09:19 -070086 private static final String DEFAULT_VERSION = "${project.version}";
Thomas Vachuska586afd82015-04-17 11:06:53 -070087
Jian Li97d6b2d2016-01-20 10:13:43 -080088 private static final String DEFAULT_CATEGORY = "default";
Jian Lic35415d2016-01-14 17:22:31 -080089 private static final String DEFAULT_URL = "http://onosproject.org";
90
Thomas Vachuska586afd82015-04-17 11:06:53 -070091 private static final String DEFAULT_FEATURES_REPO =
92 "mvn:${project.groupId}/${project.artifactId}/${project.version}/xml/features";
93 private static final String DEFAULT_ARTIFACT =
94 "mvn:${project.groupId}/${project.artifactId}/${project.version}";
95
Thomas Vachuska41e8c182015-04-21 11:09:19 -070096 private static final int BUFFER_SIZE = 8192;
Thomas Vachuska8c8b0372015-03-10 11:11:24 -070097
Thomas Vachuska586afd82015-04-17 11:06:53 -070098 private String name;
99 private String origin;
Thomas Vachuska761f0042015-11-11 19:10:17 -0800100 private String requiredApps;
Jian Lic35415d2016-01-14 17:22:31 -0800101 private String category;
102 private String url;
Simon Huntafae2f72016-03-04 21:18:23 -0800103 private String title;
Jian Lic35415d2016-01-14 17:22:31 -0800104 private String readme;
Thomas Vachuska586afd82015-04-17 11:06:53 -0700105 private String version = DEFAULT_VERSION;
Thomas Vachuska586afd82015-04-17 11:06:53 -0700106 private String featuresRepo = DEFAULT_FEATURES_REPO;
Thomas Vachuska8c8b0372015-03-10 11:11:24 -0700107 private List<String> artifacts;
108
Thomas Vachuskaa98ae7f2015-04-14 14:00:36 -0700109 /**
110 * The project base directory.
111 */
112 @Parameter(defaultValue = "${basedir}")
113 protected File baseDir;
Thomas Vachuska8c8b0372015-03-10 11:11:24 -0700114
Thomas Vachuskaa98ae7f2015-04-14 14:00:36 -0700115 /**
116 * The directory where the generated catalogue file will be put.
117 */
118 @Parameter(defaultValue = "${project.build.directory}")
119 protected File dstDirectory;
120
121 /**
122 * The project group ID.
123 */
124 @Parameter(defaultValue = "${project.groupId}")
125 protected String projectGroupId;
126
127 /**
128 * The project artifact ID.
129 */
130 @Parameter(defaultValue = "${project.artifactId}")
131 protected String projectArtifactId;
132
133 /**
134 * The project version.
135 */
136 @Parameter(defaultValue = "${project.version}")
137 protected String projectVersion;
138
139 /**
140 * The project version.
141 */
142 @Parameter(defaultValue = "${project.description}")
143 protected String projectDescription;
144
Brian O'Connorbf7eca52015-04-15 16:25:46 -0700145 @Parameter(defaultValue = "${localRepository}")
146 protected ArtifactRepository localRepository;
147
Thomas Vachuskaa98ae7f2015-04-14 14:00:36 -0700148 /**
149 * Maven project
150 */
Brian O'Connorbf7eca52015-04-15 16:25:46 -0700151 @Parameter(defaultValue = "${project}")
152 protected MavenProject project;
Thomas Vachuskaa98ae7f2015-04-14 14:00:36 -0700153
154 /**
155 * Maven project helper.
156 */
157 @Component
Brian O'Connorbf7eca52015-04-15 16:25:46 -0700158 protected MavenProjectHelper projectHelper;
Thomas Vachuskaa98ae7f2015-04-14 14:00:36 -0700159
Thomas Vachuskaa98ae7f2015-04-14 14:00:36 -0700160 private File m2Directory;
161 protected File stageDirectory;
162 protected String projectPath;
Thomas Vachuskaa98ae7f2015-04-14 14:00:36 -0700163
164 @Override
Thomas Vachuska8c8b0372015-03-10 11:11:24 -0700165 public void execute() throws MojoExecutionException {
Thomas Vachuskaa98ae7f2015-04-14 14:00:36 -0700166 File appFile = new File(baseDir, APP_XML);
Jian Li97d6b2d2016-01-20 10:13:43 -0800167 File iconFile = new File(baseDir, APP_PNG);
Thomas Vachuskaa98ae7f2015-04-14 14:00:36 -0700168 File featuresFile = new File(baseDir, FEATURES_XML);
Thomas Vachuska8c8b0372015-03-10 11:11:24 -0700169
Thomas Vachuska586afd82015-04-17 11:06:53 -0700170 name = (String) project.getProperties().get(ONOS_APP_NAME);
171
172 // If neither the app.xml file exists, nor the onos.app.name property
173 // is defined, there is nothing for this Mojo to do, so bail.
174 if (!appFile.exists() && name == null) {
Thomas Vachuskaa98ae7f2015-04-14 14:00:36 -0700175 return;
176 }
177
Brian O'Connorbf7eca52015-04-15 16:25:46 -0700178 m2Directory = new File(localRepository.getBasedir());
Thomas Vachuskaa98ae7f2015-04-14 14:00:36 -0700179 stageDirectory = new File(dstDirectory, PACKAGE_DIR);
Thomas Vachuskaa98ae7f2015-04-14 14:00:36 -0700180 projectPath = M2_PREFIX + "/" + artifactDir(projectGroupId, projectArtifactId, projectVersion);
181
Thomas Vachuska586afd82015-04-17 11:06:53 -0700182 origin = (String) project.getProperties().get(ONOS_APP_ORIGIN);
183 origin = origin != null ? origin : DEFAULT_ORIGIN;
184
Thomas Vachuska761f0042015-11-11 19:10:17 -0800185 requiredApps = (String) project.getProperties().get(ONOS_APP_REQUIRES);
Thomas Vachuskafa776af2015-11-18 00:57:10 -0800186 requiredApps = requiredApps == null ? "" : requiredApps.replaceAll("[\\s]", "");
Thomas Vachuska761f0042015-11-11 19:10:17 -0800187
Jian Lic35415d2016-01-14 17:22:31 -0800188 category = (String) project.getProperties().get(ONOS_APP_CATEGORY);
189 category = category != null ? category : DEFAULT_CATEGORY;
190
191 url = (String) project.getProperties().get(ONOS_APP_URL);
192 url = url != null ? url : DEFAULT_URL;
193
Simon Huntafae2f72016-03-04 21:18:23 -0800194 // if title does not exist, fall back to the name
195 title = (String) project.getProperties().get(ONOS_APP_TITLE);
196 title = title != null ? title : name;
197
Jian Lic35415d2016-01-14 17:22:31 -0800198 // if readme does not exist, we simply fallback to use description
199 readme = (String) project.getProperties().get(ONOS_APP_README);
200 readme = readme != null ? readme : projectDescription;
201
Thomas Vachuska586afd82015-04-17 11:06:53 -0700202 if (appFile.exists()) {
203 loadAppFile(appFile);
204 } else {
205 artifacts = ImmutableList.of(eval(DEFAULT_ARTIFACT));
206 }
Thomas Vachuskaa98ae7f2015-04-14 14:00:36 -0700207
208 // If there are any artifacts, stage the
209 if (!artifacts.isEmpty()) {
Thomas Vachuska586afd82015-04-17 11:06:53 -0700210 getLog().info("Building ONOS application package for " + name + " (v" + eval(version) + ")");
Thomas Vachuskaa98ae7f2015-04-14 14:00:36 -0700211 artifacts.forEach(a -> getLog().debug("Including artifact: " + a));
212
Brian O'Connorbf7eca52015-04-15 16:25:46 -0700213 if (stageDirectory.exists() || stageDirectory.mkdirs()) {
214 processAppXml(appFile);
Jian Li97d6b2d2016-01-20 10:13:43 -0800215 processAppPng(iconFile);
Brian O'Connorbf7eca52015-04-15 16:25:46 -0700216 processFeaturesXml(featuresFile);
217 processArtifacts();
218 generateAppPackage();
219 } else {
220 throw new MojoExecutionException("Unable to create directory: " + stageDirectory);
221 }
Thomas Vachuskaa98ae7f2015-04-14 14:00:36 -0700222 }
223 }
224
225 // Loads the app.xml file.
226 private void loadAppFile(File appFile) throws MojoExecutionException {
227 XMLConfiguration xml = new XMLConfiguration();
228 xml.setRootElementName(APP);
229
230 try (FileInputStream stream = new FileInputStream(appFile)) {
231 xml.load(stream);
232 xml.setAttributeSplittingDisabled(true);
233 xml.setDelimiterParsingDisabled(true);
234
235 name = xml.getString(NAME);
236 version = eval(xml.getString(VERSION));
Thomas Vachuskaa98ae7f2015-04-14 14:00:36 -0700237 featuresRepo = eval(xml.getString(FEATURES_REPO));
238
239 artifacts = xml.configurationsAt(ARTIFACT).stream()
240 .map(cfg -> eval(cfg.getRootNode().getValue().toString()))
241 .collect(Collectors.toList());
242
243 } catch (ConfigurationException e) {
244 throw new MojoExecutionException("Unable to parse app.xml file", e);
245 } catch (FileNotFoundException e) {
246 throw new MojoExecutionException("Unable to find app.xml file", e);
247 } catch (IOException e) {
248 throw new MojoExecutionException("Unable to read app.xml file", e);
249 }
250 }
251
252 // Processes and stages the app.xml file.
253 private void processAppXml(File appFile) throws MojoExecutionException {
254 try {
255 File file = new File(stageDirectory, APP_XML);
256 forceMkdir(stageDirectory);
Thomas Vachuska586afd82015-04-17 11:06:53 -0700257 String contents;
258
259 if (appFile.exists()) {
260 contents = fileRead(appFile);
261 } else {
262 byte[] bytes = toByteArray(getClass().getResourceAsStream(APP_XML));
263 contents = new String(bytes);
264 }
265 fileWrite(file.getAbsolutePath(), eval(contents));
Thomas Vachuskaa98ae7f2015-04-14 14:00:36 -0700266 } catch (IOException e) {
267 throw new MojoExecutionException("Unable to process app.xml", e);
268 }
269 }
270
Jian Li97d6b2d2016-01-20 10:13:43 -0800271 // Stages the app.png file of a specific application.
272 private void processAppPng(File iconFile) throws MojoExecutionException {
273 try {
274 File stagedIconFile = new File(stageDirectory, APP_PNG);
275
276 if (iconFile.exists()) {
277 FileUtils.copyFile(iconFile, stagedIconFile);
278 }
279 } catch (IOException e) {
280 throw new MojoExecutionException("Unable to copy app.png", e);
281 }
282 }
283
Thomas Vachuskaa98ae7f2015-04-14 14:00:36 -0700284 private void processFeaturesXml(File featuresFile) throws MojoExecutionException {
285 boolean specified = featuresRepo != null && featuresRepo.length() > 0;
286
287 // If featuresRepo attribute is specified and there is a features.xml
288 // file present, add the features repo as an artifact
289 try {
290 if (specified && featuresFile.exists()) {
291 processFeaturesXml(new FileInputStream(featuresFile));
292 } else if (specified) {
293 processFeaturesXml(getClass().getResourceAsStream(FEATURES_XML));
294 }
295 } catch (FileNotFoundException e) {
296 throw new MojoExecutionException("Unable to find features.xml file", e);
297 } catch (IOException e) {
298 throw new MojoExecutionException("Unable to process features.xml file", e);
299 }
300 }
301
302 // Processes and stages the features.xml file.
303 private void processFeaturesXml(InputStream stream) throws IOException {
304 String featuresArtifact =
305 artifactFile(projectArtifactId, projectVersion, XML, "features");
306 File dstDir = new File(stageDirectory, projectPath);
307 forceMkdir(dstDir);
Thomas Vachuska586afd82015-04-17 11:06:53 -0700308 String s = eval(new String(toByteArray(stream)));
Thomas Vachuskaa98ae7f2015-04-14 14:00:36 -0700309 fileWrite(new File(dstDir, featuresArtifact).getAbsolutePath(), s);
310 }
311
312 // Stages all artifacts.
Thomas Vachuskaa7a02202015-04-14 23:13:02 -0700313 private void processArtifacts() throws MojoExecutionException {
314 for (String artifact : artifacts) {
315 processArtifact(artifact);
316 }
Thomas Vachuskaa98ae7f2015-04-14 14:00:36 -0700317 }
318
319 // Stages the specified artifact.
Thomas Vachuskaa7a02202015-04-14 23:13:02 -0700320 private void processArtifact(String artifact) throws MojoExecutionException {
Thomas Vachuskaa98ae7f2015-04-14 14:00:36 -0700321 if (!artifact.startsWith(MVN_URL)) {
Thomas Vachuskaa7a02202015-04-14 23:13:02 -0700322 throw new MojoExecutionException("Unsupported artifact URL:" + artifact);
Thomas Vachuskaa98ae7f2015-04-14 14:00:36 -0700323 }
324
325 String[] fields = artifact.substring(4).split("/");
326 if (fields.length < 3) {
Thomas Vachuskaa7a02202015-04-14 23:13:02 -0700327 throw new MojoExecutionException("Illegal artifact URL:" + artifact);
Thomas Vachuskaa98ae7f2015-04-14 14:00:36 -0700328 }
329
330 try {
331 String file = artifactFile(fields);
332
333 if (projectGroupId.equals(fields[0]) && projectArtifactId.equals(fields[1])) {
334 // Local artifact is not installed yet, package it from target directory.
335 File dstDir = new File(stageDirectory, projectPath);
336 forceMkdir(dstDir);
337 copyFile(new File(dstDirectory, file), new File(dstDir, file));
338 } else {
339 // Other artifacts are packaged from ~/.m2/repository directory.
340 String m2Path = artifactDir(fields);
341 File srcDir = new File(m2Directory, m2Path);
Thomas Vachuskaa7a02202015-04-14 23:13:02 -0700342 File dstDir = new File(stageDirectory, M2_PREFIX + "/" + m2Path);
Thomas Vachuskaa98ae7f2015-04-14 14:00:36 -0700343 forceMkdir(dstDir);
344 copyFile(new File(srcDir, file), new File(dstDir, file));
345 }
346 } catch (IOException e) {
Thomas Vachuskaa7a02202015-04-14 23:13:02 -0700347 throw new MojoExecutionException("Unable to stage artifact " + artifact, e);
Thomas Vachuskaa98ae7f2015-04-14 14:00:36 -0700348 }
349 }
350
351 // Generates the ONOS package ZIP file.
352 private void generateAppPackage() throws MojoExecutionException {
353 File appZip = new File(dstDirectory, artifactFile(projectArtifactId, projectVersion,
Jian Lic35415d2016-01-14 17:22:31 -0800354 APP_ZIP, null));
Thomas Vachuskaa98ae7f2015-04-14 14:00:36 -0700355 try (FileOutputStream fos = new FileOutputStream(appZip);
356 ZipOutputStream zos = new ZipOutputStream(fos)) {
357 zipDirectory("", stageDirectory, zos);
358 projectHelper.attachArtifact(this.project, APP_ZIP, null, appZip);
359 } catch (IOException e) {
360 throw new MojoExecutionException("Unable to compress application package", e);
361 }
362 }
363
364 // Generates artifact directory name from the specified fields.
365 private String artifactDir(String[] fields) {
366 return artifactDir(fields[0], fields[1], fields[2]);
367 }
368
369 // Generates artifact directory name from the specified elements.
370 private String artifactDir(String gid, String aid, String version) {
Sanjana Agarwalde50ee52016-07-12 14:05:18 -0700371 return gid.replace('.', '/') + "/" + aid + "/" + version;
Thomas Vachuskaa98ae7f2015-04-14 14:00:36 -0700372 }
373
374 // Generates artifact file name from the specified fields.
375 private String artifactFile(String[] fields) {
376 return fields.length < 5 ?
377 artifactFile(fields[1], fields[2],
Jian Lic35415d2016-01-14 17:22:31 -0800378 (fields.length < 4 ? JAR : fields[3]), null) :
Thomas Vachuskaa98ae7f2015-04-14 14:00:36 -0700379 artifactFile(fields[1], fields[2], fields[3], fields[4]);
380 }
381
382 // Generates artifact file name from the specified elements.
383 private String artifactFile(String aid, String version, String type,
384 String classifier) {
385 return classifier == null ? aid + "-" + version + "." + type :
386 aid + "-" + version + "-" + classifier + "." + type;
387 }
388
389 // Returns the given string with project variable substitutions.
390 private String eval(String string) {
391 return string == null ? null :
Thomas Vachuska586afd82015-04-17 11:06:53 -0700392 string.replaceAll("\\$\\{onos.app.name\\}", name)
393 .replaceAll("\\$\\{onos.app.origin\\}", origin)
Thomas Vachuska761f0042015-11-11 19:10:17 -0800394 .replaceAll("\\$\\{onos.app.requires\\}", requiredApps)
Jian Lic35415d2016-01-14 17:22:31 -0800395 .replaceAll("\\$\\{onos.app.category\\}", category)
Simon Huntafae2f72016-03-04 21:18:23 -0800396 .replaceAll("\\$\\{onos.app.title\\}", title)
Jian Lic35415d2016-01-14 17:22:31 -0800397 .replaceAll("\\$\\{onos.app.url\\}", url)
Thomas Vachuska586afd82015-04-17 11:06:53 -0700398 .replaceAll("\\$\\{project.groupId\\}", projectGroupId)
Thomas Vachuskaa98ae7f2015-04-14 14:00:36 -0700399 .replaceAll("\\$\\{project.artifactId\\}", projectArtifactId)
400 .replaceAll("\\$\\{project.version\\}", projectVersion)
Jian Li8bcb4f22016-01-20 10:36:18 -0800401 .replaceAll("\\$\\{project.description\\}", readme);
Thomas Vachuskaa98ae7f2015-04-14 14:00:36 -0700402 }
403
404 // Recursively archives the specified directory into a given ZIP stream.
405 private void zipDirectory(String root, File dir, ZipOutputStream zos)
406 throws IOException {
Thomas Vachuska41e8c182015-04-21 11:09:19 -0700407 byte[] buffer = new byte[BUFFER_SIZE];
Thomas Vachuskaa98ae7f2015-04-14 14:00:36 -0700408 File[] files = dir.listFiles();
409 if (files != null && files.length > 0) {
410 for (File file : files) {
411 if (file.isDirectory()) {
412 String path = root + file.getName() + "/";
413 zos.putNextEntry(new ZipEntry(path));
414 zipDirectory(path, file, zos);
415 zos.closeEntry();
416 } else {
417 FileInputStream fin = new FileInputStream(file);
418 zos.putNextEntry(new ZipEntry(root + file.getName()));
419 int length;
420 while ((length = fin.read(buffer)) > 0) {
421 zos.write(buffer, 0, length);
422 }
423 zos.closeEntry();
424 fin.close();
425 }
426 }
427 }
Thomas Vachuska8c8b0372015-03-10 11:11:24 -0700428 }
Jian Lic35415d2016-01-14 17:22:31 -0800429}