/*
* Copyright 2012, Oracle and/or its affiliates. All rights reserved.
*
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
package com.oracle.appbundler;
import java.io.BufferedOutputStream;
import java.io.BufferedWriter;
import java.io.File;
import java.io.FileOutputStream;
import java.io.FileWriter;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.io.Writer;
import java.net.URL;
import java.nio.file.Files;
import java.nio.file.LinkOption;
import java.nio.file.Path;
import java.nio.file.StandardCopyOption;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.zip.ZipEntry;
import java.util.zip.ZipInputStream;
import javax.xml.stream.XMLOutputFactory;
import javax.xml.stream.XMLStreamException;
import javax.xml.stream.XMLStreamWriter;
import org.apache.tools.ant.BuildException;
import org.apache.tools.ant.DirectoryScanner;
import org.apache.tools.ant.Task;
import org.apache.tools.ant.types.FileSet;
import org.apache.tools.ant.types.Reference;
import org.apache.tools.ant.types.resources.FileResource;
import org.w3c.dom.views.AbstractView;
/**
* App bundler Ant task.
*/
public class AppBundlerTask extends Task {
// Output folder for generated bundle
private File outputDirectory = null;
// General bundle properties
private String name = null;
private String displayName = null;
private String identifier = null;
private File icon = null;
private String executableName = EXECUTABLE_NAME;
private String shortVersion = "1.0";
private String version = "1.0";
private String signature = "????";
private String copyright = "";
private String privileged = null;
private String workingDirectory = null;
private String minimumSystemVersion = null;
private String applicationCategory = null;
private boolean highResolutionCapable = true;
private boolean supportsAutomaticGraphicsSwitching = true;
private boolean hideDockIcon = false;
// JVM info properties
private String mainClassName = null;
private String jnlpLauncherName = null;
private String jarLauncherName = null;
private FileSet runtime = null;
private ArrayList<FileSet> classPath = new ArrayList<>();
private ArrayList<FileSet> libraryPath = new ArrayList<>();
private ArrayList<Option> options = new ArrayList<>();
private ArrayList<String> arguments = new ArrayList<>();
private ArrayList<String> architectures = new ArrayList<>();
private ArrayList<String> registeredProtocols = new ArrayList<>();
private ArrayList<BundleDocument> bundleDocuments = new ArrayList<>();
private Reference classPathRef;
private static final String EXECUTABLE_NAME = "JavaAppLauncher";
private static final String DEFAULT_ICON_NAME = "GenericApp.icns";
private static final String OS_TYPE_CODE = "APPL";
private static final String PLIST_DTD = "<!DOCTYPE plist PUBLIC \"-//Apple//DTD PLIST 1.0//EN\" \"http://www.apple.com/DTDs/PropertyList-1.0.dtd\">";
private static final String PLIST_TAG = "plist";
private static final String PLIST_VERSION_ATTRIBUTE = "version";
private static final String DICT_TAG = "dict";
private static final String KEY_TAG = "key";
private static final String ARRAY_TAG = "array";
private static final String STRING_TAG = "string";
private static final int BUFFER_SIZE = 2048;
public void setOutputDirectory(File outputDirectory) {
this.outputDirectory = outputDirectory;
}
public void setName(String name) {
this.name = name;
}
public void setDisplayName(String displayName) {
this.displayName = displayName;
}
public void setIdentifier(String identifier) {
this.identifier = identifier;
}
public void setIcon(File icon) {
this.icon = icon;
}
public void setExecutableName(String executable) {
this.executableName = executable;
}
public void setShortVersion(String shortVersion) {
this.shortVersion = shortVersion;
}
public void setVersion(String version) {
this.version = version;
}
public void setSignature(String signature) {
this.signature = signature;
}
public void setCopyright(String copyright) {
this.copyright = copyright;
}
public void setPrivileged(String privileged) {
this.privileged = privileged;
}
public void setWorkingDirectory(String workingDirectory) {
this.workingDirectory = workingDirectory;
}
public void setMinimumSystemVersion(String v){
this.minimumSystemVersion = v;
}
public void setApplicationCategory(String applicationCategory) {
this.applicationCategory = applicationCategory;
}
public void setHighResolutionCapable(boolean highResolutionCapable) {
this.highResolutionCapable = highResolutionCapable;
}
public void setHideDockIcon(boolean hideDock) {
this.hideDockIcon = hideDock;
}
public void setSupportsAutomaticGraphicsSwitching(boolean supportsAutomaticGraphicsSwitching) {
this.supportsAutomaticGraphicsSwitching = supportsAutomaticGraphicsSwitching;
}
public void setMainClassName(String mainClassName) {
this.mainClassName = mainClassName;
}
public void setJnlpLauncherName(String jnlpLauncherName) {
this.jnlpLauncherName = jnlpLauncherName;
}
public void setJarLauncherName(String jarLauncherName) {
this.jarLauncherName = jarLauncherName;
}
public void addConfiguredRuntime(FileSet runtime) throws BuildException {
if (this.runtime != null) {
throw new BuildException("Runtime already specified.");
}
this.runtime = runtime;
// If Patterns are already set up, do not do again.
if ( runtime.hasPatterns() ) {
return;
}
runtime.appendIncludes(new String[] {
"jre/",
});
runtime.appendExcludes(new String[] {
"bin/",
"jre/bin/",
"jre/lib/deploy/",
"jre/lib/deploy.jar",
"jre/lib/javaws.jar",
"jre/lib/libdeploy.dylib",
"jre/lib/libnpjp2.dylib",
"jre/lib/plugin.jar",
"jre/lib/security/javaws.policy"
});
}
public void setClasspathRef(Reference ref) {
this.classPathRef = ref;
}
public void addConfiguredClassPath(FileSet classPath) {
this.classPath.add(classPath);
}
public void addConfiguredLibraryPath(FileSet libraryPath) {
this.libraryPath.add(libraryPath);
}
public void addConfiguredBundleDocument(BundleDocument document) {
this.bundleDocuments.add(document);
}
public void addConfiguredOption(Option option) throws BuildException {
String value = option.getValue();
if (value == null) {
throw new BuildException("Value is required.");
}
options.add(option);
}
public void addConfiguredArgument(Argument argument) throws BuildException {
String value = argument.getValue();
if (value == null) {
throw new BuildException("Value is required.");
}
arguments.add(value);
}
public void addConfiguredScheme(Argument argument) throws BuildException {
String value = argument.getValue();
if (value == null) {
throw new BuildException("Value is required.");
}
this.registeredProtocols.add(value);
}
public void addConfiguredArch(Architecture architecture) throws BuildException {
String name = architecture.getName();
if (name == null) {
throw new BuildException("Name is required.");
}
architectures.add(name);
}
public File getOutputDirectory() {
return outputDirectory;
}
public String getName() {
return name;
}
public String getDisplayName() {
return displayName;
}
public String getIdentifier() {
return identifier;
}
public File getIcon() {
return icon;
}
public String getExecutableName() {
return executableName;
}
public String getShortVersion() {
return shortVersion;
}
public String getVersion() {
return version;
}
public String getSignature() {
return signature;
}
public String getCopyright() {
return copyright;
}
public String getPrivileged() {
return privileged;
}
public String getWorkingDirectory() {
return workingDirectory;
}
public String getMinimumSystemVersion() {
return minimumSystemVersion;
}
public String getApplicationCategory() {
return applicationCategory;
}
public boolean isHighResolutionCapable() {
return highResolutionCapable;
}
public boolean isSupportsAutomaticGraphicsSwitching() {
return supportsAutomaticGraphicsSwitching;
}
public boolean isHideDockIcon() {
return hideDockIcon;
}
public String getMainClassName() {
return mainClassName;
}
public String getJnlpLauncherName() {
return jnlpLauncherName;
}
public String getJarLauncherName() {
return jarLauncherName;
}
public FileSet getRuntime() {
return runtime;
}
public ArrayList<FileSet> getClassPath() {
return classPath;
}
public ArrayList<FileSet> getLibraryPath() {
return libraryPath;
}
public ArrayList<Option> getOptions() {
return options;
}
public ArrayList<String> getArguments() {
return arguments;
}
public ArrayList<String> getArchitectures() {
return architectures;
}
public ArrayList<String> getRegisteredProtocols() {
return registeredProtocols;
}
public ArrayList<BundleDocument> getBundleDocuments() {
return bundleDocuments;
}
public Reference getClassPathRef() {
return classPathRef;
}
@Override
public void execute() throws BuildException {
// Validate required properties
if (outputDirectory == null) {
throw new IllegalStateException("Output directory is required.");
}
if (!outputDirectory.exists()) {
throw new IllegalStateException("Output directory does not exist.");
}
if (!outputDirectory.isDirectory()) {
throw new IllegalStateException("Invalid output directory.");
}
if (name == null) {
throw new IllegalStateException("Name is required.");
}
if (displayName == null) {
throw new IllegalStateException("Display name is required.");
}
if (identifier == null) {
throw new IllegalStateException("Identifier is required.");
}
if (icon != null) {
if (!icon.exists()) {
throw new IllegalStateException("Icon does not exist: " + icon);
}
if (icon.isDirectory()) {
throw new IllegalStateException("Invalid icon.");
}
}
if (shortVersion == null) {
throw new IllegalStateException("Short version is required.");
}
if (signature == null) {
throw new IllegalStateException("Signature is required.");
}
if (signature.length() != 4) {
throw new IllegalStateException("Invalid signature.");
}
if (copyright == null) {
throw new IllegalStateException("Copyright is required.");
}
if (jnlpLauncherName == null && mainClassName == null) {
throw new IllegalStateException("Main class name or JNLP launcher name is required.");
}
// Create the app bundle
try {
System.out.println("Creating app bundle: " + name);
// Create directory structure
File rootDirectory = new File(outputDirectory, name + ".app");
delete(rootDirectory);
rootDirectory.mkdir();
File contentsDirectory = new File(rootDirectory, "Contents");
contentsDirectory.mkdir();
File macOSDirectory = new File(contentsDirectory, "MacOS");
macOSDirectory.mkdir();
File javaDirectory = new File(contentsDirectory, "Java");
javaDirectory.mkdir();
File plugInsDirectory = new File(contentsDirectory, "PlugIns");
plugInsDirectory.mkdir();
File resourcesDirectory = new File(contentsDirectory, "Resources");
resourcesDirectory.mkdir();
// Generate Info.plist
File infoPlistFile = new File(contentsDirectory, "Info.plist");
infoPlistFile.createNewFile();
writeInfoPlist(infoPlistFile);
// Generate PkgInfo
File pkgInfoFile = new File(contentsDirectory, "PkgInfo");
pkgInfoFile.createNewFile();
writePkgInfo(pkgInfoFile);
// Copy executable to MacOS folder
File executableFile = new File(macOSDirectory, executableName);
copy(getClass().getResource(EXECUTABLE_NAME), executableFile);
executableFile.setExecutable(true, false);
// Copy localized resources to Resources folder
copyResources(resourcesDirectory);
// Copy runtime to PlugIns folder
copyRuntime(plugInsDirectory);
// Copy class path entries to Java folder
copyClassPathEntries(javaDirectory);
// Copy class path ref entries to Java folder
copyClassPathRefEntries(javaDirectory);
// Copy library path entries to MacOS folder
copyLibraryPathEntries(macOSDirectory);
// Copy icon to Resources folder
copyIcon(resourcesDirectory);
} catch (IOException exception) {
throw new BuildException(exception);
}
}
private void copyResources(File resourcesDirectory) throws IOException {
// Unzip res.zip into resources directory
InputStream inputStream = getClass().getResourceAsStream("res.zip");
ZipInputStream zipInputStream = new ZipInputStream(inputStream);
try {
ZipEntry zipEntry = zipInputStream.getNextEntry();
while (zipEntry != null) {
File file = new File(resourcesDirectory, zipEntry.getName());
if (zipEntry.isDirectory()) {
file.mkdir();
} else {
OutputStream outputStream = new BufferedOutputStream(new FileOutputStream(file), BUFFER_SIZE);
try {
int b = zipInputStream.read();
while (b != -1) {
outputStream.write(b);
b = zipInputStream.read();
}
outputStream.flush();
} finally {
outputStream.close();
}
}
zipEntry = zipInputStream.getNextEntry();
}
} finally {
zipInputStream.close();
}
}
private void copyRuntime(File plugInsDirectory) throws IOException {
if (runtime != null) {
File runtimeHomeDirectory = runtime.getDir();
File runtimeContentsDirectory = runtimeHomeDirectory.getParentFile();
File runtimeDirectory = runtimeContentsDirectory.getParentFile();
// Create root plug-in directory
File pluginDirectory = new File(plugInsDirectory, runtimeDirectory.getName());
pluginDirectory.mkdir();
// Create Contents directory
File pluginContentsDirectory = new File(pluginDirectory, runtimeContentsDirectory.getName());
pluginContentsDirectory.mkdir();
// Copy MacOS directory
File runtimeMacOSDirectory = new File(runtimeContentsDirectory, "MacOS");
copy(runtimeMacOSDirectory, new File(pluginContentsDirectory, runtimeMacOSDirectory.getName()));
// Copy Info.plist file
File runtimeInfoPlistFile = new File(runtimeContentsDirectory, "Info.plist");
copy(runtimeInfoPlistFile, new File(pluginContentsDirectory, runtimeInfoPlistFile.getName()));
// Copy included contents of Home directory
File pluginHomeDirectory = new File(pluginContentsDirectory, runtimeHomeDirectory.getName());
DirectoryScanner directoryScanner = runtime.getDirectoryScanner(getProject());
String[] includedFiles = directoryScanner.getIncludedFiles();
for (int i = 0; i < includedFiles.length; i++) {
String includedFile = includedFiles[i];
File source = new File(runtimeHomeDirectory, includedFile);
File destination = new File(pluginHomeDirectory, includedFile);
copy(source, destination);
}
}
}
private void copyClassPathRefEntries(File javaDirectory) throws IOException {
if(classPathRef != null) {
org.apache.tools.ant.types.Path classpath =
(org.apache.tools.ant.types.Path) classPathRef.getReferencedObject(getProject());
Iterator<FileResource> iter = (Iterator<FileResource>)(Object)classpath.iterator();
while(iter.hasNext()) {
FileResource resource = iter.next();
File source = resource.getFile();
File destination = new File(javaDirectory, source.getName());
copy(source, destination);
}
}
}
private void copyClassPathEntries(File javaDirectory) throws IOException {
for (FileSet fileSet : classPath) {
File classPathDirectory = fileSet.getDir();
DirectoryScanner directoryScanner = fileSet.getDirectoryScanner(getProject());
String[] includedFiles = directoryScanner.getIncludedFiles();
for (int i = 0; i < includedFiles.length; i++) {
String includedFile = includedFiles[i];
File source = new File(classPathDirectory, includedFile);
File destination = new File(javaDirectory, new File(includedFile).getName());
copy(source, destination);
}
}
}
private void copyLibraryPathEntries(File macOSDirectory) throws IOException {
for (FileSet fileSet : libraryPath) {
File libraryPathDirectory = fileSet.getDir();
DirectoryScanner directoryScanner = fileSet.getDirectoryScanner(getProject());
String[] includedFiles = directoryScanner.getIncludedFiles();
for (int i = 0; i < includedFiles.length; i++) {
String includedFile = includedFiles[i];
File source = new File(libraryPathDirectory, includedFile);
File destination = new File(macOSDirectory, new File(includedFile).getName());
copy(source, destination);
}
}
}
private void copyIcon(File resourcesDirectory) throws IOException {
if (icon == null) {
copy(getClass().getResource(DEFAULT_ICON_NAME), new File(resourcesDirectory, DEFAULT_ICON_NAME));
} else {
copy(icon, new File(resourcesDirectory, icon.getName()));
}
}
private void writeInfoPlist(File file) throws IOException {
Writer out = new BufferedWriter(new FileWriter(file));
XMLOutputFactory output = XMLOutputFactory.newInstance();
try {
XMLStreamWriter xout = output.createXMLStreamWriter(out);
// Write XML declaration
xout.writeStartDocument();
xout.writeCharacters("\n");
// Write plist DTD declaration
xout.writeDTD(PLIST_DTD);
xout.writeCharacters("\n");
// Begin root element
xout.writeStartElement(PLIST_TAG);
xout.writeAttribute(PLIST_VERSION_ATTRIBUTE, "1.0");
xout.writeCharacters("\n");
// Begin root dictionary
xout.writeStartElement(DICT_TAG);
xout.writeCharacters("\n");
// Write bundle properties
writeProperty(xout, "CFBundleDevelopmentRegion", "English");
writeProperty(xout, "CFBundleExecutable", executableName);
writeProperty(xout, "CFBundleIconFile", (icon == null) ? DEFAULT_ICON_NAME : icon.getName());
writeProperty(xout, "CFBundleIdentifier", identifier);
writeProperty(xout, "CFBundleDisplayName", displayName);
writeProperty(xout, "CFBundleInfoDictionaryVersion", "6.0");
writeProperty(xout, "CFBundleName", name);
writeProperty(xout, "CFBundlePackageType", OS_TYPE_CODE);
writeProperty(xout, "CFBundleShortVersionString", shortVersion);
writeProperty(xout, "CFBundleVersion", version);
writeProperty(xout, "CFBundleSignature", signature);
writeProperty(xout, "NSHumanReadableCopyright", copyright);
if ( minimumSystemVersion != null ){
writeProperty(xout, "LSMinimumSystemVersion", minimumSystemVersion);
}
if (applicationCategory != null) {
writeProperty(xout, "LSApplicationCategoryType", applicationCategory);
}
if(hideDockIcon){
writeKey(xout, "LSUIElement");
writeBoolean(xout, true);
xout.writeCharacters("\n");
}
if (highResolutionCapable) {
writeKey(xout, "NSHighResolutionCapable");
writeBoolean(xout, true);
xout.writeCharacters("\n");
}
if (supportsAutomaticGraphicsSwitching) {
writeKey(xout, "NSSupportsAutomaticGraphicsSwitching");
writeBoolean(xout, true);
xout.writeCharacters("\n");
}
if(registeredProtocols.size() > 0){
writeKey(xout, "CFBundleURLTypes");
xout.writeStartElement(ARRAY_TAG);
xout.writeCharacters("\n");
xout.writeStartElement(DICT_TAG);
xout.writeCharacters("\n");
writeProperty(xout, "CFBundleURLName", identifier);
writeKey(xout, "CFBundleURLSchemes");
xout.writeStartElement(ARRAY_TAG);
xout.writeCharacters("\n");
for(String scheme:registeredProtocols){
writeString(xout, scheme);
}
xout.writeEndElement();
xout.writeCharacters("\n");
xout.writeEndElement();
xout.writeCharacters("\n");
xout.writeEndElement();
xout.writeCharacters("\n");
}
// Write runtime
if (runtime != null) {
writeProperty(xout, "JVMRuntime", runtime.getDir().getParentFile().getParentFile().getName());
}
if ( privileged != null ) {
writeProperty(xout, "JVMRunPrivileged", privileged);
}
if ( workingDirectory != null ) {
writeProperty(xout, "WorkingDirectory", workingDirectory);
}
if ( jnlpLauncherName != null ) {
// Write jnlp launcher name
writeProperty(xout, "JVMJNLPLauncher", jnlpLauncherName);
} else {
// Write main class name
writeProperty(xout, "JVMMainClassName", mainClassName);
}
if ( jarLauncherName != null ) {
writeProperty(xout, "JVMJARLauncher", jarLauncherName);
}
// Write CFBundleDocument entries
writeKey(xout, "CFBundleDocumentTypes");
xout.writeStartElement(ARRAY_TAG);
xout.writeCharacters("\n");
for(BundleDocument bundleDocument: bundleDocuments) {
xout.writeStartElement(DICT_TAG);
xout.writeCharacters("\n");
writeKey(xout, "CFBundleTypeExtensions");
xout.writeStartElement(ARRAY_TAG);
xout.writeCharacters("\n");
for(String extension : bundleDocument.getExtensions()) {
writeString(xout, extension);
}
xout.writeEndElement();
xout.writeCharacters("\n");
if(bundleDocument.hasIcon()) {
writeKey(xout, "CFBundleTypeIconFile");
writeString(xout, bundleDocument.getIcon());
}
writeKey(xout, "CFBundleTypeName");
writeString(xout, bundleDocument.getName());
writeKey(xout, "CFBundleTypeRole");
writeString(xout, bundleDocument.getRole());
writeKey(xout, "LSTypeIsPackage");
writeBoolean(xout, bundleDocument.isPackage());
xout.writeEndElement();
xout.writeCharacters("\n");
}
xout.writeEndElement();
xout.writeCharacters("\n");
// Write architectures
writeKey(xout, "LSArchitecturePriority");
xout.writeStartElement(ARRAY_TAG);
xout.writeCharacters("\n");
for (String architecture : architectures) {
writeString(xout, architecture);
}
xout.writeEndElement();
xout.writeCharacters("\n");
// Write Environment
writeKey(xout, "LSEnvironment");
xout.writeStartElement(DICT_TAG);
xout.writeCharacters("\n");
writeKey(xout, "LC_CTYPE");
writeString(xout, "UTF-8");
xout.writeEndElement();
xout.writeCharacters("\n");
// Write options
writeKey(xout, "JVMOptions");
xout.writeStartElement(ARRAY_TAG);
xout.writeCharacters("\n");
for (Option option : options) {
if (option.getName() == null) writeString(xout, option.getValue());
}
xout.writeEndElement();
xout.writeCharacters("\n");
// Write default options
writeKey(xout, "JVMDefaultOptions");
xout.writeStartElement(DICT_TAG);
xout.writeCharacters("\n");
for (Option option : options) {
if (option.getName() != null) {
writeKey(xout, option.getName());
writeString(xout, option.getValue());
}
}
xout.writeEndElement();
xout.writeCharacters("\n");
// Write arguments
writeKey(xout, "JVMArguments");
xout.writeStartElement(ARRAY_TAG);
xout.writeCharacters("\n");
for (String argument : arguments) {
writeString(xout, argument);
}
xout.writeEndElement();
xout.writeCharacters("\n");
// End root dictionary
xout.writeEndElement();
xout.writeCharacters("\n");
// End root element
xout.writeEndElement();
xout.writeCharacters("\n");
// Close document
xout.writeEndDocument();
xout.writeCharacters("\n");
out.flush();
} catch (XMLStreamException exception) {
throw new IOException(exception);
} finally {
out.close();
}
}
private void writeKey(XMLStreamWriter xout, String key) throws XMLStreamException {
xout.writeStartElement(KEY_TAG);
xout.writeCharacters(key);
xout.writeEndElement();
xout.writeCharacters("\n");
}
private void writeString(XMLStreamWriter xout, String value) throws XMLStreamException {
xout.writeStartElement(STRING_TAG);
xout.writeCharacters(value);
xout.writeEndElement();
xout.writeCharacters("\n");
}
private void writeBoolean(XMLStreamWriter xout, boolean value) throws XMLStreamException {
xout.writeEmptyElement(value ? "true" : "false");
}
private void writeProperty(XMLStreamWriter xout, String key, String value) throws XMLStreamException {
writeKey(xout, key);
writeString(xout, value);
}
private void writePkgInfo(File file) throws IOException {
Writer out = new BufferedWriter(new FileWriter(file));
try {
out.write(OS_TYPE_CODE + signature);
out.flush();
} finally {
out.close();
}
}
private static void delete(File file) throws IOException {
Path filePath = file.toPath();
if (Files.exists(filePath, LinkOption.NOFOLLOW_LINKS)) {
if (Files.isDirectory(filePath, LinkOption.NOFOLLOW_LINKS)) {
File[] files = file.listFiles();
for (int i = 0; i < files.length; i++) {
delete(files[i]);
}
}
Files.delete(filePath);
}
}
private static void copy(URL location, File file) throws IOException {
try (InputStream in = location.openStream()) {
Files.copy(in, file.toPath(), StandardCopyOption.REPLACE_EXISTING);
}
}
private static void copy(File source, File destination) throws IOException {
Path sourcePath = source.toPath();
Path destinationPath = destination.toPath();
destination.getParentFile().mkdirs();
Files.copy(sourcePath, destinationPath, StandardCopyOption.REPLACE_EXISTING /*, LinkOption.NOFOLLOW_LINKS*/ );
if (Files.isDirectory(sourcePath, LinkOption.NOFOLLOW_LINKS)) {
String[] files = source.list();
for (int i = 0; i < files.length; i++) {
String file = files[i];
copy(new File(source, file), new File(destination, file));
}
}
}
}