package org.apache.maven.plugin.compiler.module; | |
/* | |
* Licensed to the Apache Software Foundation (ASF) under one | |
* or more contributor license agreements. See the NOTICE file | |
* distributed with this work for additional information | |
* regarding copyright ownership. The ASF licenses this file | |
* to you under the Apache License, Version 2.0 (the | |
* "License"); you may not use this file except in compliance | |
* with the License. You may obtain a copy of the License at | |
* | |
* http://www.apache.org/licenses/LICENSE-2.0 | |
* | |
* Unless required by applicable law or agreed to in writing, | |
* software distributed under the License is distributed on an | |
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY | |
* KIND, either express or implied. See the License for the | |
* specific language governing permissions and limitations | |
* under the License. | |
*/ | |
import java.io.File; | |
import java.io.FileInputStream; | |
import java.io.IOException; | |
import java.util.Collections; | |
import java.util.HashMap; | |
import java.util.HashSet; | |
import java.util.LinkedHashMap; | |
import java.util.Map; | |
import java.util.Set; | |
import java.util.jar.JarFile; | |
import java.util.jar.Manifest; | |
import org.apache.maven.plugin.compiler.module.ProjectAnalyzerResult.ModuleNameSource; | |
import org.codehaus.plexus.component.annotations.Component; | |
import org.codehaus.plexus.component.annotations.Requirement; | |
import org.codehaus.plexus.logging.AbstractLogEnabled; | |
/** | |
* Maps artifacts to modules and analyzes the type of required modules | |
* | |
* @author Robert Scholte | |
* @since 3.7.0 | |
*/ | |
@Component( role = ProjectAnalyzer.class ) | |
public class ProjectAnalyzer extends AbstractLogEnabled | |
{ | |
@Requirement( hint = "asm" ) | |
private ModuleInfoParser asmParser; | |
@Requirement( hint = "reflect" ) | |
private ModuleInfoParser reflectParser; | |
public ProjectAnalyzerResult analyze( ProjectAnalyzerRequest request ) | |
throws IOException | |
{ | |
ProjectAnalyzerResult result = new ProjectAnalyzerResult(); | |
Map<File, JavaModuleDescriptor> pathElements = | |
new LinkedHashMap<File, JavaModuleDescriptor>( request.getDependencyArtifacts().size() ); | |
JavaModuleDescriptor baseModuleDescriptor = request.getBaseModuleDescriptor(); | |
Map<String, JavaModuleDescriptor> availableNamedModules = new HashMap<String, JavaModuleDescriptor>(); | |
Map<String, ModuleNameSource> moduleNameSources = new HashMap<String, ModuleNameSource>(); | |
// start from root | |
result.setBaseModuleDescriptor( baseModuleDescriptor ); | |
// collect all modules from path | |
for ( File file : request.getDependencyArtifacts() ) | |
{ | |
JavaModuleDescriptor descriptor = extractDescriptor( file ); | |
if ( descriptor != null ) | |
{ | |
availableNamedModules.put( descriptor.name(), descriptor ); | |
} | |
if ( descriptor == null || descriptor.isAutomatic() ) | |
{ | |
Manifest manifest = extractManifest( file ); | |
String modulename = null; | |
if ( manifest != null ) | |
{ | |
modulename = manifest.getMainAttributes().getValue( "Automatic-Module-Name" ); | |
} | |
if ( modulename != null ) | |
{ | |
moduleNameSources.put( modulename, ModuleNameSource.MANIFEST ); | |
} | |
else if ( descriptor != null ) | |
{ | |
moduleNameSources.put( descriptor.name(), ModuleNameSource.FILENAME ); | |
} | |
} | |
else | |
{ | |
moduleNameSources.put( descriptor.name(), ModuleNameSource.MODULEDESCRIPTOR ); | |
} | |
pathElements.put( file, descriptor ); | |
} | |
result.setPathElements( pathElements ); | |
result.setModuleNameSources( moduleNameSources ); | |
if ( baseModuleDescriptor != null ) | |
{ | |
Set<String> requiredNamedModules = new HashSet<String>(); | |
Set<String> requiredUnnamedModules = new HashSet<String>(); | |
select( baseModuleDescriptor, Collections.unmodifiableMap( availableNamedModules ), requiredNamedModules, | |
requiredUnnamedModules ); | |
result.setRequiredNormalModules( requiredNamedModules ); | |
result.setRequiredAutomaticModules( requiredUnnamedModules ); | |
} | |
return result; | |
} | |
private JavaModuleDescriptor extractDescriptor( File file ) | |
throws IOException | |
{ | |
JavaModuleDescriptor moduleDescriptor; | |
if ( file.isFile() || new File( file, "module-info.class" ).exists() ) | |
{ | |
moduleDescriptor = reflectParser.getModuleDescriptor( file ); | |
if ( moduleDescriptor == null ) | |
{ | |
moduleDescriptor = asmParser.getModuleDescriptor( file ); | |
} | |
} | |
else | |
{ | |
moduleDescriptor = null; | |
} | |
return moduleDescriptor; | |
} | |
private Manifest extractManifest( File file ) | |
throws IOException | |
{ | |
Manifest manifest; | |
if ( file.isFile() ) | |
{ | |
JarFile jarFile = null; | |
try | |
{ | |
jarFile = new JarFile( file ); | |
manifest = jarFile.getManifest(); | |
} | |
finally | |
{ | |
jarFile.close(); | |
} | |
} | |
else if ( new File( file, "META-INF/MANIFEST.MF" ).exists() ) | |
{ | |
manifest = new Manifest( new FileInputStream( new File( file, "META-INF/MANIFEST.MF" ) ) ); | |
} | |
else | |
{ | |
manifest = null; | |
} | |
return manifest; | |
} | |
private void select( JavaModuleDescriptor module, Map<String, JavaModuleDescriptor> availableModules, | |
Set<String> namedModules, Set<String> unnamedModules ) | |
{ | |
for ( JavaModuleDescriptor.JavaRequires requires : module.requires() ) | |
{ | |
String requiresName = requires.name(); | |
JavaModuleDescriptor requiredModule = availableModules.get( requiresName ); | |
if ( requiredModule != null && !requiredModule.isAutomatic() ) | |
{ | |
if ( namedModules.add( requiresName ) ) | |
{ | |
select( requiredModule, availableModules, namedModules, unnamedModules ); | |
} | |
} | |
else | |
{ | |
unnamedModules.add( requiresName ); | |
} | |
} | |
} | |
} |