All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.ibm.cloud.objectstorage.services.aspera.transfer.AsperaLibraryLoader Maven / Gradle / Ivy

Go to download

A single bundled dependency that includes all service and dependent JARs with third-party libraries relocated to different namespaces.

There is a newer version: 2.13.4
Show newest version
/*
* Copyright 2018 IBM Corp. All Rights Reserved.
*
* Licensed 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 com.ibm.cloud.objectstorage.services.aspera.transfer;

import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.URISyntaxException;
import java.net.URL;
import java.util.Arrays;
import java.util.Collections;
import java.util.Enumeration;
import java.util.List;
import java.util.jar.Attributes;
import java.util.jar.JarEntry;
import java.util.jar.JarFile;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;

import com.ibm.aspera.faspmanager2.faspmanager2;

/**
 * Utility class to support extracting and loading native Aspera
 * assets (ascp, dynamic libraries, configuration) from the cos-aspera dependency
 */
public final class AsperaLibraryLoader { 
	protected static Log log = LogFactory.getLog(AsperaLibraryLoader.class);
	
	private static final List MAC_DYNAMIC_LIBS = Collections.unmodifiableList(
			Arrays.asList("libfaspmanager2.jnilib", "_faspmanager2.so"));
	private static final List UNIX_DYNAMIC_LIBS = Collections.unmodifiableList(
			Arrays.asList("libfaspmanager2.so"));
	private static final List WINDOWS_DYNAMIC_LIBS = Collections.unmodifiableList(
			Arrays.asList("faspmanager2.dll"));
	private static final String SEPARATOR = System.getProperty("file.separator");
	private static final File EXTRACT_LOCATION_ROOT =
			new File(System.getProperty("user.home") +
					SEPARATOR +
					".aspera" +
					SEPARATOR + 
					"cos-aspera");
	
	/**
	 * Prepares and loads the Aspera library in preparation for its use. May conditionally
	 * extract Aspera library jar contents to a location on the local filesystem, determined
	 * by a combination of the User's home directory and library version. Loads the underlying
	 * dynamic library for use by the Aspera library Java bindings
	 */
	public static String load() {
		JarFile jar = null;
		String location = null;
		try {
			jar = createJar();
			String version = jarVersion(jar);
			location = EXTRACT_LOCATION_ROOT + SEPARATOR + version;
			File extractedLocation = new File(location);
			if(!extractedLocation.exists()) {
				extractJar(jar, extractedLocation);
			}
			loadLibrary(extractedLocation, osLibs());
		} catch (Exception e) {
			throw new AsperaLibraryLoadException("Unable to load Aspera Library", e);
		} finally {
			if(jar != null) {
				try {
					jar.close();
				} catch (IOException e) {
					log.warn("Unable to close Aspera jar file after loading", e);
				}
			}
		}

		return location;
	}

	/**
	 * Creates an instance of JarFile which references the Aspera library
	 * @return Aspera Library jar file
	 * @throws IOException if unable to create a JarFile reference
	 * @throws URISyntaxException if the location to the Aspera library is invalid
	 */
	public static JarFile createJar() throws IOException, URISyntaxException {
		URL location = faspmanager2.class.getProtectionDomain().getCodeSource().getLocation();
		return new JarFile(new File(location.toURI()));
	}

	/**
	 * Determines the version associated with this jar
	 * @param jar Source jar to query version information from
	 * @return The source jar's version
	 * @throws IOException if unable to successfully query source jar
	 */
	public static String jarVersion(JarFile jar) throws IOException {
		String version = jar.getManifest().getMainAttributes().getValue(Attributes.Name.IMPLEMENTATION_VERSION);
		
		if(version == null) {
			version = String.format("%d", System.currentTimeMillis());
		}
		return version;
	}
	
	/**
	 * Creates a 1:1 copy of all contents from a jar file to the specified location on the local filesystem
	 * @param jar The source jar to extract contents from
	 * @param extractedLocation The target location for extracted jar contents 
	 * @throws IOException if jar extraction fails IO
	 */
	public static void extractJar(JarFile jar, File extractedLocation) throws IOException {		
		Enumeration entries = jar.entries();
		while(entries.hasMoreElements()) {
			JarEntry entry = entries.nextElement();
			
			File destPath = new File(extractedLocation, SEPARATOR + entry.getName());

			// is Directory
			if(entry.isDirectory()) {
				log.debug("Creating directory: " + destPath);
				destPath.mkdirs();
				continue;
			}
			
			// is File
			log.debug("Creating parent directories for file: " + destPath);
			destPath.getParentFile().mkdirs();
			extractFile(jar, entry, destPath);
		}
	}

	/**
	 * Extracts a jar entry from a jar file to a target location on the local file system
	 * @param jar The jar in which the desired file resides
	 * @param entry The desired entry (file) to extract from the jar
	 * @param destPath The target location to extract the jar entry to 
	 * @throws IOException if any IO failure occurs during file extraction
	 */
	public static void extractFile(JarFile jar, JarEntry entry, File destPath) throws IOException {
		InputStream in = null;
		OutputStream out = null;
		
		try {
			in = jar.getInputStream(entry);
			out = new FileOutputStream(destPath);
			byte[] buf = new byte[1024];
	        for (int i = in.read(buf); i != -1; i = in.read(buf))
	        {
	           out.write(buf, 0, i);
	        }
		} finally {
			if(in != null) {
				in.close();
			}
			if(out != null) {
				out.close();
			}
		}

		//Ensure persmissions are set correct on ascp, has to be done after the File has been created
		if (entry.getName().equals("ascp")) {
			destPath.setExecutable(true);
			destPath.setWritable(true);
		}
	}

	
	/**
	 * Determine which os the jvm is running on
	 * @return 	the os specific list of native files to load
	 */
	public static List osLibs() {
		String OS = System.getProperty("os.name").toLowerCase();
		if (OS.indexOf("win") >= 0){
			return WINDOWS_DYNAMIC_LIBS;
		} else if (OS.indexOf("mac") >= 0) {
			return MAC_DYNAMIC_LIBS;
		} else if (OS.indexOf("nix") >= 0 || OS.indexOf("nux") >= 0 || OS.indexOf("aix") > 0 ) {
			return UNIX_DYNAMIC_LIBS;
		} else {
			throw new AsperaLibraryLoadException("OS is not supported for Aspera");
		}
	}
	
	/**
	 * Loads a dynamic library into the JVM from a list of candidates
	 * @param extractedPath The base directory where candidate dynamic libraries reside
	 * @param candidates A list of candidate dynamic library names for various platforms
	 * @return 	true if one of the candidate libraries was loaded successfully, else false
	 */
	public static void loadLibrary(File extractedPath, List candidates) {
		for (String lib : candidates) {
			File libPath = new File(extractedPath, lib);
			String absPath = libPath.getAbsolutePath();
			log.debug("Attempting to load dynamic library: " + absPath);
			try {
				System.load(absPath);
				log.info("Loaded dynamic library: " + absPath);
				return;
			} catch (UnsatisfiedLinkError e) {
				log.debug("Unable to load dynamic library: " + absPath, e);
			}
		}
		throw new RuntimeException("Failed to load Aspera dynamic library from candidates " + candidates + " at location: " + extractedPath);
	}
	
	/**
	 * An exception that represents a failed attempt to load the Aspera library
	 */
	public static class AsperaLibraryLoadException extends RuntimeException {
		private static final long serialVersionUID = 1L;
		
		/**
	     * Creates a new AsperaLibraryLoadException with the specified message.
	     *
	     * @param message
	     *            An error message describing why this exception was thrown.
	     */
		public AsperaLibraryLoadException(String message) {
	        super(message);
	    }

		/**
	     * Creates a new AsperaLibraryLoadException with the root cause.
	     *
	     * @param cause
	     *          The underlying cause of this exception.
	     */
	    public AsperaLibraryLoadException(Throwable cause) {
	        super(cause);
	    }

	    /**
	     * Creates a new AsperaLibraryLoadException with the specified message, and root
	     * cause.
	     *
	     * @param message
	     *            An error message describing why this exception was thrown.
	     * @param cause
	     *            The underlying cause of this exception.
	     */
	    public AsperaLibraryLoadException(String message, Throwable cause) {
	        super(message, cause);
	    }
	}
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy