private static Feature internalAssemble()

in src/main/java/org/apache/sling/feature/builder/FeatureBuilder.java [298:375]


    private static Feature internalAssemble(final List<String> processedFeatures,
            final Feature feature,
            final BuilderContext context) {
        if ( feature.isAssembled() ) {
            return feature;
        }
        if ( processedFeatures.contains(feature.getId().toMvnId()) ) {
            throw new IllegalStateException("Recursive inclusion of " + feature.getId().toMvnId() + " via " + processedFeatures);
        }
        processedFeatures.add(feature.getId().toMvnId());

        // we copy the feature as we set the assembled flag on the result
        final Feature result = feature.copy();

        if ( result.getPrototype() != null) {
            // clear everything in the result, will be added in the process
            result.getVariables().clear();
            result.getBundles().clear();
            result.getFrameworkProperties().clear();
            result.getConfigurations().clear();
            result.getRequirements().clear();
            result.getCapabilities().clear();
            result.setPrototype(null);
            result.getExtensions().clear();

            final Prototype i = feature.getPrototype();

            final Feature f = context.getFeatureProvider().provide(i.getId());
            if ( f == null ) {
                throw new IllegalStateException("Unable to find prototype feature " + i.getId());
            }
            if (f.isFinal()) {
                throw new IllegalStateException(
                        "Prototype feature " + i.getId() + " is marked as final and can't be used in a prototype.");
            }
            final Feature prototypeFeature = internalAssemble(processedFeatures, f, context);

            // process prototype instructions
            processPrototype(prototypeFeature, i);

            // and now merge the prototype feature into the result. No overrides should be needed since the result is empty before
            merge(result, prototypeFeature, context, Collections.emptyList(), Collections.emptyMap(), TRACKING_KEY, true, true);

            // and merge the current feature over the prototype feature into the result
            merge(result, feature, context, Collections.singletonList(
                    ArtifactId.parse(BuilderUtil.CATCHALL_OVERRIDE + BuilderContext.VERSION_OVERRIDE_ALL)),
                    Collections.singletonMap("*", BuilderContext.CONFIG_MERGE_LATEST),
                    TRACKING_KEY, true, false);

            for (Artifact a : result.getBundles()) {
                a.getMetadata().remove(TRACKING_KEY);
                LinkedHashSet<ArtifactId> originList = new LinkedHashSet<>(Arrays.asList(a.getFeatureOrigins()));
                originList.remove(prototypeFeature.getId());
                originList.add(feature.getId());
                a.setFeatureOrigins(originList.toArray(new ArtifactId[0]));
            }
            for (Extension e : result.getExtensions()) {
                if (ExtensionType.ARTIFACTS == e.getType()) {
                    for (Artifact a : e.getArtifacts()) {
                        a.getMetadata().remove(TRACKING_KEY);
                    }
                }
            }
            // correct feature origins
            for(final Configuration cfg : result.getConfigurations()) {
                final List<ArtifactId> origins = cfg.getFeatureOrigins();
                if ( origins.size() == 1 && origins.contains(feature.getId())) {
                    cfg.setFeatureOrigins(null);
                }
            }
        }

        result.setAssembled(true);

        processedFeatures.remove(feature.getId().toMvnId());

        return result;
    }