public static LinkedHashSet<String> findJars(LogicalPlan dag, Class<?>[] defaultClasses) { List<Class<?>> jarClasses = new ArrayList<Class<?>>(); for (String className : dag.getClassNames()) { try { Class<?> clazz = Thread.currentThread().getContextClassLoader().loadClass(className); jarClasses.add(clazz); } catch (ClassNotFoundException e) { throw new IllegalArgumentException("Failed to load class " + className, e); } } for (Class<?> clazz : Lists.newArrayList(jarClasses)) { // process class and super classes (super does not require deploy annotation) for (Class<?> c = clazz; c != Object.class && c != null; c = c.getSuperclass()) { // LOG.debug("checking " + c); jarClasses.add(c); jarClasses.addAll(Arrays.asList(c.getInterfaces())); } } jarClasses.addAll(Arrays.asList(defaultClasses)); if (dag.isDebug()) { LOG.debug("Deploy dependencies: {}", jarClasses); } LinkedHashSet<String> localJarFiles = new LinkedHashSet<String>(); // avoid duplicates HashMap<String, String> sourceToJar = new HashMap<String, String>(); for (Class<?> jarClass : jarClasses) { if (jarClass.getProtectionDomain().getCodeSource() == null) { // system class continue; } String sourceLocation = jarClass.getProtectionDomain().getCodeSource().getLocation().toString(); String jar = sourceToJar.get(sourceLocation); if (jar == null) { // don't create jar file from folders multiple times jar = JarFinder.getJar(jarClass); sourceToJar.put(sourceLocation, jar); LOG.debug("added sourceLocation {} as {}", sourceLocation, jar); } if (jar == null) { throw new AssertionError("Cannot resolve jar file for " + jarClass); } localJarFiles.add(jar); } String libJarsPath = dag.getValue(LogicalPlan.LIBRARY_JARS); if (!StringUtils.isEmpty(libJarsPath)) { String[] libJars = StringUtils.splitByWholeSeparator(libJarsPath, LIB_JARS_SEP); localJarFiles.addAll(Arrays.asList(libJars)); } LOG.info("Local jar file dependencies: " + localJarFiles); return localJarFiles; }
/** * Will inject this bundle context code inside the dotCMS context * * @param className a reference class inside this bundle jar * @param reload if a redefinition should be done or not * @throws Exception */ private void injectContext(String className, Boolean reload) throws Exception { // Get the location of this OSGI bundle jar source code using a known class inside this bundle Class clazz = Class.forName(className, false, getFelixClassLoader()); URL classURL = clazz.getProtectionDomain().getCodeSource().getLocation(); // Verify if we have our UrlOsgiClassLoader on the main class loaders UrlOsgiClassLoader urlOsgiClassLoader = activatorUtil.findCustomURLLoader(ClassLoader.getSystemClassLoader()); if (urlOsgiClassLoader != null) { if (!urlOsgiClassLoader.contains( classURL)) { // Verify if this URL is already in our custom ClassLoader urlOsgiClassLoader.addURL(classURL); } // The ClassLoader and the class content is already in the system ClassLoader, so we need to // reload the jar contents if (reload) { urlOsgiClassLoader.reload(classURL); } } else { // Getting the reference of a known class in order to get the base/main class loader Class baseClass = getContextClassLoader().loadClass("org.quartz.Job"); // Creates our custom class loader in order to use it to inject the class code inside dotcms // context urlOsgiClassLoader = new UrlOsgiClassLoader(classURL, baseClass.getClassLoader()); // We may have classes we want to override from e beginning, for example a custom // implementation of a dotCMS class if (reload) { urlOsgiClassLoader.reload(classURL); } // Linking our custom class loader with the dotCMS class loaders hierarchy. urlOsgiClassLoader.linkClassLoaders(); } }