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);
}
}