001/* 002 * Licensed to the Apache Software Foundation (ASF) under one 003 * or more contributor license agreements. See the NOTICE file 004 * distributed with this work for additional information 005 * regarding copyright ownership. The ASF licenses this file 006 * to you under the Apache License, Version 2.0 (the 007 * "License"); you may not use this file except in compliance 008 * with the License. You may obtain a copy of the License at 009 * 010 * http://www.apache.org/licenses/LICENSE-2.0 011 * 012 * Unless required by applicable law or agreed to in writing, 013 * software distributed under the License is distributed on an 014 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 015 * KIND, either express or implied. See the License for the 016 * specific language governing permissions and limitations 017 * under the License. 018 */ 019package org.apache.reef.util; 020 021import org.apache.commons.compress.utils.IOUtils; 022 023import java.io.*; 024import java.util.jar.JarEntry; 025import java.util.jar.JarOutputStream; 026import java.util.jar.Manifest; 027import java.util.logging.Level; 028import java.util.logging.Logger; 029 030/** 031 * Helper class to create JAR files. 032 */ 033public class JARFileMaker implements AutoCloseable { 034 035 private static final Logger LOG = Logger.getLogger(JARFileMaker.class.getName()); 036 037 private final FileOutputStream fileOutputStream; 038 private final JarOutputStream jarOutputStream; 039 private String relativeStartCanonicalPath = null; 040 041 public JARFileMaker(final File outputFile, final Manifest manifest) throws IOException { 042 this.fileOutputStream = new FileOutputStream(outputFile); 043 this.jarOutputStream = new JarOutputStream(this.fileOutputStream, manifest); 044 } 045 046 public JARFileMaker(final File outputFile) throws IOException { 047 this.fileOutputStream = new FileOutputStream(outputFile); 048 this.jarOutputStream = new JarOutputStream(this.fileOutputStream); 049 } 050 051 /** 052 * Adds a file to the JAR. If inputFile is a folder, it will be added recursively. 053 * 054 * @param inputFile 055 * @throws IOException 056 */ 057 public JARFileMaker add(final File inputFile) throws IOException { 058 059 final String fileNameInJAR = makeRelative(inputFile); 060 if (inputFile.isDirectory()) { 061 final JarEntry entry = new JarEntry(fileNameInJAR); 062 entry.setTime(inputFile.lastModified()); 063 this.jarOutputStream.putNextEntry(entry); 064 this.jarOutputStream.closeEntry(); 065 final File[] files = inputFile.listFiles(); 066 if (files != null) { 067 for (final File nestedFile : files) { 068 add(nestedFile); 069 } 070 } 071 return this; 072 } 073 074 final JarEntry entry = new JarEntry(fileNameInJAR); 075 entry.setTime(inputFile.lastModified()); 076 this.jarOutputStream.putNextEntry(entry); 077 try (final BufferedInputStream in = new BufferedInputStream(new FileInputStream(inputFile))) { 078 IOUtils.copy(in, this.jarOutputStream); 079 this.jarOutputStream.closeEntry(); 080 } catch (final FileNotFoundException ex) { 081 LOG.log(Level.WARNING, "Skip the file: " + inputFile, ex); 082 } 083 return this; 084 } 085 086 public JARFileMaker addChildren(final File folder) throws IOException { 087 this.relativeStartCanonicalPath = folder.getCanonicalPath(); 088 final File[] files = folder.listFiles(); 089 if (files != null) { 090 for (final File f : files) { 091 this.add(f); 092 } 093 } 094 this.relativeStartCanonicalPath = null; 095 return this; 096 } 097 098 private String makeRelative(final File input) throws IOException { 099 final String result; 100 if (this.relativeStartCanonicalPath == null) { 101 result = input.getCanonicalPath(); 102 } else { 103 result = input.getCanonicalPath() 104 .replace(this.relativeStartCanonicalPath, "") // Drop the absolute prefix 105 .substring(1); // drop the '/' at the beginning 106 } 107 if (input.isDirectory()) { 108 return result.replace("\\", "/") + "/"; 109 } else { 110 return result.replace("\\", "/"); 111 } 112 113 } 114 115 @Override 116 public void close() throws IOException { 117 this.jarOutputStream.close(); 118 this.fileOutputStream.close(); 119 } 120}