From 824f2219ac1851b2db93e154f04041b359382a0e Mon Sep 17 00:00:00 2001 From: Jess Sightler Date: Thu, 4 Sep 2014 15:08:44 -0400 Subject: [PATCH] WINDUP-241: Port Brad's Manifest Visitor to Windup 2.x --- .../windup/graph/dao/ArchiveService.java | 81 +++++++------- .../graph/model/resource/FileModel.java | 14 ++- .../apps/java/model/JarManifestModel.java | 27 ++--- .../operation/UnzipArchiveToOutputFolder.java | 16 +-- ...coverArchiveManifestFilesRuleProvider.java | 105 ++++++++++++++++++ .../apps/java/service/JarManifestService.java | 28 +++++ ...indupArchitectureMediumBinaryModeTest.java | 28 +++++ 7 files changed, 226 insertions(+), 73 deletions(-) create mode 100644 rules/app/java/src/main/java/org/jboss/windup/rules/apps/java/scan/provider/DiscoverArchiveManifestFilesRuleProvider.java create mode 100644 rules/app/java/src/main/java/org/jboss/windup/rules/apps/java/service/JarManifestService.java diff --git a/graph/api/src/main/java/org/jboss/windup/graph/dao/ArchiveService.java b/graph/api/src/main/java/org/jboss/windup/graph/dao/ArchiveService.java index b5c9422e28..f324976ea6 100644 --- a/graph/api/src/main/java/org/jboss/windup/graph/dao/ArchiveService.java +++ b/graph/api/src/main/java/org/jboss/windup/graph/dao/ArchiveService.java @@ -1,21 +1,18 @@ package org.jboss.windup.graph.dao; -import java.util.Iterator; +import java.util.StringTokenizer; import org.jboss.windup.graph.GraphContext; import org.jboss.windup.graph.model.ArchiveModel; -import org.jboss.windup.graph.model.WindupVertexFrame; -import org.jboss.windup.graph.model.resource.ResourceModel; +import org.jboss.windup.graph.model.resource.FileModel; import org.jboss.windup.graph.service.GraphService; -import com.thinkaurelius.titan.core.attribute.Cmp; -import com.thinkaurelius.titan.core.attribute.Text; -import com.tinkerpop.blueprints.Direction; -import com.tinkerpop.blueprints.Edge; -import com.tinkerpop.blueprints.Vertex; -import com.tinkerpop.gremlin.java.GremlinPipeline; -import com.tinkerpop.pipes.PipeFunction; - +/** + * Provides methods for searching, creating, and deleting ArchiveModel Vertices. + * + * @author jsightler + * + */ public class ArchiveService extends GraphService { public ArchiveService() @@ -28,43 +25,43 @@ public ArchiveService(GraphContext context) super(context, ArchiveModel.class); } - public Iterable findAllRootArchives() + /** + * Finds the file at the provided path within the archive. + * + * Eg, getChildFile(ArchiveModel, "/META-INF/MANIFEST.MF") will return a {@link FileModel} if a file named + * /META-INF/MANIFEST.MF exists within the archive + * + * This function expects filePath to use "/" characters to index within the archive, regardless of the underlying + * operating system platform being used. + * + * @return Returns the located {@link FileModel} or null if no file with this path could be located + */ + public FileModel getChildFile(ArchiveModel archiveModel, String filePath) { - // iterate through all vertices - Iterable pipeline = new GremlinPipeline(getTypedQuery()) - // check to see whether there is an edge coming in that links to the resource providing the java - // class model. - .filter(new PipeFunction() - { - public Boolean compute(Vertex argument) - { - Iterator edges = argument.getEdges(Direction.IN, "child").iterator(); - if (!edges.hasNext()) - { - return true; - } - // if there aren't two edges, return false. - return false; - } - }); - return getGraphContext().getFramed().frameVertices(pipeline, ArchiveModel.class); - } + StringTokenizer stk = new StringTokenizer(filePath, "/"); - public boolean isArchiveResource(ResourceModel resource) - { - return (new GremlinPipeline(resource.asVertex())).out("archiveResourceFacet").iterator() - .hasNext(); + FileModel currentFileModel = archiveModel.getUnzippedDirectory(); + + while (stk.hasMoreTokens() && currentFileModel != null) + { + String pathElement = stk.nextToken(); + + currentFileModel = findFileModel(currentFileModel, pathElement); + } + return currentFileModel; } - public ArchiveModel getArchiveFromResource(ResourceModel resource) + private FileModel findFileModel(FileModel fm, String pathElement) { - Iterator v = (new GremlinPipeline(resource.asVertex())).out("archiveResourceFacet") - .iterator(); - if (v.hasNext()) + FileModel result = null; + for (FileModel child : fm.getFilesInDirectory()) { - return getGraphContext().getFramed().frame(v.next(), ArchiveModel.class); + if (child.getFileName().equals(pathElement)) + { + result = child; + break; + } } - - return null; + return result; } } diff --git a/graph/api/src/main/java/org/jboss/windup/graph/model/resource/FileModel.java b/graph/api/src/main/java/org/jboss/windup/graph/model/resource/FileModel.java index 73444207c2..772a5d7cf4 100644 --- a/graph/api/src/main/java/org/jboss/windup/graph/model/resource/FileModel.java +++ b/graph/api/src/main/java/org/jboss/windup/graph/model/resource/FileModel.java @@ -63,7 +63,7 @@ public interface FileModel extends ResourceModel @Property(MD5_HASH) public void setMD5Hash(String md5Hash); - + @Property(SHA1_HASH) public String getSHA1Hash(); @@ -135,7 +135,16 @@ public String getPrettyPathWithinProject() else { FileModel projectModelFileModel = projectModel.getRootFileModel(); - Path projectPath = Paths.get(projectModelFileModel.getFilePath()); + Path projectPath; + if (projectModelFileModel instanceof ArchiveModel) + { + ArchiveModel archiveModelForProject = (ArchiveModel) projectModelFileModel; + projectPath = Paths.get(archiveModelForProject.getUnzippedDirectory().getFilePath()); + } + else + { + projectPath = Paths.get(projectModelFileModel.getFilePath()); + } List paths = generatePathList(projectPath); return generatePathString(paths); @@ -191,7 +200,6 @@ private void appendPath(List paths, Path stopPath, FileModel fileModel) if (fileModel.getParentFile() != null) { - FileModel parent = fileModel.getParentFile(); appendPath(paths, stopPath, parent); } diff --git a/rules/app/java/src/main/java/org/jboss/windup/rules/apps/java/model/JarManifestModel.java b/rules/app/java/src/main/java/org/jboss/windup/rules/apps/java/model/JarManifestModel.java index de42ab9caf..05bff7cab6 100644 --- a/rules/app/java/src/main/java/org/jboss/windup/rules/apps/java/model/JarManifestModel.java +++ b/rules/app/java/src/main/java/org/jboss/windup/rules/apps/java/model/JarManifestModel.java @@ -1,29 +1,24 @@ package org.jboss.windup.rules.apps.java.model; -import java.util.Set; - +import org.jboss.windup.graph.model.ArchiveModel; import org.jboss.windup.graph.model.resource.FileModel; import com.tinkerpop.blueprints.Direction; import com.tinkerpop.frames.Adjacency; -import com.tinkerpop.frames.modules.javahandler.JavaHandler; import com.tinkerpop.frames.modules.typedgraph.TypeValue; -@TypeValue("JarManifestMeta") +/** + * Contains information from the META-INF/MANIFEST.MF file within an archive. + */ +@TypeValue(JarManifestModel.TYPE) public interface JarManifestModel extends FileModel { - @Adjacency(label = "archive", direction = Direction.IN) - public void setJarArchive(final JarArchiveModel archive); - - @Adjacency(label = "archive", direction = Direction.IN) - public JarArchiveModel getJarArchive(); - - @JavaHandler - public String getProperty(String property); + public static final String TYPE = "JarManifestModel"; + public static final String ARCHIVE = "archive"; - @JavaHandler - public void setProperty(String propertyName, String obj); + @Adjacency(label = ARCHIVE, direction = Direction.IN) + public void setArchive(final ArchiveModel archive); - @JavaHandler - public Set keySet(); + @Adjacency(label = ARCHIVE, direction = Direction.IN) + public ArchiveModel getArchive(); } diff --git a/rules/app/java/src/main/java/org/jboss/windup/rules/apps/java/scan/operation/UnzipArchiveToOutputFolder.java b/rules/app/java/src/main/java/org/jboss/windup/rules/apps/java/scan/operation/UnzipArchiveToOutputFolder.java index 590fe50cd1..5bc1f51552 100644 --- a/rules/app/java/src/main/java/org/jboss/windup/rules/apps/java/scan/operation/UnzipArchiveToOutputFolder.java +++ b/rules/app/java/src/main/java/org/jboss/windup/rules/apps/java/scan/operation/UnzipArchiveToOutputFolder.java @@ -131,7 +131,7 @@ private void unzipToTempDirectory(final GraphContext context, final Path tempFol newFileModel.setParentArchive(archiveModel); // add all unzipped files, and make sure their parent archive is set - recurseAndAddFiles(context, tempFolder, fileService, archiveModel, newFileModel, false); + recurseAndAddFiles(context, tempFolder, fileService, archiveModel, newFileModel); } /** @@ -143,7 +143,7 @@ private void unzipToTempDirectory(final GraphContext context, final Path tempFol */ private void recurseAndAddFiles(GraphContext context, Path tempFolder, FileModelService fileService, ArchiveModel archiveModel, - FileModel parentFileModel, boolean setParentFile) + FileModel parentFileModel) { File fileReference = parentFileModel.asFile(); @@ -154,15 +154,7 @@ private void recurseAndAddFiles(GraphContext context, Path tempFolder, FileModel { for (File subFile : subFiles) { - FileModel subFileModel; - if (setParentFile) - { - subFileModel = fileService.createByFilePath(parentFileModel, subFile.getAbsolutePath()); - } - else - { - subFileModel = fileService.createByFilePath(subFile.getAbsolutePath()); - } + FileModel subFileModel = fileService.createByFilePath(parentFileModel, subFile.getAbsolutePath()); subFileModel.setParentArchive(archiveModel); if (subFile.isFile() && ZipUtil.endsWithZipExtension(subFileModel.getFilePath())) @@ -178,7 +170,7 @@ private void recurseAndAddFiles(GraphContext context, Path tempFolder, FileModel if (subFile.isDirectory()) { - recurseAndAddFiles(context, tempFolder, fileService, archiveModel, subFileModel, true); + recurseAndAddFiles(context, tempFolder, fileService, archiveModel, subFileModel); } } } diff --git a/rules/app/java/src/main/java/org/jboss/windup/rules/apps/java/scan/provider/DiscoverArchiveManifestFilesRuleProvider.java b/rules/app/java/src/main/java/org/jboss/windup/rules/apps/java/scan/provider/DiscoverArchiveManifestFilesRuleProvider.java new file mode 100644 index 0000000000..c80f465a35 --- /dev/null +++ b/rules/app/java/src/main/java/org/jboss/windup/rules/apps/java/scan/provider/DiscoverArchiveManifestFilesRuleProvider.java @@ -0,0 +1,105 @@ +package org.jboss.windup.rules.apps.java.scan.provider; + +import java.io.IOException; +import java.io.InputStream; +import java.util.List; +import java.util.jar.Manifest; +import java.util.logging.Level; +import java.util.logging.Logger; + +import javax.inject.Inject; + +import org.apache.commons.lang.StringUtils; +import org.jboss.windup.config.GraphRewrite; +import org.jboss.windup.config.RulePhase; +import org.jboss.windup.config.WindupRuleProvider; +import org.jboss.windup.config.operation.ruleelement.AbstractIterationOperation; +import org.jboss.windup.config.query.Query; +import org.jboss.windup.graph.GraphContext; +import org.jboss.windup.graph.dao.ArchiveService; +import org.jboss.windup.graph.model.ArchiveModel; +import org.jboss.windup.graph.model.resource.FileModel; +import org.jboss.windup.rules.apps.java.model.JarManifestModel; +import org.jboss.windup.rules.apps.java.service.JarManifestService; +import org.ocpsoft.rewrite.config.ConditionBuilder; +import org.ocpsoft.rewrite.config.Configuration; +import org.ocpsoft.rewrite.config.ConfigurationBuilder; +import org.ocpsoft.rewrite.context.EvaluationContext; + +/** + * Discovers MANIFEST.MF files within archives. + * + * @author jsightler + * + */ +public class DiscoverArchiveManifestFilesRuleProvider extends WindupRuleProvider +{ + private static final Logger LOG = Logger.getLogger(DiscoverArchiveManifestFilesRuleProvider.class.getSimpleName()); + + @Inject + private ArchiveService archiveService; + + @Inject + private JarManifestService jarManifestService; + + @Override + public RulePhase getPhase() + { + return RulePhase.DISCOVERY; + } + + @Override + public List> getExecuteAfter() + { + return asClassList(UnzipArchivesToOutputRuleProvider.class); + } + + @Override + public Configuration getConfiguration(GraphContext context) + { + ConditionBuilder archivesFound = Query.find(ArchiveModel.class); + + return ConfigurationBuilder.begin() + .addRule() + .when(archivesFound) + .perform(new ExtractManifestInformationFromArchive()); + } + + private class ExtractManifestInformationFromArchive extends AbstractIterationOperation + { + @Override + public void perform(GraphRewrite event, EvaluationContext context, ArchiveModel payload) + { + FileModel manifestFile = archiveService.getChildFile(payload, "META-INF/MANIFEST.MF"); + if (manifestFile == null) + { + // no manifest found, skip this one + return; + } + + JarManifestModel jarManifest = jarManifestService.addTypeToModel(manifestFile); + jarManifest.setArchive(payload); + + try (InputStream is = manifestFile.asInputStream()) + { + Manifest manifest = new Manifest(is); + if (manifest == null || manifest.getMainAttributes().size() == 0) + { + 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); + } + } + catch (IOException e) + { + LOG.log(Level.WARNING, "Exception reading manifest from file: " + manifestFile.getFilePath(), e); + } + } + } + +} diff --git a/rules/app/java/src/main/java/org/jboss/windup/rules/apps/java/service/JarManifestService.java b/rules/app/java/src/main/java/org/jboss/windup/rules/apps/java/service/JarManifestService.java new file mode 100644 index 0000000000..60335be3cc --- /dev/null +++ b/rules/app/java/src/main/java/org/jboss/windup/rules/apps/java/service/JarManifestService.java @@ -0,0 +1,28 @@ +package org.jboss.windup.rules.apps.java.service; + +import javax.inject.Inject; + +import org.jboss.windup.graph.GraphContext; +import org.jboss.windup.graph.service.GraphService; +import org.jboss.windup.rules.apps.java.model.JarManifestModel; + +/** + * Manages the creation, querying, and deletion of {@link JarManifestModel}s. + * + * @author jsightler + * + */ +public class JarManifestService extends GraphService +{ + + public JarManifestService() + { + super(JarManifestModel.class); + } + + @Inject + public JarManifestService(GraphContext context) + { + super(context, JarManifestModel.class); + } +} diff --git a/tests/core/src/test/java/org/jboss/windup/tests/application/WindupArchitectureMediumBinaryModeTest.java b/tests/core/src/test/java/org/jboss/windup/tests/application/WindupArchitectureMediumBinaryModeTest.java index d086036fd3..3bd26cd319 100644 --- a/tests/core/src/test/java/org/jboss/windup/tests/application/WindupArchitectureMediumBinaryModeTest.java +++ b/tests/core/src/test/java/org/jboss/windup/tests/application/WindupArchitectureMediumBinaryModeTest.java @@ -13,6 +13,9 @@ import org.jboss.shrinkwrap.api.ShrinkWrap; import org.jboss.windup.engine.WindupProcessor; import org.jboss.windup.graph.GraphContext; +import org.jboss.windup.rules.apps.java.model.JarManifestModel; +import org.jboss.windup.rules.apps.java.service.JarManifestService; +import org.junit.Assert; import org.junit.Test; import org.junit.runner.RunWith; @@ -57,5 +60,30 @@ public void testRunWindupMedium() throws Exception { final String path = "../../test-files/Windup1x-javaee-example.war"; super.runTest(processor, graphContext, path, false); + + validateManifestEntries(); + } + + private void validateManifestEntries() throws Exception + { + JarManifestService jarManifestService = new JarManifestService(graphContext); + Iterable manifests = jarManifestService.findAll(); + + int numberFound = 0; + boolean warManifestFound = false; + for (JarManifestModel manifest : manifests) + { + if (manifest.getArchive().getFileName().equals("Windup1x-javaee-example.war")) + { + Assert.assertEquals("1.0", manifest.asVertex().getProperty("Manifest-Version")); + Assert.assertEquals("Plexus Archiver", manifest.asVertex().getProperty("Archiver-Version")); + Assert.assertEquals("Apache Maven", manifest.asVertex().getProperty("Created-By")); + warManifestFound = true; + } + + numberFound++; + } + Assert.assertEquals(9, numberFound); + Assert.assertTrue(warManifestFound); } }