blob: ba153d0840805008e436464d9687cbef1412f579 [file] [log] [blame]
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
package org.apache.accumulo.classloader.vfs;
import java.io.File;
import java.io.IOException;
import java.lang.management.ManagementFactory;
import java.lang.ref.WeakReference;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import org.apache.commons.io.FileUtils;
import org.apache.commons.vfs2.CacheStrategy;
import org.apache.commons.vfs2.FileObject;
import org.apache.commons.vfs2.FileSystemException;
import org.apache.commons.vfs2.FileSystemManager;
import org.apache.commons.vfs2.FileType;
import org.apache.commons.vfs2.cache.SoftRefFilesCache;
import org.apache.commons.vfs2.impl.DefaultFileSystemManager;
import org.apache.commons.vfs2.impl.FileContentInfoFilenameFactory;
import org.apache.commons.vfs2.provider.FileReplicator;
import org.apache.commons.vfs2.provider.hdfs.HdfsFileProvider;
import edu.umd.cs.findbugs.annotations.SuppressFBWarnings;
public class VFSManager {
public static class AccumuloVFSManagerShutdownThread implements Runnable {
@Override
public void run() {
try {
VFSManager.close();
} catch (Exception e) {
// do nothing, we are shutting down anyway
}
}
}
private static List<WeakReference<DefaultFileSystemManager>> vfsInstances =
Collections.synchronizedList(new ArrayList<>());
private static volatile boolean DEBUG = false;
static void enableDebug() {
DEBUG = true;
}
static {
// Register the shutdown hook
Runtime.getRuntime().addShutdownHook(new Thread(new AccumuloVFSManagerShutdownThread()));
}
public static FileObject[] resolve(FileSystemManager vfs, String uris)
throws FileSystemException {
return resolve(vfs, uris, new ArrayList<>());
}
static FileObject[] resolve(FileSystemManager vfs, String uris,
ArrayList<FileObject> pathsToMonitor) throws FileSystemException {
if (uris == null) {
return new FileObject[0];
}
ArrayList<FileObject> classpath = new ArrayList<>();
pathsToMonitor.clear();
for (String path : uris.split(",")) {
path = path.trim();
if (path.equals("")) {
continue;
}
path = ReloadingVFSClassLoader.replaceEnvVars(path, System.getenv());
FileObject fo = vfs.resolveFile(path);
switch (fo.getType()) {
case FILE:
case FOLDER:
classpath.add(fo);
pathsToMonitor.add(fo);
break;
case IMAGINARY:
// assume its a pattern
String pattern = fo.getName().getBaseName();
if (fo.getParent() != null) {
// still monitor the parent
pathsToMonitor.add(fo.getParent());
if (fo.getParent().getType() == FileType.FOLDER) {
FileObject[] children = fo.getParent().getChildren();
for (FileObject child : children) {
if (child.getType() == FileType.FILE
&& child.getName().getBaseName().matches(pattern)) {
classpath.add(child);
}
}
} else {
if (DEBUG)
System.out.println("classpath entry " + fo.getParent().toString() + " is "
+ fo.getParent().getType().toString());
}
} else {
if (DEBUG)
System.out.println("ignoring classpath entry: " + fo.toString());
}
break;
default:
System.out.println("ignoring classpath entry: " + fo.toString());
break;
}
}
return classpath.toArray(new FileObject[classpath.size()]);
}
public static DefaultFileSystemManager generateVfs() throws FileSystemException {
DefaultFileSystemManager vfs = new DefaultFileSystemManager();
vfs.addProvider("res", new org.apache.commons.vfs2.provider.res.ResourceFileProvider());
vfs.addProvider("zip", new org.apache.commons.vfs2.provider.zip.ZipFileProvider());
vfs.addProvider("gz", new org.apache.commons.vfs2.provider.gzip.GzipFileProvider());
vfs.addProvider("ram", new org.apache.commons.vfs2.provider.ram.RamFileProvider());
vfs.addProvider("file", new org.apache.commons.vfs2.provider.local.DefaultLocalFileProvider());
vfs.addProvider("jar", new org.apache.commons.vfs2.provider.jar.JarFileProvider());
vfs.addProvider("http", new org.apache.commons.vfs2.provider.http.HttpFileProvider());
vfs.addProvider("https", new org.apache.commons.vfs2.provider.https.HttpsFileProvider());
vfs.addProvider("ftp", new org.apache.commons.vfs2.provider.ftp.FtpFileProvider());
vfs.addProvider("ftps", new org.apache.commons.vfs2.provider.ftps.FtpsFileProvider());
vfs.addProvider("war", new org.apache.commons.vfs2.provider.jar.JarFileProvider());
vfs.addProvider("par", new org.apache.commons.vfs2.provider.jar.JarFileProvider());
vfs.addProvider("ear", new org.apache.commons.vfs2.provider.jar.JarFileProvider());
vfs.addProvider("sar", new org.apache.commons.vfs2.provider.jar.JarFileProvider());
vfs.addProvider("ejb3", new org.apache.commons.vfs2.provider.jar.JarFileProvider());
vfs.addProvider("tmp", new org.apache.commons.vfs2.provider.temp.TemporaryFileProvider());
vfs.addProvider("tar", new org.apache.commons.vfs2.provider.tar.TarFileProvider());
vfs.addProvider("tbz2", new org.apache.commons.vfs2.provider.tar.TarFileProvider());
vfs.addProvider("tgz", new org.apache.commons.vfs2.provider.tar.TarFileProvider());
vfs.addProvider("bz2", new org.apache.commons.vfs2.provider.bzip2.Bzip2FileProvider());
vfs.addProvider("hdfs", new HdfsFileProvider());
vfs.addExtensionMap("jar", "jar");
vfs.addExtensionMap("zip", "zip");
vfs.addExtensionMap("gz", "gz");
vfs.addExtensionMap("tar", "tar");
vfs.addExtensionMap("tbz2", "tar");
vfs.addExtensionMap("tgz", "tar");
vfs.addExtensionMap("bz2", "bz2");
vfs.addMimeTypeMap("application/x-tar", "tar");
vfs.addMimeTypeMap("application/x-gzip", "gz");
vfs.addMimeTypeMap("application/zip", "zip");
vfs.setFileContentInfoFactory(new FileContentInfoFilenameFactory());
vfs.setFilesCache(new SoftRefFilesCache());
File cacheDir = computeTopCacheDir();
vfs.setReplicator(new UniqueFileReplicator(cacheDir));
vfs.setCacheStrategy(CacheStrategy.ON_RESOLVE);
vfs.init();
vfsInstances.add(new WeakReference<>(vfs));
return vfs;
}
@SuppressFBWarnings(value = "PATH_TRAVERSAL_IN",
justification = "tmpdir is controlled by admin, not unchecked user input")
private static File computeTopCacheDir() {
String cacheDirPath = ReloadingVFSClassLoader.getVFSCacheDir();
String procName = ManagementFactory.getRuntimeMXBean().getName();
return new File(cacheDirPath,
"accumulo-vfs-manager-cache-" + procName + "-" + System.getProperty("user.name", "nouser"));
}
public static void returnVfs(DefaultFileSystemManager vfs) {
if (DEBUG) {
System.out.println("Closing VFS instance.");
}
FileReplicator replicator;
try {
replicator = vfs.getReplicator();
if (replicator instanceof UniqueFileReplicator) {
((UniqueFileReplicator) replicator).close();
}
} catch (FileSystemException e) {
System.err.println("Error occurred closing VFS instance: " + e.getMessage());
}
vfs.close();
}
public static void close() {
for (WeakReference<DefaultFileSystemManager> vfsInstance : vfsInstances) {
DefaultFileSystemManager ref = vfsInstance.get();
if (ref != null) {
returnVfs(ref);
}
}
try {
FileUtils.deleteDirectory(computeTopCacheDir());
} catch (IOException e) {
System.err.println("IOException deleting cache directory");
e.printStackTrace();
}
}
}