/* * Copyright (C) 2014 Intel Corporation * All rights reserved. */ package com.intel.mtwilson.launcher; import com.intel.dcsg.cpg.classpath.FileURLClassLoader; import com.intel.dcsg.cpg.classpath.JarClassIterator; import com.intel.dcsg.cpg.classpath.MultiJarFileClassLoader; import com.intel.dcsg.cpg.extensions.ExtensionUtil; import com.intel.dcsg.cpg.extensions.ImplementationRegistrar; import com.intel.dcsg.cpg.extensions.Registrar; import com.intel.dcsg.cpg.extensions.Scanner; import com.intel.dcsg.cpg.io.file.FilenameContainsFilter; import com.intel.dcsg.cpg.io.file.FilenameEndsWithFilter; import com.intel.dcsg.cpg.performance.CountingIterator; import com.intel.dcsg.cpg.util.ArrayIterator; import com.intel.mtwilson.My; import com.intel.mtwilson.MyFilesystem; import java.io.File; import java.io.IOException; import java.util.ArrayList; /** * * @author jbuhacoff */ public class ExtensionDirectoryLauncher extends ExtensionLauncher implements Runnable { private static final org.slf4j.Logger log = org.slf4j.LoggerFactory.getLogger(ExtensionDirectoryLauncher.class); private File javaFolder; private ClassLoader parentClassLoader; // private MultiJarFileClassLoader applicationClassLoader; private ClassLoader applicationClassLoader; private Registrar[] registrars; /** * Initializes member variables parentClassLoader, * applicationClassLoader, and javaFolder; * they can be replaced using the * available setter methods. * * The applicationClassLoader is configured with parentClassLoader as its * parent; if you replace with another classloader you will have to set * its parent yourself. */ public ExtensionDirectoryLauncher() { // determine the parent classloader to use parentClassLoader = Thread.currentThread().getContextClassLoader(); if(parentClassLoader==null) { parentClassLoader = ExtensionDirectoryLauncher.class.getClassLoader(); } // look for java extension directory // String javaPath = My.filesystem().getBootstrapFilesystem().getJavaPath(); // for example, /opt/mtwilson/java String javaPath = MyFilesystem.getApplicationFilesystem().getBootstrapFilesystem().getJavaPath(); // for example, /opt/mtwilson/java log.debug("Default application java path: {}", javaPath); // if( My.configuration().getmtwj) javaFolder = new File(javaPath); // applicationClassLoader = new MultiJarFileClassLoader(parentClassLoader); registrars = new Registrar[] { new ImplementationRegistrar() } ; log.debug("thread context class loader: {}", Thread.currentThread().getContextClassLoader().getClass().getName()); } public ClassLoader getParentClassLoader() { return parentClassLoader; } public void setParentClassLoader(ClassLoader parentClassLoader) { this.parentClassLoader = parentClassLoader; } public ClassLoader getApplicationClassLoader() { return applicationClassLoader; } // public void setApplicationClassLoader(MultiJarFileClassLoader applicationClassLoader) { public void setApplicationClassLoader(ClassLoader applicationClassLoader) { this.applicationClassLoader = applicationClassLoader; } public File getJavaFolder() { return javaFolder; } public void setJavaFolder(File javaFolder) { this.javaFolder = javaFolder; } public Registrar[] getRegistrars() { return registrars; } public void setRegistrars(Registrar[] registrars) { this.registrars = registrars; } @Override public void run() { // add all the jar files to a classloader try { load(getApplicationJars()); } catch(IOException e) { log.error("Cannot load jars", e); return; } // scan mtwilson jars for plugins, in the main classloader and also in all feature classloaders / java ext dirs scan(getApplicationExtensionJars(), getRegistrars()); } public File[] getApplicationJars() { log.debug("Scanning jar files in {}", javaFolder.getAbsolutePath()); // list all the jar files in the java directory FilenameEndsWithFilter jarfilter = new FilenameEndsWithFilter(".jar"); File[] jars = javaFolder.listFiles(jarfilter); if( jars == null ) { return new File[0]; } return jars; } /** * Default behavior is to filter the application jars to select only * jars that have "mtwilson" in the name, for example mtwilson-attestation-ws-v2.jar * or othercompany-mtwilson-plugin.jar * * @return */ public File[] getApplicationExtensionJars() { FilenameContainsFilter jarfilter = new FilenameContainsFilter("mtwilson"); File[] jars = getApplicationJars(); ArrayList<File> extensionJars = new ArrayList<>(); for(int i=0; i<jars.length; i++) { if( jarfilter.accept(jars[i]) ) { extensionJars.add(jars[i]); } } return extensionJars.toArray(new File[extensionJars.size()]); } public void load(File[] jars) throws IOException { if( applicationClassLoader == null ) { applicationClassLoader = new FileURLClassLoader(jars, parentClassLoader); } else {} } public void scan(File[] jars, Registrar[] registrars) { long time0 = System.currentTimeMillis(); CountingIterator<File> it = new CountingIterator<>(new ArrayIterator<>(jars)); // only scans directory for jar files; does NOT scan subdirectories for(int i=0; i<registrars.length; i++) { log.debug("Scanning with registrar {}", registrars[i].getClass().getName()); } while (it.hasNext()) { File jar = it.next(); log.debug("Scanning {}", jar.getAbsolutePath()); try {/* for(Registrar registrar : registrars) { ExtensionUtil.scan(registrar, new JarClassIterator(jar, applicationClassLoader));// we use our current classloader which means if any classes are already loaded we'll reuse them }*/ // ExtensionUtil.scan(new JarClassIterator(jar, applicationClassLoader), registrars); Scanner scanner = new Scanner(registrars); scanner.setThrowExceptions(false); scanner.setThrowErrors(false); scanner.scan(new JarClassIterator(jar, applicationClassLoader)); } catch(Throwable e) { // catch ClassNotFoundException and NoClassDefFoundError log.error("Cannot read jar file {} because {}", jar.getAbsolutePath(), e.getClass().getName() + ": " + e.getMessage()); log.debug("Caught throwable", e); //e.printStackTrace(); // log.error("Cannot read jar file {}", jar.getAbsolutePath()); } } long time1 = System.currentTimeMillis(); log.info("Scanned {} jars in {}ms", it.getValue(), time1-time0); } }