package streamflow.engine.framework; import com.google.common.cache.CacheBuilder; import com.google.common.cache.CacheLoader; import com.google.common.cache.LoadingCache; import java.io.File; import java.net.URL; import java.net.URLClassLoader; import java.util.concurrent.ExecutionException; import org.apache.commons.io.FileUtils; import org.apache.commons.io.IOUtils; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import streamflow.util.environment.StreamflowEnvironment; public class FrameworkUtils { private static final Logger LOG = LoggerFactory.getLogger(FrameworkUtils.class); private static final String DEFAULT_CLASS_LOADER_POLICY = "FRAMEWORK_FIRST"; private static FrameworkUtils singleton; private LoadingCache<String, ClassLoader> frameworkFirstCache; private LoadingCache<String, ClassLoader> frameworkLastCache; private FrameworkUtils() { } public static synchronized FrameworkUtils getInstance() { if (singleton == null) { singleton = new FrameworkUtils(); singleton.initialize(); } return singleton; } @Override public Object clone() throws CloneNotSupportedException { throw new CloneNotSupportedException(); } private void initialize() { frameworkFirstCache = CacheBuilder.newBuilder().build(new FrameworkFirstCacheLoader()); frameworkLastCache = CacheBuilder.newBuilder().build(new FrameworkLastCacheLoader()); // Initialize the frameworks directory where temporary frameworks will be stored File frameworksDir = new File(StreamflowEnvironment.getFrameworksDir()); if (!frameworksDir.exists()) { frameworksDir.mkdirs(); } } public Class loadFrameworkClass(String frameworkHash, String frameworkClass) throws FrameworkException { // Default policy is to load frameworks first return loadFrameworkClass(frameworkHash, frameworkClass, DEFAULT_CLASS_LOADER_POLICY); } public Class loadFrameworkClass(String frameworkHash, String frameworkClass, String classLoaderPolicy) throws FrameworkException { Class frameworkClazz = null; try { // Load the framework realm to isolate the class loading for the framework ClassLoader frameworkClassLoader = getFrameworkClassLoader(frameworkHash, classLoaderPolicy); // Load the module using the specified module class frameworkClazz = frameworkClassLoader.loadClass(frameworkClass); } catch (ClassNotFoundException ex) { throw new FrameworkException( "Framework class was not found in the framework jar: " + frameworkClass); } return frameworkClazz; } public <T> T loadFrameworkClassInstance(String frameworkHash, String frameworkClass, Class<T> frameworkClassType) throws FrameworkException { // Defaut policy is to load frameworks first return loadFrameworkClassInstance( frameworkHash, frameworkClass, frameworkClassType, DEFAULT_CLASS_LOADER_POLICY); } public <T> T loadFrameworkClassInstance(String frameworkHash, String frameworkClass, Class<T> frameworkClassType, String classLoaderPolicy) throws FrameworkException { try { // Load the framework class from the framework with specified coordinates Class frameworkClazz = loadFrameworkClass(frameworkHash, frameworkClass, classLoaderPolicy); // Check to make sure that the library loaded matches the class type if (frameworkClassType.isAssignableFrom(frameworkClazz)) { // Create a new instance of the module and return it return (T) frameworkClazz.newInstance(); } else { throw new FrameworkException( "The framework class could not be assigned to the specified class type: " + frameworkClass); } } catch (FrameworkException ex) { // Rethrow framework exceptions as is throw ex; } catch (InstantiationException ex) { throw new FrameworkException( "Component class cound not be instantiated: " + frameworkClass); } catch (IllegalAccessException ex) { throw new FrameworkException( "Component class was illegally accessed: " + frameworkClass); } catch (Exception ex) { LOG.error("Component loading failed due to an unexpected exception: ", ex); throw new FrameworkException( "Component loading failed due to an unexpected exception: " + ex.getMessage()); } } public ClassLoader getFrameworkClassLoader(String frameworkHash) throws FrameworkException { return getFrameworkClassLoader(frameworkHash, DEFAULT_CLASS_LOADER_POLICY); } public ClassLoader getFrameworkClassLoader(String frameworkHash, String classLoaderPolicy) throws FrameworkException { try { if (classLoaderPolicy.equalsIgnoreCase("FRAMEWORK_LAST")) { return frameworkLastCache.get(frameworkHash); } else { // Default class loader policy is framework first return frameworkFirstCache.get(frameworkHash); } } catch (ExecutionException ex) { throw new FrameworkException("Framework class loader execution exception: " + ex.getMessage()); } } public URL getFrameworkJarUrl(String frameworkHash) { File frameworkJar = new File(StreamflowEnvironment.getFrameworksDir(), frameworkHash + ".jar"); // Check if the framework jar has already been added if (!frameworkJar.exists()) { // URL to the framework jar embedded within the topology jar //URL embeddedFrameworkUrl = Thread.currentThread().getContextClassLoader() URL embeddedFrameworkUrl = this.getClass().getClassLoader() .getResource("STREAMFLOW-INF/lib/" + frameworkHash + ".jar"); try { // Copy the framework jar out of the topology jar and into the temp directory FileUtils.writeByteArrayToFile(frameworkJar, IOUtils.toByteArray(embeddedFrameworkUrl)); } catch (Exception ex) { LOG.error("An exception occurred while copying the inbuilt framework jar to the temp directory", ex); } } try { return frameworkJar.toURI().toURL(); } catch (Exception ex) { LOG.error("Unabled to load the framework jar URL: ", ex); return null; } } private class FrameworkFirstCacheLoader extends CacheLoader<String, ClassLoader> { @Override public ClassLoader load(String frameworkHash) throws FrameworkException { URL frameworkUrl = getFrameworkJarUrl(frameworkHash); if (frameworkUrl != null) { // Add the framework jar URL to the list to be loaded by the classloader URL[] frameworkUrls = new URL[]{frameworkUrl}; LOG.info("Framework First Class Loader initialized by cache: Framework Hash = " + frameworkHash); return new FrameworkFirstClassLoader( frameworkUrls, Thread.currentThread().getContextClassLoader()); } else { throw new FrameworkException("Unable to load the framework jar, file was not available: " + frameworkUrl); } } } private class FrameworkLastCacheLoader extends CacheLoader<String, ClassLoader> { @Override public ClassLoader load(String frameworkHash) throws FrameworkException { URL frameworkUrl = getFrameworkJarUrl(frameworkHash); if (frameworkUrl != null) { // Add the framework jar URL to the list to be loaded by the classloader URL[] frameworkUrls = new URL[]{frameworkUrl}; LOG.info("Framework Last Class Loader initialized by cache: Framework Hash = " + frameworkHash); return new URLClassLoader( frameworkUrls, Thread.currentThread().getContextClassLoader()); } else { throw new FrameworkException("Unable to load the framework jar, file was not available: " + frameworkUrl); } } } }