private void writeFeatures()

in tooling/karaf-maven-plugin/src/main/java/org/apache/karaf/tooling/features/GenerateDescriptorMojo.java [428:597]


    private void writeFeatures(PrintStream out) throws ArtifactResolutionException, ArtifactNotFoundException,
            IOException, JAXBException, SAXException, ParserConfigurationException, XMLStreamException, MojoExecutionException {
        getLog().info("Generating feature descriptor file " + outputFile.getAbsolutePath());
        //read in an existing feature.xml
        ObjectFactory objectFactory = new ObjectFactory();
        Features features;
        if (inputFile.exists()) {
            filter(inputFile, filteredInputFile);
            features = readFeaturesFile(filteredInputFile);
        } else {
            features = objectFactory.createFeaturesRoot();
        }
        if (features.getName() == null) {
            features.setName(project.getArtifactId());
        }

        Feature feature = null;
        for (Feature test : features.getFeature()) {
            if (test.getName().equals(primaryFeatureName)) {
                feature = test;
            }
        }
        if (feature == null) {
            feature = objectFactory.createFeature();
            feature.setName(primaryFeatureName);
        }
        if (!feature.hasVersion()) {
            feature.setVersion(project.getArtifact().getBaseVersion());
        }
        if (feature.getDescription() == null) {
            feature.setDescription(project.getName());
        }
        if (installMode != null) {
            feature.setInstall(installMode);
        }
        if (project.getDescription() != null && feature.getDetails() == null) {
            feature.setDetails(project.getDescription());
        }
        if (includeProjectArtifact) {
            Bundle bundle = objectFactory.createBundle();
            bundle.setLocation(this.dependencyHelper.artifactToMvn(project.getArtifact(), project.getVersion()));
            if (startLevel != null) {
                bundle.setStartLevel(startLevel);
            }
            feature.getBundle().add(bundle);
        }
        boolean needWrap = false;

        // First pass to look for features
        // Track other features we depend on and their repositories (we track repositories instead of building them from
        // the feature's Maven artifact to allow for multi-feature repositories)
        // TODO Initialise the repositories from the existing feature file if any
        Map<Dependency, Feature> otherFeatures = new HashMap<>();
        Map<Feature, String> featureRepositories = new HashMap<>();
        FeaturesCache cache = new FeaturesCache(featuresCacheSize, artifactCacheSize);
        for (final LocalDependency entry : localDependencies) {
            Object artifact = entry.getArtifact();

            if (excludedArtifactIds.contains(this.dependencyHelper.getArtifactId(artifact))) {
                continue;
            }

            processFeatureArtifact(features, feature, otherFeatures, featureRepositories, cache, artifact,
                    entry.getParent(), true);
        }
        // Do not retain cache beyond this point
        cache = null;

        // Second pass to look for bundles
        if (addBundlesToPrimaryFeature) {
            localDependency:
            for (final LocalDependency entry : localDependencies) {
                Object artifact = entry.getArtifact();

                if (excludedArtifactIds.contains(this.dependencyHelper.getArtifactId(artifact))) {
                    continue;
                }

                if (!this.dependencyHelper.isArtifactAFeature(artifact)) {
                    String bundleName = this.dependencyHelper.artifactToMvn(artifact, getVersionOrRange(entry.getParent(), artifact));

                    for (ConfigFile cf : feature.getConfigfile()) {
                        if (bundleName.equals(cf.getLocation().replace('\n', ' ').trim())) {
                            // The bundle matches a configfile, ignore it
                            continue localDependency;
                        }
                    }

                    File bundleFile = this.dependencyHelper.resolve(artifact, getLog());
                    Manifest manifest = getManifest(bundleFile);
                    boolean bundleNeedsWrapping = false;
                    if (manifest == null || !ManifestUtils.isBundle(manifest)) {
                        bundleName = "wrap:" + bundleName;
                        bundleNeedsWrapping = true;
                    }

                    Bundle bundle = null;
                    for (Bundle b : feature.getBundle()) {
                        if (bundleName.equals(b.getLocation())) {
                            bundle = b;
                            break;
                        }
                    }
                    if (bundle == null) {
                        bundle = objectFactory.createBundle();
                        bundle.setLocation(bundleName);
                        // Check the features this feature depends on don't already contain the dependency
                        // TODO Perhaps only for transitive dependencies?
                        boolean includedTransitively =
                            simplifyBundleDependencies && isBundleIncludedTransitively(feature, otherFeatures, bundle);
                        if (!includedTransitively && (!"provided".equals(entry.getScope()) || !ignoreScopeProvided)) {
                            feature.getBundle().add(bundle);
                            needWrap |= bundleNeedsWrapping;
                        }

                        if (
                                (markRuntimeScopeAsDependency && "runtime".equals( entry.getScope() )) ||
                                (markTransitiveAsDependency && entry.isTransitive())
                        ) {
                            bundle.setDependency(true);
                        }
                    }

                    if (startLevel != null && bundle.getStartLevel() == 0) {
                        bundle.setStartLevel(startLevel);
                    }
                }
            }
        }

        if (needWrap) {
            Dependency wrapDependency = new Dependency();
            wrapDependency.setName("wrap");
            wrapDependency.setDependency(false);
            wrapDependency.setPrerequisite(true);
            feature.getFeature().add(wrapDependency);
        }

        if ((!feature.getBundle().isEmpty() || !feature.getFeature().isEmpty()) && !features.getFeature().contains(feature)) {
            features.getFeature().add(feature);
        }

        // Add any missing repositories for the included features
        for (Feature includedFeature : features.getFeature()) {
            for (Dependency dependency : includedFeature.getFeature()) {
                Feature dependedFeature = otherFeatures.get(dependency);
                if (dependedFeature != null && !features.getFeature().contains(dependedFeature)) {
                    String repository = featureRepositories.get(dependedFeature);
                    if (repository != null && !features.getRepository().contains(repository)) {
                        features.getRepository().add(repository);
                    }
                }
            }
        }
        if (useJson) {
            try {
                JacksonUtil.marshal(features, out);
            } catch (Exception e) {
                throw new MojoExecutionException("Can't create features json", e);
            }
        } else {
            JaxbUtil.marshal(features, out);
        }
        try {
            checkChanges(features, objectFactory);
        } catch (Exception e) {
            throw new MojoExecutionException("Features contents have changed", e);
        }
        getLog().info("...done!");
    }