package org.jboss.windup.rules.apps.java.scan.provider;

import java.io.IOException;
import java.io.InputStream;
import java.util.jar.Manifest;
import java.util.logging.Level;
import java.util.logging.Logger;

import org.apache.commons.lang3.StringUtils;
import org.jboss.windup.config.GraphRewrite;
import org.jboss.windup.config.metadata.RuleMetadata;
import org.jboss.windup.config.phase.ArchiveMetadataExtractionPhase;
import org.jboss.windup.config.query.Query;
import org.jboss.windup.config.ruleprovider.IteratingRuleProvider;
import org.jboss.windup.graph.model.ArchiveModel;
import org.jboss.windup.graph.model.resource.FileModel;
import org.jboss.windup.graph.service.ArchiveService;
import org.jboss.windup.reporting.model.TechnologyTagLevel;
import org.jboss.windup.reporting.service.TechnologyTagService;
import org.jboss.windup.rules.apps.java.model.JarManifestModel;
import org.jboss.windup.rules.apps.java.service.JarManifestService;
import org.jboss.windup.util.Logging;
import org.ocpsoft.rewrite.config.ConditionBuilder;
import org.ocpsoft.rewrite.context.EvaluationContext;

/**
 * Discovers MANIFEST.MF files within archives.
 *
 * @author <a href="mailto:jesse.sightler@gmail.com">Jesse Sightler</a>
 */
@RuleMetadata(phase = ArchiveMetadataExtractionPhase.class, perform = "DiscoverManifestFilesInArchives")
public class DiscoverArchiveManifestFilesRuleProvider extends IteratingRuleProvider<ArchiveModel>
{
    private static final Logger LOG = Logging.get(DiscoverArchiveManifestFilesRuleProvider.class);

    private static final String TECH_TAG = "Manifest";
    private static final TechnologyTagLevel TECH_TAG_LEVEL = TechnologyTagLevel.INFORMATIONAL;

    @Override
    public ConditionBuilder when()
    {
        return Query.fromType(ArchiveModel.class);
    }

    @Override
    public void perform(GraphRewrite event, EvaluationContext context, ArchiveModel payload)
    {
        ArchiveService archiveService = new ArchiveService(event.getGraphContext());
        FileModel manifestFile = archiveService.getChildFile(payload, "META-INF/MANIFEST.MF");
        if (manifestFile == null)
        {
            manifestFile = archiveService.getChildFile(payload, "WEB-INF/classes/META-INF/MANIFEST.MF");
        }

        if (manifestFile == null)
        {
            // no manifest found, skip this one
            return;
        }
        TechnologyTagService technologyTagService = new TechnologyTagService(event.getGraphContext());
        JarManifestService jarManifestService = new JarManifestService(event.getGraphContext());
        technologyTagService.addTagToFileModel(manifestFile, TECH_TAG, TECH_TAG_LEVEL);

        JarManifestModel jarManifest = jarManifestService.addTypeToModel(manifestFile);
        jarManifest.setArchive(payload);
        jarManifest.setGenerateSourceReport(true);

        try (InputStream is = manifestFile.asInputStream())
        {
            Manifest manifest = new Manifest(is);
            if (manifest.getMainAttributes().isEmpty())
            {
                // no manifest found, skip this one
                return;
            }

            for (Object key : manifest.getMainAttributes().keySet())
            {
                String property = StringUtils.trim(key.toString());
                String propertyValue = StringUtils.trim(manifest.getMainAttributes().get(key).toString());
                jarManifest.asVertex().setProperty(property, propertyValue);
            }

            if (StringUtils.isBlank(jarManifest.getName())) {
                // if the name is still blank, try to get it from the first entry in the file list.
                // A few apache projects do it this way
                for (String entry : manifest.getEntries().keySet()) {
                    for (Object key : manifest.getAttributes(entry).keySet())
                    {
                        String property = StringUtils.trim(key.toString());
                        String propertyValue = StringUtils.trim(manifest.getAttributes(entry).get(key).toString());
                        if (StringUtils.isBlank((String)jarManifest.asVertex().getProperty(property)))
                            jarManifest.asVertex().setProperty(property, propertyValue);
                    }
                    if (!StringUtils.isBlank(jarManifest.getName()))
                        break;
                }
            }
        }
        catch (IOException e)
        {
            LOG.log(Level.WARNING, "Exception reading manifest from file: " + manifestFile.getFilePath(), e);
        }
    }

}

@@ -106,16 +106,41 @@
 Stream;%0A
+import java.util.Arrays;%0A
 import j
@@ -1938,338 +1938,551 @@
     
-ArchiveService archiveService = new ArchiveService(event.getGraphContext()
+String%5B%5D filenames = %7B%0A                    %22META-INF/MANIFEST.MF%22,%0A                    %22WEB-INF/classes/META-INF/MANIFEST.MF%22%0A        %7D;%0A        Arrays.stream(filenames).forEach(filename -%3E %7B%0A            importManifest(event, payload, filename);%0A        %7D
 );%0A    
+%7D%0A%0A
     
-FileModel manifestFile = archiveService.getChildFile(payload, %22META-INF/MANIFEST.MF%22);%0A        if (manifestFile == null)%0A        %7B%0A            manifestFile = archiveService.getChildFile(payload, %22WEB-INF/classes/META-INF/MANIFEST.MF%22);%0A        %7D
+private void importManifest(GraphRewrite event, ArchiveModel archive, String manifestFilePath)%0A    %7B%0A        ArchiveService archiveService = new ArchiveService(event.getGraphContext());%0A        FileModel manifestFile = archiveService.getChildFile(archive, manifestFilePath);
 %0A%0A  
@@ -3009,23 +3009,23 @@
 Archive(
-payload
+archive
 );%0A     
@@ -3761,16 +3761,28 @@
 Name()))
+%0A           
  %7B%0A     
@@ -3999,16 +3999,32 @@
 eySet())
+%0A               
  %7B%0A     
@@ -4366,16 +4366,17 @@
 (String)
+ 
 jarManif
@@ -4833,11 +4833,10 @@
 %7D%0A    %7D%0A
-%0A
 %7D%0A

Support multiple manifest.mf files in an archive