private void changeManifestClasspath()

in src/main/java/org/apache/maven/plugins/ear/EarMojo.java [742:960]


    private void changeManifestClasspath( EarModule module, File original, JavaEEVersion javaEEVersion,
                                          Collection<String> outdatedResources )
        throws MojoFailureException
    {
        final String moduleLibDir = module.getLibDir();
        if ( !( ( moduleLibDir == null ) || skinnyModules || ( skinnyWars && module instanceof WebModule ) ) )
        {
            return;
        }

        // for new created items
        FileTime outputFileTime = MavenArchiver.parseBuildOutputTimestamp( outputTimestamp )
            .map( FileTime::from )
            .orElse( null );

        FileSystem fileSystem = null;

        try
        {
            Path workDirectory;

            // Handle the case that the destination might be a directory (project-038)
            // We can get FileSystems only for files
            if ( original.isFile() )
            {
                fileSystem = FileSystems.newFileSystem(
                    original.toPath(), Thread.currentThread().getContextClassLoader() );
                workDirectory = fileSystem.getRootDirectories().iterator().next();
            }
            else
            {
                workDirectory = original.toPath();
            }

            // Create a META-INF/MANIFEST.MF file if it doesn't exist (project-038)
            Path metaInfDirectory = workDirectory.resolve( "META-INF" );
            if ( !Files.exists( metaInfDirectory ) )
            {
                Files.createDirectory( metaInfDirectory );
                if ( outputFileTime != null )
                {
                    Files.setLastModifiedTime( metaInfDirectory, outputFileTime );
                }
                getLog().debug(
                    "This project did not have a META-INF directory before, so a new directory was created." );
            }
            Path manifestFile = metaInfDirectory.resolve( "MANIFEST.MF" );
            if ( !Files.exists( manifestFile ) )
            {
                Files.createFile( manifestFile );
                if ( outputFileTime != null )
                {
                    Files.setLastModifiedTime( manifestFile, outputFileTime );
                }
                getLog().debug(
                    "This project did not have a META-INF/MANIFEST.MF file before, so a new file was created." );
            }

            Manifest mf = readManifest( manifestFile );
            Attribute classPath = mf.getMainSection().getAttribute( "Class-Path" );
            List<String> classPathElements = new ArrayList<>();

            boolean classPathExists;
            if ( classPath != null )
            {
                classPathExists = true;
                classPathElements.addAll( Arrays.asList( classPath.getValue().split( " " ) ) );
            }
            else
            {
                classPathExists = false;
                classPath = new Attribute( "Class-Path", "" );
            }

            if ( ( moduleLibDir != null ) && ( skinnyModules || ( skinnyWars && module instanceof WebModule ) ) )
            {
                // Remove modules
                for ( EarModule otherModule : getAllEarModules() )
                {
                    if ( module.equals( otherModule ) )
                    {
                        continue;
                    }
                    // MEAR-189:
                    // We use the original name, cause in case of outputFileNameMapping
                    // we could not not delete it and it will end up in the resulting EAR and the WAR
                    // will not be cleaned up.
                    final Path workLibDir = workDirectory.resolve( moduleLibDir );
                    Path artifact = workLibDir.resolve( module.getArtifact().getFile().getName() );

                    // MEAR-217
                    // If WAR contains files with timestamps, but EAR strips them away (useBaseVersion=true)
                    // the artifact is not found. Therefore, respect the current fileNameMapping additionally.

                    if ( !Files.exists( artifact ) )
                    {
                        getLog().debug( "module does not exist with original file name." );
                        artifact = workLibDir.resolve( otherModule.getBundleFileName() );
                        getLog().debug( "Artifact with mapping: " + artifact.toAbsolutePath() );
                    }

                    if ( !Files.exists( artifact ) )
                    {
                        getLog().debug( "Artifact with mapping does not exist." );
                        artifact = workLibDir.resolve( otherModule.getArtifact().getFile().getName() );
                        getLog().debug( "Artifact with original file name: " + artifact.toAbsolutePath() );
                    }

                    if ( !Files.exists( artifact ) )
                    {
                        getLog().debug( "Artifact with original file name does not exist." );
                        final Artifact otherModuleArtifact = otherModule.getArtifact();
                        if ( otherModuleArtifact.isSnapshot() )
                        {
                            try
                            {
                                artifact = workLibDir.resolve( MappingUtils.evaluateFileNameMapping(
                                        ARTIFACT_DEFAULT_FILE_NAME_MAPPING, otherModuleArtifact ) );
                                getLog()
                                    .debug( "Artifact with default mapping file name: " + artifact.toAbsolutePath() );
                            }
                            catch ( InterpolationException e )
                            {
                                getLog().warn(
                                    "Failed to evaluate file name for [" + otherModule + "] module using mapping: "
                                        + ARTIFACT_DEFAULT_FILE_NAME_MAPPING );
                            }
                        }
                    }

                    if ( Files.exists( artifact ) )
                    {
                        getLog().debug( " -> Artifact to delete: " + artifact );
                        Files.delete( artifact );
                    }
                }
            }

            // Modify the classpath entries in the manifest
            final boolean forceClassPathModification =
                javaEEVersion.lt( JavaEEVersion.FIVE ) || defaultLibBundleDir == null;
            final boolean classPathExtension = !skipClassPathModification || forceClassPathModification;
            for ( EarModule otherModule : getModules() )
            {
                if ( module.equals( otherModule ) )
                {
                    continue;
                }
                final int moduleClassPathIndex = findModuleInClassPathElements( classPathElements, otherModule );
                if ( moduleClassPathIndex != -1 )
                {
                    if ( otherModule.isClassPathItem() )
                    {
                        classPathElements.set( moduleClassPathIndex, otherModule.getUri() );
                    }
                    else
                    {
                        classPathElements.remove( moduleClassPathIndex );
                    }
                }
                else if ( otherModule.isClassPathItem() && classPathExtension )
                {
                    classPathElements.add( otherModule.getUri() );
                }
            }

            // Remove provided modules from classpath
            for ( EarModule otherModule : getProvidedEarModules() )
            {
                final int moduleClassPathIndex = findModuleInClassPathElements( classPathElements, otherModule );
                if ( moduleClassPathIndex != -1 )
                {
                    classPathElements.remove( moduleClassPathIndex );
                }
            }

            if ( !skipClassPathModification || !classPathElements.isEmpty() || classPathExists )
            {
                classPath.setValue( StringUtils.join( classPathElements.iterator(), " " ) );
                mf.getMainSection().addConfiguredAttribute( classPath );

                // Write the manifest to disk, preserve timestamp
                FileTime lastModifiedTime = Files.getLastModifiedTime( manifestFile );
                try ( BufferedWriter writer = Files.newBufferedWriter( manifestFile, StandardCharsets.UTF_8,
                                                                       StandardOpenOption.WRITE,
                                                                       StandardOpenOption.CREATE,
                                                                       StandardOpenOption.TRUNCATE_EXISTING ) )
                {
                    mf.write( writer );
                }
                Files.setLastModifiedTime( manifestFile, lastModifiedTime );
                removeFromOutdatedResources( manifestFile, outdatedResources );
            }

            if ( fileSystem != null )
            {
                fileSystem.close();
                fileSystem = null;
            }
        }
        catch ( ManifestException | IOException | ArchiverException e )
        {
            throw new MojoFailureException( e.getMessage(), e );
        }
        finally
        {
            if ( fileSystem != null )
            {
                try
                {
                    fileSystem.close();
                }
                catch ( IOException e )
                {
                    // ignore here
                }
            }
        }
    }