package hudson.plugins.tfs.model;
import com.microsoft.tfs.core.persistence.FilesystemPersistenceStore;
import com.microsoft.tfs.core.persistence.PersistenceStore;
import com.microsoft.tfs.core.persistence.VersionedVendorFilesystemPersistenceStore;
import org.apache.commons.io.IOUtils;
import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.util.Arrays;
import java.util.Comparator;
import java.util.List;
import java.util.TreeMap;
public class NativeLibraryManager implements NativeLibraryExtractor {
private static final String VENDOR_NAME = "Microsoft";
private static final String TFS_SDK = "TFS_SDK";
private static final String VERSION = "14.0.1";
private static final String nativeFolderPropertyName = "com.microsoft.tfs.jni.native.base-directory";
private static final String NATIVE = "native";
private static final Class<NativeLibraryManager> metaClass = NativeLibraryManager.class;
private static final TreeMap<String, TreeMap<String, List<String>>> NATIVE_LIBRARIES =
new TreeMap<String, TreeMap<String, List<String>>>();
static {
final TreeMap<String, List<String>> aix = new TreeMap<String, List<String>>();
final List<String> aix_ppc = Arrays.asList(
"libnative_auth.a",
"libnative_console.a",
"libnative_filesystem.a",
"libnative_misc.a",
"libnative_synchronization.a"
);
aix.put("ppc", aix_ppc);
NATIVE_LIBRARIES.put("aix", aix);
final TreeMap<String, List<String>> freebsd = new TreeMap<String, List<String>>();
final List<String> freebsd_x86 = Arrays.asList(
"libnative_auth.so",
"libnative_console.so",
"libnative_filesystem.so",
"libnative_misc.so",
"libnative_synchronization.so"
);
freebsd.put("x86", freebsd_x86);
final List<String> freebsd_x86_64 = Arrays.asList(
"libnative_auth.so",
"libnative_console.so",
"libnative_filesystem.so",
"libnative_misc.so",
"libnative_synchronization.so"
);
freebsd.put("x86_64", freebsd_x86_64);
NATIVE_LIBRARIES.put("freebsd", freebsd);
final TreeMap<String, List<String>> hpux = new TreeMap<String, List<String>>();
final List<String> hpux_ia64_32 = Arrays.asList(
"libnative_auth.so",
"libnative_console.so",
"libnative_filesystem.so",
"libnative_misc.so",
"libnative_synchronization.so"
);
hpux.put("ia64_32", hpux_ia64_32);
final List<String> hpux_PA_RISC = Arrays.asList(
"libnative_auth.sl",
"libnative_console.sl",
"libnative_filesystem.sl",
"libnative_misc.sl",
"libnative_synchronization.sl"
);
hpux.put("PA_RISC", hpux_PA_RISC);
NATIVE_LIBRARIES.put("hpux", hpux);
final TreeMap<String, List<String>> linux = new TreeMap<String, List<String>>();
final List<String> linux_arm = Arrays.asList(
"libnative_auth.so",
"libnative_console.so",
"libnative_filesystem.so",
"libnative_misc.so",
"libnative_synchronization.so"
);
linux.put("arm", linux_arm);
final List<String> linux_ppc = Arrays.asList(
"libnative_auth.so",
"libnative_console.so",
"libnative_filesystem.so",
"libnative_misc.so",
"libnative_synchronization.so"
);
linux.put("ppc", linux_ppc);
final List<String> linux_x86 = Arrays.asList(
"libnative_auth.so",
"libnative_console.so",
"libnative_filesystem.so",
"libnative_misc.so",
"libnative_synchronization.so"
);
linux.put("x86", linux_x86);
final List<String> linux_x86_64 = Arrays.asList(
"libnative_auth.so",
"libnative_console.so",
"libnative_filesystem.so",
"libnative_misc.so",
"libnative_synchronization.so"
);
linux.put("x86_64", linux_x86_64);
NATIVE_LIBRARIES.put("linux", linux);
final TreeMap<String, List<String>> macosx = new TreeMap<String, List<String>>(new Comparator<String>() {
@SuppressWarnings("ComparatorMethodParameterNotUsed" /* because of null key */)
public int compare(final String o1, final String o2) {
return 0;
}
});
final List<String> macosx_universal = Arrays.asList(
"libnative_auth.jnilib",
"libnative_console.jnilib",
"libnative_filesystem.jnilib",
"libnative_keychain.jnilib",
"libnative_misc.jnilib",
"libnative_synchronization.jnilib"
);
macosx.put(null, macosx_universal);
NATIVE_LIBRARIES.put("macosx", macosx);
final TreeMap<String, List<String>> solaris = new TreeMap<String, List<String>>();
final List<String> solaris_sparc = Arrays.asList(
"libnative_auth.so",
"libnative_console.so",
"libnative_filesystem.so",
"libnative_misc.so",
"libnative_synchronization.so"
);
solaris.put("sparc", solaris_sparc);
final List<String> solaris_x86 = Arrays.asList(
"libnative_auth.so",
"libnative_console.so",
"libnative_filesystem.so",
"libnative_misc.so",
"libnative_synchronization.so"
);
solaris.put("x86", solaris_x86);
final List<String> solaris_x86_64 = Arrays.asList(
"libnative_auth.so",
"libnative_console.so",
"libnative_filesystem.so",
"libnative_misc.so",
"libnative_synchronization.so"
);
solaris.put("x86_64", solaris_x86_64);
NATIVE_LIBRARIES.put("solaris", solaris);
final TreeMap<String, List<String>> win32 = new TreeMap<String, List<String>>();
final List<String> win32_x86 = Arrays.asList(
"native_auth.dll",
"native_console.dll",
"native_credential.dll",
"native_filesystem.dll",
"native_messagewindow.dll",
"native_misc.dll",
"native_registry.dll",
"native_synchronization.dll"
);
win32.put("x86", win32_x86);
final List<String> win32_x86_64 = Arrays.asList(
"native_auth.dll",
"native_console.dll",
"native_credential.dll",
"native_filesystem.dll",
"native_messagewindow.dll",
"native_misc.dll",
"native_registry.dll",
"native_synchronization.dll"
);
win32.put("x86_64", win32_x86_64);
NATIVE_LIBRARIES.put("win32", win32);
}
private final PersistenceStore store;
public NativeLibraryManager(final PersistenceStore store) {
this.store = store;
}
public void extractFiles() throws IOException {
// TODO: it would be great if we detected the current OS and architecture to extract only the needed files
extractFiles(this);
}
static void extractFiles(final NativeLibraryExtractor extractor) throws IOException {
for (final String operatingSystem : NATIVE_LIBRARIES.keySet()) {
final TreeMap<String, List<String>> architecturesToFileNames = NATIVE_LIBRARIES.get(operatingSystem);
for (final String architecture : architecturesToFileNames.keySet()) {
final List<String> fileNames = architecturesToFileNames.get(architecture);
for (final String fileName : fileNames) {
extractor.extractFile(operatingSystem, architecture, fileName);
}
}
}
}
public void extractFile(final String operatingSystem, final String architecture, final String fileName) throws IOException {
final String pathToNativeFile = buildPathToNativeFile(operatingSystem, architecture, fileName);
if (!store.containsItem(pathToNativeFile)) {
InputStream inputStream = null;
OutputStream outputStream = null;
try {
inputStream = metaClass.getResourceAsStream(pathToNativeFile);
outputStream = store.getItemOutputStream(pathToNativeFile);
IOUtils.copy(inputStream, outputStream);
}
finally {
IOUtils.closeQuietly(inputStream);
IOUtils.closeQuietly(outputStream);
}
}
}
// it is important that this return a string containing forward slashes
static String buildPathToNativeFile(final String operatingSystem, final String architecture, final String fileName) {
final StringBuilder sb = new StringBuilder(NATIVE.length() + 1 + operatingSystem.length() + 1 + 7 /* max architecture length */ + 1 + fileName.length());
sb.append(NATIVE).append('/');
sb.append(operatingSystem).append('/');
if (architecture != null) {
sb.append(architecture).append('/');
}
sb.append(fileName);
final String result = sb.toString();
return result;
}
public static synchronized void initialize() throws IOException {
final String nativeFolder = System.getProperty(nativeFolderPropertyName);
if (nativeFolder == null) {
final File vendor = new File(VENDOR_NAME);
final File vendor_sdk = new File(vendor, TFS_SDK);
final File vendor_sdk_version = new File(vendor_sdk, VERSION);
final FilesystemPersistenceStore store = new UserHomePersistenceStore(vendor_sdk_version);
final NativeLibraryManager manager = new NativeLibraryManager(store);
manager.extractFiles();
final File storeFile = store.getStoreFile();
final File nativeFile = new File(storeFile, NATIVE);
final String absolutePath = nativeFile.getAbsolutePath();
System.setProperty(nativeFolderPropertyName, absolutePath);
}
}
}