123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234 |
- /*
- * Copyright (c) 2006-2017 DMDirc Developers
- *
- * Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated
- * documentation files (the "Software"), to deal in the Software without restriction, including without limitation the
- * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to
- * permit persons to whom the Software is furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in all copies or substantial portions of the
- * Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE
- * WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS
- * OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
- * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
- */
-
- package com.dmdirc.util.io;
-
- import java.io.IOException;
- import java.net.URI;
- import java.net.URISyntaxException;
- import java.net.URL;
- import java.nio.file.CopyOption;
- import java.nio.file.DirectoryStream;
- import java.nio.file.FileSystem;
- import java.nio.file.FileSystems;
- import java.nio.file.Files;
- import java.nio.file.Path;
- import java.nio.file.Paths;
- import java.nio.file.StandardCopyOption;
- import java.security.CodeSource;
- import java.security.ProtectionDomain;
- import java.util.HashMap;
- import java.util.Map;
- import java.util.Optional;
-
- /**
- * Utility class to deal with files.
- */
- public final class FileUtils {
-
- private static final Optional<FileSystem> JAR_FILE_SYSTEM = getJarFileSystem();
-
- private FileUtils() {
- // Shouldn't be instansiated.
- }
-
- private static Optional<FileSystem> getJarFileSystem() {
- if (isRunningFromJar(FileUtils.class)) {
- try {
- final FileSystem fs = FileSystems.newFileSystem(
- getApplicationPath(FileUtils.class), null);
- return Optional.of(fs);
- } catch (IOException ex) {
- return Optional.empty();
- }
- } else {
- return Optional.empty();
- }
- }
-
- /**
- * Checks whether this application has been run from a jar or not.
- *
- * @param clazz Class used to locate the application
- *
- * @return true if the application was launched from a jar, false otherwise
- *
- * @throws IllegalStateException If the application path cannot be determined for any reason
- */
- public static boolean isRunningFromJar(final Class<?> clazz) throws IllegalStateException {
- // If we're running from any kind of regular file, assume it's a jar.
- return Files.isRegularFile(getApplicationPath(clazz));
- }
-
- /**
- * Returns the base location for the specified class, this is either the a jar or a folder
- * depending on how the application was launched.
- *
- * This can fail for a number of reasons, it is not wholly reliable.
- *
- * @param clazz Class used to locate the application
- *
- * @return A {@link Path} to application location
- *
- * @throws IllegalStateException If the application path cannot be determined for any reason
- */
- public static Path getApplicationPath(final Class<?> clazz) throws IllegalStateException {
- final ProtectionDomain pd;
- try {
- pd = clazz.getProtectionDomain();
- } catch (SecurityException ex) {
- throw new IllegalStateException("Unable to get protection domain", ex);
- }
- final CodeSource cs = pd.getCodeSource();
- if (cs == null) {
- throw new IllegalStateException("Unable to get the code source");
- }
- final URI uri;
- try {
- uri = cs.getLocation().toURI();
- } catch (URISyntaxException ex) {
- throw new IllegalStateException("Unable to convert location to URI", ex);
- }
- return Paths.get(uri);
- }
-
- /**
- * Recursively copies the resources specified by the given URL to the destination folder.
- * Existing files will be replaced.
- *
- * @param source The resource to be copied (file or folder).
- * @param destination The destination folder to copy the resource to.
- * @throws IOException If the resource couldn't be copied.
- */
- public static void copyResourcesContents(final URL source, final Path destination)
- throws IOException {
- doCopyResources(source, destination, true);
- }
-
- /**
- * Recursively copies the resources specified by the given URL to the destination folder.
- * Existing files will be replaced.
- *
- * @param source The resource to be copied (file or folder).
- * @param destination The destination folder to copy the resource to.
- * @throws IOException If the resource couldn't be copied.
- */
- public static void copyResources(final URL source, final Path destination) throws IOException {
- doCopyResources(source, destination, false);
- }
-
- private static void doCopyResources(final URL source, final Path destination,
- final boolean contents) throws IOException {
- try {
- final String path = source.toURI().toString();
- final int index = path.indexOf("!/");
- if (index > -1) {
- final String file = path.substring(0, index);
- final Map<String, String> env = new HashMap<>();
- try (final FileSystem fs = FileSystems.newFileSystem(URI.create(file), env)) {
- doCopyRecursively(fs.getPath(path.substring(index + 2)), destination, contents,
- StandardCopyOption.REPLACE_EXISTING);
- }
- } else {
- doCopyRecursively(Paths.get(source.toURI()), destination, contents,
- StandardCopyOption.REPLACE_EXISTING);
- }
- } catch (URISyntaxException ex) {
- throw new IOException("Unable to get source URI", ex);
- }
- }
-
- /**
- * Returns a {@link Path} for the specified bundled resource. If the app is running from a jar,
- * the resource will be backed by a Zip file system.
- *
- * @param resource The resource to get a path for
- * @return The path for the specified resource
- * @throws URISyntaxException If the resource could not be mapped to a path
- * @deprecated This doesn't and can't work reliably in all cases, and should be avoided.
- */
- @Deprecated
- public static Path getPathForResource(final URL resource) throws URISyntaxException {
- if (JAR_FILE_SYSTEM.isPresent()) {
- final String path = resource.toURI().toString();
- final int index = path.indexOf("!/");
- if (index > -1) {
- return JAR_FILE_SYSTEM.get().getPath(path.substring(index + 1));
- }
-
- // If we're running inside an OSGI framework then the classloader returns bundleresource:// URIs.
- // We don't have a filesystem handler for those, so instead map them on to the jar file system.
- // [This is hacky and horrible. It assumes that we only have one bundle, and that this class
- // is located in the same bundle as all of its callers.]
- if (path.startsWith("bundleresource://")) {
- return JAR_FILE_SYSTEM.get().getPath(path.substring(path.indexOf("/", 19)));
- }
- }
-
- return Paths.get(resource.toURI());
- }
-
- /**
- * Recursively copies the contents of one path to another. Once complete, a deep copy of the
- * source file or folder will be present in the destination directory.
- *
- * @param source The path that should be copied.
- * @param destination The directory to place copied files in.
- * @param options Options to use when copying.
- * @throws IOException If any files couldn't be copied.
- */
- public static void copyRecursivelyContents(final Path source, final Path destination,
- final CopyOption... options) throws IOException {
- doCopyRecursively(source, destination, true, options);
- }
-
- /**
- * Recursively copies one path to another. Once complete, a deep copy of the source file or
- * folder will be present in the destination directory.
- *
- * @param source The path that should be copied.
- * @param destination The directory to place copied files in.
- * @param options Options to use when copying.
- * @throws IOException If any files couldn't be copied.
- */
- public static void copyRecursively(final Path source, final Path destination,
- final CopyOption... options) throws IOException {
- doCopyRecursively(source, destination, false, options);
- }
-
- private static void doCopyRecursively(final Path source, final Path destination,
- final boolean contents, final CopyOption... options) throws IOException {
- final Path destinationPath;
- if (contents) {
- destinationPath = destination;
- } else {
- destinationPath = destination.resolve(source.getFileName().toString());
- }
-
- if (Files.isDirectory(source)) {
- Files.createDirectories(destinationPath);
- try (DirectoryStream<Path> directoryStream = Files.newDirectoryStream(source)) {
- for (Path path : directoryStream) {
- copyRecursively(path, destinationPath, options);
- }
- }
- } else {
- Files.copy(source, destinationPath, options);
- }
- }
-
- }
|