/** * Loads the details for the specified NAR. The details will be extracted from the manifest file. * * @param narDirectory the nar directory * @return details about the NAR * @throws IOException ioe */ private static NarDetails getNarDetails(final File narDirectory) throws IOException { final NarDetails narDetails = new NarDetails(); narDetails.setNarWorkingDirectory(narDirectory); final File manifestFile = new File(narDirectory, "META-INF/MANIFEST.MF"); try (final FileInputStream fis = new FileInputStream(manifestFile)) { final Manifest manifest = new Manifest(fis); final Attributes attributes = manifest.getMainAttributes(); // get the nar details narDetails.setNarId(attributes.getValue("Nar-Id")); narDetails.setNarDependencyId(attributes.getValue("Nar-Dependency-Id")); } return narDetails; }
/** Should be called at most once. */ private InitContext load(final File frameworkWorkingDir, final File extensionsWorkingDir) throws IOException, ClassNotFoundException { // get the system classloader final ClassLoader systemClassLoader = ClassLoader.getSystemClassLoader(); // find all nar files and create class loaders for them. final Map<String, ClassLoader> extensionDirectoryClassLoaderLookup = new LinkedHashMap<>(); final Map<String, ClassLoader> narIdClassLoaderLookup = new HashMap<>(); // make sure the nar directory is there and accessible FileUtils.ensureDirectoryExistAndCanAccess(frameworkWorkingDir); FileUtils.ensureDirectoryExistAndCanAccess(extensionsWorkingDir); final List<File> narWorkingDirContents = new ArrayList<>(); final File[] frameworkWorkingDirContents = frameworkWorkingDir.listFiles(); if (frameworkWorkingDirContents != null) { narWorkingDirContents.addAll(Arrays.asList(frameworkWorkingDirContents)); } final File[] extensionsWorkingDirContents = extensionsWorkingDir.listFiles(); if (extensionsWorkingDirContents != null) { narWorkingDirContents.addAll(Arrays.asList(extensionsWorkingDirContents)); } if (!narWorkingDirContents.isEmpty()) { final List<NarDetails> narDetails = new ArrayList<>(); // load the nar details which includes and nar dependencies for (final File unpackedNar : narWorkingDirContents) { final NarDetails narDetail = getNarDetails(unpackedNar); // ensure the nar contained an identifier if (narDetail.getNarId() == null) { logger.warn("No NAR Id found. Skipping: " + unpackedNar.getAbsolutePath()); continue; } // store the nar details narDetails.add(narDetail); } // attempt to locate the jetty nar ClassLoader jettyClassLoader = null; for (final Iterator<NarDetails> narDetailsIter = narDetails.iterator(); narDetailsIter.hasNext(); ) { final NarDetails narDetail = narDetailsIter.next(); // look for the jetty nar if (JETTY_NAR_ID.equals(narDetail.getNarId())) { // create the jetty classloader jettyClassLoader = createNarClassLoader(narDetail.getNarWorkingDirectory(), systemClassLoader); // remove the jetty nar since its already loaded narIdClassLoaderLookup.put(narDetail.getNarId(), jettyClassLoader); narDetailsIter.remove(); break; } } // ensure the jetty nar was found if (jettyClassLoader == null) { throw new IllegalStateException("Unable to locate Jetty bundle."); } int narCount; do { // record the number of nars to be loaded narCount = narDetails.size(); // attempt to create each nar class loader for (final Iterator<NarDetails> narDetailsIter = narDetails.iterator(); narDetailsIter.hasNext(); ) { final NarDetails narDetail = narDetailsIter.next(); final String narDependencies = narDetail.getNarDependencyId(); // see if this class loader is eligible for loading ClassLoader narClassLoader = null; if (narDependencies == null) { narClassLoader = createNarClassLoader(narDetail.getNarWorkingDirectory(), jettyClassLoader); } else if (narIdClassLoaderLookup.containsKey(narDetail.getNarDependencyId())) { narClassLoader = createNarClassLoader( narDetail.getNarWorkingDirectory(), narIdClassLoaderLookup.get(narDetail.getNarDependencyId())); } // if we were able to create the nar class loader, store it and remove the details if (narClassLoader != null) { extensionDirectoryClassLoaderLookup.put( narDetail.getNarWorkingDirectory().getCanonicalPath(), narClassLoader); narIdClassLoaderLookup.put(narDetail.getNarId(), narClassLoader); narDetailsIter.remove(); } } // attempt to load more if some were successfully loaded this iteration } while (narCount != narDetails.size()); // see if any nars couldn't be loaded for (final NarDetails narDetail : narDetails) { logger.warn( String.format( "Unable to resolve required dependency '%s'. Skipping NAR %s", narDetail.getNarDependencyId(), narDetail.getNarWorkingDirectory().getAbsolutePath())); } } return new InitContext( frameworkWorkingDir, extensionsWorkingDir, narIdClassLoaderLookup.get(FRAMEWORK_NAR_ID), new LinkedHashMap<>(extensionDirectoryClassLoaderLookup)); }