/** * Gets the bundle with the given coordinate. * * @param bundleCoordinate the coordinate of the bundle to find * @return the bundle with the coordinate, or an empty optional */ private Optional<Bundle> getBundle(final BundleCoordinate bundleCoordinate) { return initContext.bundles.values().stream() .filter(b -> b.getBundleDetails().getCoordinate().equals(bundleCoordinate)) .findFirst(); }
final String bundleId = bundleDetail.getCoordinate().getId(); final Set<BundleCoordinate> coordinates = bundleIdToCoordinatesLookup.computeIfAbsent(bundleId, (id) -> new HashSet<>()); coordinates.add(bundleDetail.getCoordinate()); final String bundleId = bundleDetail.getCoordinate().getId(); final Set<BundleCoordinate> coordinates = bundleIdToCoordinatesLookup.computeIfAbsent(bundleId, (id) -> new HashSet<>()); coordinates.add(bundleDetail.getCoordinate()); initContext.bundles.put(bundleDetail.getWorkingDirectory().getCanonicalPath(), bundle); logger.error("Unable to load NAR {} due to {}, skipping...", new Object[]{bundleDetail.getWorkingDirectory(), e.getMessage()}); for (final BundleDetails bundleDetail : additionalBundleDetails) { logger.warn(String.format("Unable to resolve required dependency '%s'. Skipping NAR '%s'", bundleDetail.getDependencyCoordinate().getId(), bundleDetail.getWorkingDirectory().getAbsolutePath())); skippedBundles.add(bundleDetail);
public BundleDetails build() { return new BundleDetails(this); } }
@Override public void logClassLoaderMapping() { final StringBuilder builder = new StringBuilder(); builder.append("Extension Type Mapping to Bundle:"); for (final Map.Entry<Class, Set<Class>> entry : definitionMap.entrySet()) { builder.append("\n\t=== ").append(entry.getKey().getSimpleName()).append(" Type ==="); for (final Class type : entry.getValue()) { final List<Bundle> bundles = classNameBundleLookup.containsKey(type.getName()) ? classNameBundleLookup.get(type.getName()) : Collections.emptyList(); builder.append("\n\t").append(type.getName()); for (final Bundle bundle : bundles) { final String coordinate = bundle.getBundleDetails().getCoordinate().getCoordinate(); final String workingDir = bundle.getBundleDetails().getWorkingDirectory().getPath(); builder.append("\n\t\t").append(coordinate).append(" || ").append(workingDir); } } builder.append("\n\t=== End ").append(entry.getKey().getSimpleName()).append(" types ==="); } logger.info(builder.toString()); } }
public SystemDiagnosticsSnapshotDTO.VersionInfoDTO createVersionInfoDTO() { final SystemDiagnosticsSnapshotDTO.VersionInfoDTO dto = new SystemDiagnosticsSnapshotDTO.VersionInfoDTO(); dto.setJavaVendor(System.getProperty("java.vendor")); dto.setJavaVersion(System.getProperty("java.version")); dto.setOsName(System.getProperty("os.name")); dto.setOsVersion(System.getProperty("os.version")); dto.setOsArchitecture(System.getProperty("os.arch")); final Bundle frameworkBundle = NarClassLoadersHolder.getInstance().getFrameworkBundle(); if (frameworkBundle != null) { final BundleDetails frameworkDetails = frameworkBundle.getBundleDetails(); dto.setNiFiVersion(frameworkDetails.getCoordinate().getVersion()); // Get build info dto.setBuildTag(frameworkDetails.getBuildTag()); dto.setBuildRevision(frameworkDetails.getBuildRevision()); dto.setBuildBranch(frameworkDetails.getBuildBranch()); dto.setBuildTimestamp(frameworkDetails.getBuildTimestampDate()); } return dto; }
/** * Determines if the given controller service node has the required API as an ancestor. * * @param controllerServiceImplBundle the bundle of a controller service being referenced by a processor * @param requiredApiCoordinate the controller service API required by the processor * @return true if the controller service node has the require API as an ancestor, false otherwise */ private boolean matchesApi(final ExtensionManager extensionManager, final Bundle controllerServiceImplBundle, final BundleCoordinate requiredApiCoordinate) { // start with the coordinate of the controller service for cases where the API and service are in the same bundle BundleCoordinate controllerServiceDependencyCoordinate = controllerServiceImplBundle.getBundleDetails().getCoordinate(); boolean foundApiDependency = false; while (controllerServiceDependencyCoordinate != null) { // determine if the dependency coordinate matches the required API if (requiredApiCoordinate.equals(controllerServiceDependencyCoordinate)) { foundApiDependency = true; break; } // move to the next dependency in the chain, or stop if null final Bundle controllerServiceDependencyBundle = extensionManager.getBundle(controllerServiceDependencyCoordinate); if (controllerServiceDependencyBundle == null) { controllerServiceDependencyCoordinate = null; } else { controllerServiceDependencyCoordinate = controllerServiceDependencyBundle.getBundleDetails().getDependencyCoordinate(); } } return foundApiDependency; }
private Map<File, Bundle> findWars(final Set<Bundle> bundles) { final Map<File, Bundle> wars = new HashMap<>(); // consider each nar working directory bundles.forEach(bundle -> { final BundleDetails details = bundle.getBundleDetails(); final File narDependencies = new File(details.getWorkingDirectory(), "NAR-INF/bundled-dependencies"); if (narDependencies.isDirectory()) { // list the wars from this nar final File[] narDependencyDirs = narDependencies.listFiles(WAR_FILTER); if (narDependencyDirs == null) { throw new IllegalStateException(String.format("Unable to access working directory for NAR dependencies in: %s", narDependencies.getAbsolutePath())); } // add each war for (final File war : narDependencyDirs) { wars.put(war, bundle); } } }); return wars; }
private List<BundleDetails> loadBundleDetails(List<File> unpackedNars) { final List<BundleDetails> narDetails = new ArrayList<>(); for (final File unpackedNar : unpackedNars) { try { final BundleDetails narDetail = getNarDetails(unpackedNar); final BundleCoordinate unpackedNarCoordinate = narDetail.getCoordinate(); // Skip this NAR if there is another NAR with the same group, id, and version final Optional<Bundle> existingBundle = getBundle(unpackedNarCoordinate); if (existingBundle.isPresent()) { final BundleDetails existingBundleDetails = existingBundle.get().getBundleDetails(); final String existingNarWorkingDir = existingBundleDetails.getWorkingDirectory().getCanonicalPath(); final String unpackedNarWorkingDir = narDetail.getWorkingDirectory().getCanonicalPath(); logger.error("Unable to load NAR with coordinates {} and working directory {} " + "because another NAR with the same coordinates already exists at {}", new Object[]{unpackedNarCoordinate, unpackedNarWorkingDir, existingNarWorkingDir}); } else { narDetails.add(narDetail); } } catch (Exception e) { logger.error("Unable to load NAR {} due to {}, skipping...", new Object[]{unpackedNar.getAbsolutePath(), e.getMessage()}); } } return narDetails; }
private void enrichComponent(EnrichingElementAdapter componentToEnrich, Map<String, Bundle> componentToEnrichVersionToBundles) throws FlowEnrichmentException { if (componentToEnrich.getBundleElement() != null) { return; } BundleCoordinate enrichingBundleCoordinate = null; if (!componentToEnrichVersionToBundles.isEmpty()) { // If there is only one supporting bundle, choose it, otherwise carry out additional analysis if (componentToEnrichVersionToBundles.size() == 1) { BundleDetails enrichingBundleDetails = componentToEnrichVersionToBundles.entrySet().iterator().next().getValue().getBundleDetails(); enrichingBundleCoordinate = enrichingBundleDetails.getCoordinate(); // Adjust the bundle to reflect the values we learned from the Extension Manager componentToEnrich.setBundleInformation(enrichingBundleCoordinate); componentToEnrich.setDependsUponBundleCoordinate(enrichingBundleDetails.getDependencyCoordinate()); } else { // multiple options final Set<String> componentToEnrichBundleVersions = componentToEnrichVersionToBundles.values().stream() .map(bundle -> bundle.getBundleDetails().getCoordinate().getVersion()).collect(Collectors.toSet()); // Select the last version of those available for the enriching bundle final String bundleVersion = componentToEnrichBundleVersions.stream().sorted().reduce((version, otherVersion) -> otherVersion).get(); final BundleCoordinate enrichingCoordinate = componentToEnrichVersionToBundles.get(bundleVersion).getBundleDetails().getCoordinate(); componentToEnrich.setBundleInformation(enrichingCoordinate); logger.warn("Multiple enriching bundle options were available for component {}. The automatically selected enriching bundle was {}", new Object[]{componentToEnrich.getComponentClass(), enrichingCoordinate}); } } else { logger.warn("Could not find any eligible bundles for {}. Automatic start of the flow cannot be guaranteed.", componentToEnrich.getComponentClass()); } }
aboutDTO.setVersion(frameworkDetails.getCoordinate().getVersion()); aboutDTO.setBuildTag(frameworkDetails.getBuildTag()); aboutDTO.setBuildRevision(frameworkDetails.getBuildRevision()); aboutDTO.setBuildBranch(frameworkDetails.getBuildBranch()); aboutDTO.setBuildTimestamp(frameworkDetails.getBuildTimestampDate());
private static BundleCoordinate findBundleForType(final ExtensionManager extensionManager, final String type, final BundleCoordinate desiredCoordinate) { final List<Bundle> bundles = extensionManager.getBundles(type); if (bundles.isEmpty()) { throw new IllegalStateException(String.format("%s is not known to this NiFi instance.", type)); } else if (bundles.size() > 1) { if (desiredCoordinate == null) { throw new IllegalStateException(String.format("Multiple versions of %s exist.", type)); } else { throw new IllegalStateException(String.format("Multiple versions of %s exist. No exact match for %s.", type, desiredCoordinate)); } } else { return bundles.get(0).getBundleDetails().getCoordinate(); } }
final BundleCoordinate bundleDependencyCoordinate = bundleDetail.getDependencyCoordinate(); if (bundleDependencyCoordinate == null) { final ClassLoader jettyClassLoader = getJettyBundle().getClassLoader(); bundleClassLoader = createNarClassLoader(bundleDetail.getWorkingDirectory(), jettyClassLoader); } else { final Optional<Bundle> dependencyBundle = getBundle(bundleDependencyCoordinate); bundleClassLoader = createNarClassLoader(bundleDetail.getWorkingDirectory(), narDependencyClassLoader); } else { final String dependencyCoordinateStr = bundleDependencyCoordinate.getCoordinate(); logger.warn(String.format("While loading '%s' unable to locate exact NAR dependency '%s'. Only found one possible match '%s'. Continuing...", bundleDetail.getCoordinate().getCoordinate(), dependencyCoordinateStr, coordinate.getCoordinate())); bundleClassLoader = createNarClassLoader(bundleDetail.getWorkingDirectory(), narDependencyClassLoader);
previouslySkippedBundles.forEach(b -> unpackedNars.add(b.getWorkingDirectory())); final BundleCoordinate bundleCoordinate = bundle.getBundleDetails().getCoordinate(); final Set<Class> extensions = extensionManager.getTypes(bundleCoordinate); if (extensions.isEmpty()) {
private void enrichComponent(EnrichingElementAdapter componentToEnrich, Map<String, Bundle> componentToEnrichVersionToBundles) throws FlowEnrichmentException { if (componentToEnrich.getBundleElement() != null) { return; } BundleCoordinate enrichingBundleCoordinate = null; if (!componentToEnrichVersionToBundles.isEmpty()) { // If there is only one supporting bundle, choose it, otherwise carry out additional analysis if (componentToEnrichVersionToBundles.size() == 1) { BundleDetails enrichingBundleDetails = componentToEnrichVersionToBundles.entrySet().iterator().next().getValue().getBundleDetails(); enrichingBundleCoordinate = enrichingBundleDetails.getCoordinate(); // Adjust the bundle to reflect the values we learned from the Extension Manager componentToEnrich.setBundleInformation(enrichingBundleCoordinate); componentToEnrich.setDependsUponBundleCoordinate(enrichingBundleDetails.getDependencyCoordinate()); } else { // multiple options final Set<String> componentToEnrichBundleVersions = componentToEnrichVersionToBundles.values().stream() .map(bundle -> bundle.getBundleDetails().getCoordinate().getVersion()).collect(Collectors.toSet()); // Select the last version of those available for the enriching bundle final String bundleVersion = componentToEnrichBundleVersions.stream().sorted().reduce((version, otherVersion) -> otherVersion).get(); final BundleCoordinate enrichingCoordinate = componentToEnrichVersionToBundles.get(bundleVersion).getBundleDetails().getCoordinate(); componentToEnrich.setBundleInformation(enrichingCoordinate); logger.warn("Multiple enriching bundle options were available for component {}. The automatically selected enriching bundle was {}", new Object[]{componentToEnrich.getComponentClass(), enrichingCoordinate}); } } else { logger.warn("Could not find any eligible bundles for {}. Automatic start of the flow cannot be guaranteed.", componentToEnrich.getComponentClass()); } }
@Override public void discoverExtensions(final Set<Bundle> narBundles) { // get the current context class loader ClassLoader currentContextClassLoader = Thread.currentThread().getContextClassLoader(); // consider each nar class loader for (final Bundle bundle : narBundles) { // Must set the context class loader to the nar classloader itself // so that static initialization techniques that depend on the context class loader will work properly final ClassLoader ncl = bundle.getClassLoader(); Thread.currentThread().setContextClassLoader(ncl); loadExtensions(bundle); // Create a look-up from coordinate to bundle bundleCoordinateBundleLookup.put(bundle.getBundleDetails().getCoordinate(), bundle); } // restore the current context class loader if appropriate if (currentContextClassLoader != null) { Thread.currentThread().setContextClassLoader(currentContextClassLoader); } }
final String narCoordinate = narDetail.getCoordinate().getCoordinate(); if (narCoordinatesToWorkingDir.containsKey(narCoordinate)) { final String existingNarWorkingDir = narCoordinatesToWorkingDir.get(narCoordinate); throw new IllegalStateException("Unable to load NAR with coordinates " + narCoordinate + " and working directory " + narDetail.getWorkingDirectory() + " because another NAR with the same coordinates already exists at " + existingNarWorkingDir); narCoordinatesToWorkingDir.put(narCoordinate, narDetail.getWorkingDirectory().getCanonicalPath()); if (JETTY_NAR_ID.equals(narDetail.getCoordinate().getId())) { jettyClassLoader = createNarClassLoader(narDetail.getWorkingDirectory(), rootClassloader); narDirectoryBundleLookup.put(narDetail.getWorkingDirectory().getCanonicalPath(), new Bundle(narDetail, jettyClassLoader)); narCoordinateClassLoaderLookup.put(narDetail.getCoordinate().getCoordinate(), jettyClassLoader); narDetailsIter.remove(); narIdBundleLookup.computeIfAbsent(narDetail.getCoordinate().getId(), id -> new HashSet<>()).add(narDetail.getCoordinate()); final BundleCoordinate narDependencyCoordinate = narDetail.getDependencyCoordinate(); narClassLoader = createNarClassLoader(narDetail.getWorkingDirectory(), jettyClassLoader); } else { final String dependencyCoordinateStr = narDependencyCoordinate.getCoordinate(); narClassLoader = createNarClassLoader(narDetail.getWorkingDirectory(), narDependencyClassLoader); } else { narDetail.getCoordinate().getCoordinate(), dependencyCoordinateStr, coordinate.getCoordinate()));
unpackBundleDocs(docsWorkingDir, extensionMapping, systemBundle.getBundleDetails().getCoordinate(), systemBundle.getBundleDetails().getWorkingDirectory());
/** * Determines if the given controller service node has the required API as an ancestor. * * @param controllerServiceImplBundle the bundle of a controller service being referenced by a processor * @param requiredApiCoordinate the controller service API required by the processor * @return true if the controller service node has the require API as an ancestor, false otherwise */ private boolean matchesApi(final Bundle controllerServiceImplBundle, final BundleCoordinate requiredApiCoordinate) { // start with the coordinate of the controller service for cases where the API and service are in the same bundle BundleCoordinate controllerServiceDependencyCoordinate = controllerServiceImplBundle.getBundleDetails().getCoordinate(); boolean foundApiDependency = false; while (controllerServiceDependencyCoordinate != null) { // determine if the dependency coordinate matches the required API if (requiredApiCoordinate.equals(controllerServiceDependencyCoordinate)) { foundApiDependency = true; break; } // move to the next dependency in the chain, or stop if null final Bundle controllerServiceDependencyBundle = ExtensionManager.getBundle(controllerServiceDependencyCoordinate); if (controllerServiceDependencyBundle == null) { controllerServiceDependencyCoordinate = null; } else { controllerServiceDependencyCoordinate = controllerServiceDependencyBundle.getBundleDetails().getDependencyCoordinate(); } } return foundApiDependency; }
/** * Find the bundle coordinates for any service APIs that are referenced by this component and not part of the same bundle. * * @param component the component being instantiated */ protected Set<BundleCoordinate> findReachableApiBundles(final ConfigurableComponent component) { final Set<BundleCoordinate> reachableApiBundles = new HashSet<>(); try (final NarCloseable closeable = NarCloseable.withComponentNarLoader(component.getClass().getClassLoader())) { final List<PropertyDescriptor> descriptors = component.getPropertyDescriptors(); if (descriptors != null && !descriptors.isEmpty()) { for (final PropertyDescriptor descriptor : descriptors) { final Class<? extends ControllerService> serviceApi = descriptor.getControllerServiceDefinition(); if (serviceApi != null && !component.getClass().getClassLoader().equals(serviceApi.getClassLoader())) { final Bundle apiBundle = classLoaderBundleLookup.get(serviceApi.getClassLoader()); reachableApiBundles.add(apiBundle.getBundleDetails().getCoordinate()); } } } } return reachableApiBundles; }
final String narCoordinate = narDetail.getCoordinate().getCoordinate(); if (narCoordinatesToWorkingDir.containsKey(narCoordinate)) { final String existingNarWorkingDir = narCoordinatesToWorkingDir.get(narCoordinate); throw new IllegalStateException("Unable to load NAR with coordinates " + narCoordinate + " and working directory " + narDetail.getWorkingDirectory() + " because another NAR with the same coordinates already exists at " + existingNarWorkingDir); narCoordinatesToWorkingDir.put(narCoordinate, narDetail.getWorkingDirectory().getCanonicalPath()); final BundleCoordinate narDependencyCoordinate = narDetail.getDependencyCoordinate(); narClassLoader = createNarClassLoader(narDetail.getWorkingDirectory(), currentContextClassLoader); } else { final String dependencyCoordinateStr = narDependencyCoordinate.getCoordinate(); narClassLoader = createNarClassLoader(narDetail.getWorkingDirectory(), narDependencyClassLoader); } else { narDetail.getCoordinate().getCoordinate(), dependencyCoordinateStr, coordinate.getCoordinate())); narClassLoader = createNarClassLoader(narDetail.getWorkingDirectory(), narDependencyClassLoader); narDirectoryBundleLookup.put(narDetail.getWorkingDirectory().getCanonicalPath(), new Bundle(narDetail, bundleClassLoader)); narCoordinateClassLoaderLookup.put(narDetail.getCoordinate().getCoordinate(), narClassLoader); narDetailsIter.remove(); narDetail.getDependencyCoordinate().getId(), narDetail.getWorkingDirectory().getAbsolutePath())); .filter(b -> b.getBundleDetails().getCoordinate().getId().equals(FRAMEWORK_NAR_ID))