in nbm-maven-plugin/src/main/java/org/apache/netbeans/nbm/CreateClusterAppMojo.java [195:732]
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();
BufferedOutputStream outstream = null;
try
{
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 );
}
}
finally
{
IOUtil.close( 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().info( ex.getModule() + " added by " + art.getId() + ""
+ 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 InputStreamFacade()
{
@Override
public InputStream getInputStream() throws IOException
{
return new StringInputStream( createBundleConfigFile( cnb, ex.isBundleAutoload() ),
"UTF-8" );
}
}, moduleConf );
FileUtils.copyStreamToFile( new InputStreamFacade()
{
@Override
public InputStream getInputStream() throws IOException
{
return 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( new Date().getTime() );
}
}
try
{
createBinEtcDir( nbmBuildDirFile, brandingToken );
}
catch ( IOException ex )
{
throw new MojoExecutionException(
"Cannot process etc folder content creation.", ex );
}
}