public void execute()

in nbm-maven-plugin/src/main/java/org/apache/netbeans/nbm/CreateClusterAppMojo.java [188:586]


    public void execute() throws MojoExecutionException, MojoFailureException {

        File nbmBuildDirFile = new File(outputDirectory, brandingToken);
        if (!nbmBuildDirFile.exists()) {
            nbmBuildDirFile.mkdirs();
        }

        if ("nbm-application".equals(project.getPackaging())) {
            Project antProject = registerNbmAntTasks();

            Set<String> wrappedBundleCNBs = new HashSet<>(100);
            Map<String, Set<String>> clusterDependencies = new HashMap<>();
            Map<String, Set<String>> clusterModules = new HashMap<>();

            //verify integrity
            Set<String> modulesCNBs = new HashSet<>(SET_INITIAL_SIZE);
            Set<String> dependencyCNBs = new HashSet<>(SET_INITIAL_SIZE);
            Map<String, Set<String>> dependencyCNBBacktraces = new HashMap<>(MAP_INITIALSIZE);
            Set<String> requireTokens = new HashSet<>(MAP_INITIALSIZE);
            Map<String, Set<String>> requireTokensBacktraces = new HashMap<>(MAP_INITIALSIZE);
            Set<String> provideTokens = new HashSet<>(MAP_INITIALSIZE);
            Set<String> osgiImports = new HashSet<>(MAP_INITIALSIZE);
            Map<String, Set<String>> osgiImportsBacktraces = new HashMap<>(MAP_INITIALSIZE);
            Set<String> osgiExports = new HashSet<>(MAP_INITIALSIZE);
            //a way to deal with nb module declaring xxx.** (subpackages) declaration that is consumed by osgi imports
            Set<String> osgiExportsSubs = new HashSet<>(MAP_INITIALSIZE);

            List<BundleTuple> bundles = new ArrayList<>();

            @SuppressWarnings("unchecked")
            Set<Artifact> artifacts = project.getArtifacts();
            for (Artifact art : artifacts) {
                ArtifactResult res = turnJarToNbmFile(art, artifactFactory, artifactResolver, project, session.getLocalRepository());
                if (res.hasConvertedArtifact()) {
                    art = res.getConvertedArtifact();
                }

                if (art.getType().equals("nbm-file")) {
                    try {
                        JarFile jf = new JarFile(art.getFile());
                        try {
                            String clusterName = findCluster(jf);
                            ClusterTuple cluster = processCluster(clusterName, nbmBuildDirFile, art);

                            getLog().debug("Copying " + art.getId() + " to cluster " + clusterName);
                            Enumeration<JarEntry> enu = jf.entries();

                            // we need to trigger this ant task to generate the update_tracking file.
                            MakeListOfNBM makeTask = (MakeListOfNBM) antProject.createTask("genlist");
                            antProject.setNewProperty("module.name", art.getFile().getName()); // TODO
                            antProject.setProperty("cluster.dir", clusterName);
                            FileSet set = makeTask.createFileSet();
                            set.setDir(cluster.location);
                            makeTask.setOutputfiledir(cluster.location);
                            String[] executables = null;
                            File classpathRoot = null;
                            String classPath = null;
                            while (enu.hasMoreElements()) {
                                JarEntry ent = enu.nextElement();
                                String name = ent.getName();
                                //MNBMODULE-176
                                if (name.equals("Info/executables.list")) {
                                    if (cluster.newer) {
                                        InputStream is = jf.getInputStream(ent);
                                        executables = StringUtils.split(IOUtil.toString(is, "UTF-8"), "\n");
                                    }
                                } else if (name.startsWith("netbeans/")) { // ignore everything else.
                                    String path = clusterName + name.substring("netbeans".length());
                                    boolean ispack200 = path.endsWith(".jar.pack.gz");
                                    if (ispack200) {
                                        path = path.replace(".jar.pack.gz", ".jar");
                                    }
                                    File fl = new File(nbmBuildDirFile, path.replace("/", File.separator));
                                    String part = name.substring("netbeans/".length());
                                    if (ispack200) {
                                        part = part.replace(".jar.pack.gz", ".jar");
                                    }
                                    if (cluster.newer) {
                                        if (ent.isDirectory()) {
                                            fl.mkdirs();
                                        } else if (path.endsWith(".external")) // MNBMODULE-138
                                        {
                                            InputStream is = jf.getInputStream(ent);
                                            try {
                                                externalDownload(new File(fl.getParentFile(),
                                                        fl.getName().replaceFirst("[.]external$", "")), is);
                                            } finally {
                                                is.close();
                                            }
                                            //MNBMODULE-192
                                            set.appendIncludes(new String[]{
                                                name.substring("netbeans/".length(), name.length() - ".external".length())
                                            });
                                        } else {
                                            set.appendIncludes(new String[]{
                                                part
                                            });

                                            fl.getParentFile().mkdirs();
                                            fl.createNewFile();
                                            try (BufferedOutputStream outstream = new BufferedOutputStream(new FileOutputStream(fl))) {
                                                InputStream instream = jf.getInputStream(ent);
                                                if (ispack200) {
                                                    try (JarOutputStream jos = new JarOutputStream(outstream)) {
                                                        Pack200.Unpacker unp = Pack200.newUnpacker();
                                                        GZIPInputStream gzip = new GZIPInputStream(instream);
                                                        unp.unpack(gzip, jos);
                                                    } catch (LinkageError cnfe) {
                                                        throw new BuildException("Using jdk 14 and later prevents "
                                                                + "reading of NBM created with pack200");
                                                    }
                                                } else {
                                                    IOUtil.copy(instream, outstream);
                                                }
                                            }
                                        }
                                    }

                                    // TODO examine netbeans/config/Modules to see if the module is autoload/eager
                                    // in verifyIntegrity these could be handled more gracefully than regular modules.
                                    // eager is simpler, does not need to have module dependencies satisfied.
                                    // autoload needs checking if any of the other modules declares a dependency on it.
                                    // if not, also safe to ignore?
                                    // now figure which one of the jars is the module jar..
                                    if (part.matches("(modules|core|lib)/[^/]+[.]jar")) {
                                        ExamineManifest ex = new ExamineManifest(getLog());
                                        ex.setJarFile(fl);
                                        ex.setPopulateDependencies(true);
                                        ex.checkFile();
                                        if (ex.isNetBeansModule()) {
                                            makeTask.setModule(part);
                                            addToMap(clusterDependencies, clusterName, ex.getDependencyTokens());
                                            addToMap(clusterModules, clusterName, Collections.singletonList(ex.
                                                    getModule()));
                                            if (ex.getClasspath().length() > 0) { //MNBMODULE-220
                                                try {
                                                    classPath = URLDecoder.decode(ex.getClasspath(), "UTF-8");
                                                } catch (UnsupportedEncodingException exception) {
                                                    throw new IllegalStateException(exception);
                                                }
                                                classpathRoot = fl.getParentFile();
                                            }
                                        }
                                        if (verifyIntegrity) {
                                            dependencyCNBs.addAll(ex.getDependencyTokens());
                                            modulesCNBs.add(ex.getModule());
                                            for (String d : ex.getDependencyTokens()) {
                                                addToMap(dependencyCNBBacktraces, d, Collections.singletonList(ex.
                                                        getModule()));
                                            }
                                            if (ex.isNetBeansModule()) {
                                                requireTokens.addAll(ex.getNetBeansRequiresTokens());
                                                for (String r : ex.getNetBeansRequiresTokens()) {
                                                    addToMap(requireTokensBacktraces, r, Collections.singletonList(ex.
                                                            getModule()));
                                                }
                                                provideTokens.addAll(ex.getNetBeansProvidesTokens());
                                                for (String pack : ex.getPackages()) {
                                                    if (pack.endsWith(".**")) {
                                                        //what to do with subpackages?
                                                        pack = pack.substring(0, pack.length() - ".**".length());
                                                        osgiExportsSubs.add(pack);
                                                    } else if (pack.endsWith(".*")) {
                                                        pack = pack.substring(0, pack.length() - ".*".length());
                                                        osgiExports.add(pack);
                                                    }
                                                }

                                            }
                                        }
                                    }
                                }
                            }
                            if (classPath != null) { // MNBMODULE-220 collect wrappedbundleCNBs, later useful in assignClustersToBundles(),
                                // these get removed from list of bundles.
                                String[] paths = StringUtils.split(classPath, " ");
                                for (String path : paths) {
                                    path = path.trim();
                                    File classpathFile = new File(classpathRoot, path);
                                    if (path.equals("${java.home}/lib/ext/jfxrt.jar")) { //MNBMODULE-228
                                        String jhm = System.getProperty("java.home");
                                        classpathFile = new File(new File(new File(new File(jhm), "lib"), "ext"),
                                                "jfxrt.jar");
                                        if (!classpathFile.exists()) {
                                            File jdk7 = new File(new File(new File(jhm), "lib"), "jfxrt.jar");
                                            if (jdk7.exists()) {
                                                classpathFile = jdk7;
                                            }
                                        }
                                    }
                                    if (!classpathFile.isFile()) {
                                        getLog().warn("Could not resolve Class-Path item in " + art.getId()
                                                + ", path is:" + path + ", skipping");
                                        continue; //try to guard against future failures
                                    }
                                    ExamineManifest ex = new ExamineManifest(getLog());
                                    ex.setJarFile(classpathFile);
                                    //ex.setPopulateDependencies( true );
                                    ex.checkFile();
                                    if (ex.isOsgiBundle()) {
                                        if (art.getId().contains(groupIdPrefix
                                                + ".modules:org-netbeans-modules-maven-embedder")) {
                                            // in this case we dont want module-maven-embedder to be considered as
                                            // wrapper for his libs guava is provided but ide have it also
                                        } else {
                                            getLog().debug(ex.getModule() + " added by " + art.getId() + " located in: " + classpathFile);
                                            wrappedBundleCNBs.add(ex.getModule());
                                        }
                                    }
                                }
                            }
                            if (cluster.newer) {
                                try {
                                    makeTask.execute();
                                } catch (BuildException e) {
                                    getLog().error("Cannot Generate update_tracking XML file from " + art.getFile());
                                    throw new MojoExecutionException(e.getMessage(), e);
                                }

                                if (executables != null) {
                                    //MNBMODULE-176
                                    for (String exec : executables) {
                                        exec = exec.replace("/", File.separator);
                                        File execFile = new File(cluster.location, exec);
                                        if (execFile.exists()) {
                                            execFile.setExecutable(true, false);
                                        }
                                    }
                                }
                            }

                        } finally {
                            jf.close();
                        }
                    } catch (IOException ex) {
                        getLog().error(art.getFile().getAbsolutePath(), ex);
                    }
                }
                if (res.isOSGiBundle()) {
                    ExamineManifest ex = res.getExaminedManifest();
                    bundles.add(new BundleTuple(art, ex));
                    if (verifyIntegrity) {
                        dependencyCNBs.addAll(ex.getDependencyTokens());
                        for (String d : ex.getDependencyTokens()) {
                            addToMap(dependencyCNBBacktraces, d, Collections.singletonList(ex.getModule()));
                        }
                        modulesCNBs.add(ex.getModule());
                        osgiImports.addAll(ex.getOsgiImports());
                        for (String d : ex.getOsgiImports()) {
                            addToMap(osgiImportsBacktraces, d, Collections.singletonList(ex.getModule()));
                        }

                        osgiExports.addAll(ex.getOsgiExports());
                    }
                }
            }

            if (verifyIntegrity) {
                if (getLog().isDebugEnabled()) {
                    getLog().debug("All found codenamebases:" + Arrays.toString(modulesCNBs.toArray()));
                    getLog().debug("All found OSGI exports:" + Arrays.toString(osgiExports.toArray()));
                    getLog().debug("All found provided tokens:" + Arrays.toString(provideTokens.toArray()));
                }
                dependencyCNBs.removeAll(modulesCNBs);
                if (modulesCNBs.contains("org.netbeans.modules.netbinox")) {
                    dependencyCNBs.remove("org.eclipse.osgi"); //this is special.
                }
                osgiImports.removeAll(osgiExports);
                Iterator<String> it = osgiImports.iterator();
                while (it.hasNext()) {
                    String s = it.next();
                    if (s.startsWith("java.")
                            || s.startsWith("javax.")
                            || s.startsWith("sun.")
                            || s.startsWith("org.xml.sax")
                            || s.startsWith("org.w3c.dom")
                            || s.startsWith("org.ietf.jgss")) {
                        it.remove();
                        continue;
                    }
                    for (String sub : osgiExportsSubs) {
                        if (s.startsWith(sub)) {
                            it.remove();
                            break;
                        }
                    }
                }
                requireTokens.removeAll(provideTokens);
                requireTokens.removeAll(defaultPlatformTokens);
                if (!dependencyCNBs.isEmpty() || !osgiImports.isEmpty() || !requireTokens.isEmpty()) {
                    if (!dependencyCNBs.isEmpty()) {
                        getLog().error(
                                "Some included modules/bundles depend on these codenamebases but they are not included."
                                + " The application will fail starting up. The missing codenamebases are:");
                        for (String s : dependencyCNBs) {
                            Set<String> back = dependencyCNBBacktraces.get(s);
                            getLog().error("   " + s + (back != null ? "          ref: " + Arrays.toString(back.
                                    toArray()) : ""));
                        }
                    }
                    if (!osgiImports.isEmpty()) {
                        getLog().error(
                                "Some OSGi imports are not satisfied by included bundles' exports. "
                                + "The application will fail starting up. The missing imports are:");
                        for (String s : osgiImports) {
                            Set<String> back = osgiImportsBacktraces.get(s);
                            getLog().error("   " + s + (back != null ? "          ref: " + Arrays.toString(back.
                                    toArray()) : ""));
                        }
                    }
                    if (!requireTokens.isEmpty()) {
                        getLog().error(
                                "Some tokens required by included modules are not provided by included modules. "
                                + "The application will fail starting up. The missing tokens are:");
                        for (String s : requireTokens) {
                            Set<String> back = requireTokensBacktraces.get(s);
                            getLog().error("   " + s + (back != null ? "          ref: " + Arrays.toString(back.
                                    toArray()) : ""));
                        }
                    }
                    throw new MojoFailureException(
                            "See above for consistency validation check failures. "
                            + " Either fix those by adding the relevant dependencies to the application or "
                            + "disable the check by setting the verifyIntegrity parameter to false or by running with "
                            + "-Dnetbeans.verify.integrity=false cmd line parameter.");
                } else {
                    getLog().info("Integrity verification passed.");
                }
            } else {
                getLog().info("Integrity verification skipped.");
            }

            //attempt to sort clusters based on the dependencies and cluster content.
            Map<String, Set<String>> cluster2depClusters = computeClusterOrdering(clusterDependencies, clusterModules);
            clusterModules.clear();

            //now assign the cluster to bundles based on dependencies..
            assignClustersToBundles(bundles, wrappedBundleCNBs, clusterDependencies, cluster2depClusters, getLog());

            for (BundleTuple ent : bundles) {
                Artifact art = ent.artifact;
                final ExamineManifest ex = ent.manifest;

                String clstr = ent.cluster;
                if (clstr == null) {
                    clstr = defaultCluster;
                }

                ClusterTuple cluster = processCluster(clstr, nbmBuildDirFile, art);
                if (cluster.newer) {
                    getLog().info("Copying " + art.getId() + " to cluster " + clstr);
                    File modules = new File(cluster.location, "modules");
                    modules.mkdirs();
                    File config = new File(cluster.location, "config");
                    File confModules = new File(config, "Modules");
                    confModules.mkdirs();
                    File updateTracking = new File(cluster.location, "update_tracking");
                    updateTracking.mkdirs();
                    final String cnb = ex.getModule();
                    final String cnbDashed = cnb.replace(".", "-");
                    //do we need the file in some canotical name pattern in moduleArt?
                    final File moduleArt = new File(modules, cnbDashed + ".jar");
                    final String specVer = ex.getSpecVersion();
                    try {
                        FileUtils.copyFile(art.getFile(), moduleArt);
                        final File moduleConf = new File(confModules, cnbDashed + ".xml");
                        FileUtils.copyStreamToFile(() -> new StringInputStream(createBundleConfigFile(cnb, ex.isBundleAutoload()), "UTF-8"), moduleConf);
                        FileUtils.copyStreamToFile(() -> new StringInputStream(createBundleUpdateTracking(cnb, moduleArt, moduleConf, specVer), "UTF-8"), new File(updateTracking, cnbDashed + ".xml"));
                    } catch (IOException exc) {
                        getLog().error(exc);
                    }
                }
            }
            getLog().info("Created NetBeans module cluster(s) at " + nbmBuildDirFile.getAbsoluteFile());

        } else {
            throw new MojoExecutionException("This goal only makes sense on project with nbm-application packaging");
        }
        //in 6.1 the rebuilt modules will be cached if the timestamp is not touched.
        File[] files = nbmBuildDirFile.listFiles();
        for (File file : files) {
            if (file.isDirectory()) {
                File stamp = new File(file, ".lastModified");
                if (!stamp.exists()) {
                    try {
                        stamp.createNewFile();
                    } catch (IOException ex) {
                        ex.printStackTrace();
                    }
                }
                stamp.setLastModified(getOutputTimestampOrNow(project).getTime());
            }
        }
        try {
            createBinEtcDir(nbmBuildDirFile, brandingToken);
        } catch (IOException ex) {
            throw new MojoExecutionException("Cannot process etc folder content creation.", ex);
        }
    }