View Javadoc
1   package org.apache.maven.plugin.compiler.module;
2   
3   /*
4    * Licensed to the Apache Software Foundation (ASF) under one
5    * or more contributor license agreements.  See the NOTICE file
6    * distributed with this work for additional information
7    * regarding copyright ownership.  The ASF licenses this file
8    * to you under the Apache License, Version 2.0 (the
9    * "License"); you may not use this file except in compliance
10   * with the License.  You may obtain a copy of the License at
11   *
12   *   http://www.apache.org/licenses/LICENSE-2.0
13   *
14   * Unless required by applicable law or agreed to in writing,
15   * software distributed under the License is distributed on an
16   * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
17   * KIND, either express or implied.  See the License for the
18   * specific language governing permissions and limitations
19   * under the License.
20   */
21  
22  import java.io.File;
23  import java.io.FileInputStream;
24  import java.io.IOException;
25  import java.util.Collections;
26  import java.util.HashMap;
27  import java.util.HashSet;
28  import java.util.LinkedHashMap;
29  import java.util.Map;
30  import java.util.Set;
31  import java.util.jar.JarFile;
32  import java.util.jar.Manifest;
33  
34  import org.apache.maven.plugin.compiler.module.ProjectAnalyzerResult.ModuleNameSource;
35  import org.codehaus.plexus.component.annotations.Component;
36  import org.codehaus.plexus.component.annotations.Requirement;
37  import org.codehaus.plexus.logging.AbstractLogEnabled;
38  
39  /**
40   * Maps artifacts to modules and analyzes the type of required modules
41   * 
42   * @author Robert Scholte
43   * @since 3.7.0
44   */
45  @Component( role = ProjectAnalyzer.class )
46  public class ProjectAnalyzer extends AbstractLogEnabled
47  {
48      @Requirement( hint = "asm" )
49      private ModuleInfoParser asmParser;
50  
51      @Requirement( hint = "reflect" )
52      private ModuleInfoParser reflectParser;
53  
54      public ProjectAnalyzerResult analyze( ProjectAnalyzerRequest request )
55          throws IOException
56      {
57          ProjectAnalyzerResult result = new ProjectAnalyzerResult();
58          
59          Map<File, JavaModuleDescriptor> pathElements =
60              new LinkedHashMap<File, JavaModuleDescriptor>( request.getDependencyArtifacts().size() );
61  
62          JavaModuleDescriptor baseModuleDescriptor = request.getBaseModuleDescriptor();
63  
64          Map<String, JavaModuleDescriptor> availableNamedModules = new HashMap<String, JavaModuleDescriptor>(); 
65          
66          Map<String, ModuleNameSource> moduleNameSources = new HashMap<String, ModuleNameSource>();
67          
68          // start from root
69          result.setBaseModuleDescriptor( baseModuleDescriptor );
70  
71          // collect all modules from path
72          for ( File file : request.getDependencyArtifacts() )
73          {
74              JavaModuleDescriptor descriptor = extractDescriptor( file );
75  
76              if ( descriptor != null )
77              {
78                  availableNamedModules.put( descriptor.name(), descriptor );
79              }
80              
81              if ( descriptor == null || descriptor.isAutomatic() )
82              {
83                  Manifest manifest = extractManifest( file );
84  
85                  String modulename = null;
86                  
87                  if ( manifest != null )
88                  {
89                      modulename = manifest.getMainAttributes().getValue( "Automatic-Module-Name" );
90                  }
91  
92                  if ( modulename != null )
93                  {
94                      moduleNameSources.put( modulename, ModuleNameSource.MANIFEST );
95                  }
96                  else if ( descriptor != null )
97                  {
98                      moduleNameSources.put( descriptor.name(), ModuleNameSource.FILENAME );
99                  }
100             }
101             else
102             {
103                 moduleNameSources.put( descriptor.name(), ModuleNameSource.MODULEDESCRIPTOR );
104             }
105             
106             pathElements.put( file, descriptor );
107         }
108         result.setPathElements( pathElements );
109         
110         result.setModuleNameSources( moduleNameSources );
111 
112         if ( baseModuleDescriptor != null )
113         {
114             Set<String> requiredNamedModules = new HashSet<String>();
115             Set<String> requiredUnnamedModules = new HashSet<String>();
116             
117             select( baseModuleDescriptor, Collections.unmodifiableMap( availableNamedModules ), requiredNamedModules,
118                     requiredUnnamedModules );
119             
120             result.setRequiredNormalModules( requiredNamedModules );
121             result.setRequiredAutomaticModules( requiredUnnamedModules );
122         }
123 
124         return result;
125     }
126 
127     private JavaModuleDescriptor extractDescriptor( File file )
128         throws IOException
129     {
130         JavaModuleDescriptor moduleDescriptor;
131         if ( file.isFile() || new File( file, "module-info.class" ).exists() )
132         {
133             moduleDescriptor = reflectParser.getModuleDescriptor( file );
134 
135             if ( moduleDescriptor == null )
136             {
137                 moduleDescriptor = asmParser.getModuleDescriptor( file );
138             }
139         }
140         else
141         {
142             moduleDescriptor = null;
143         }
144         return moduleDescriptor;
145     }
146 
147     private Manifest extractManifest( File file )
148         throws IOException
149     {
150         Manifest manifest;
151         if ( file.isFile() )
152         {
153             JarFile jarFile = null;
154             try
155             {
156                 jarFile = new JarFile( file );
157                 manifest = jarFile.getManifest();
158             }
159             finally
160             {
161                 jarFile.close();
162             }
163         }
164         else if ( new File( file, "META-INF/MANIFEST.MF" ).exists() )
165         {
166             manifest = new Manifest( new FileInputStream( new File( file, "META-INF/MANIFEST.MF" ) ) );
167         }
168         else
169         {
170             manifest = null;
171         }
172 
173         return manifest;
174     }
175 
176 
177     private void select( JavaModuleDescriptor module, Map<String, JavaModuleDescriptor> availableModules,
178                          Set<String> namedModules, Set<String> unnamedModules )
179     {
180         for ( JavaModuleDescriptor.JavaRequires requires : module.requires() )
181         {
182             String requiresName = requires.name();
183             JavaModuleDescriptor requiredModule = availableModules.get( requiresName );
184 
185             if ( requiredModule != null && !requiredModule.isAutomatic() )
186             {
187                 if ( namedModules.add( requiresName ) )
188                 {
189                     select( requiredModule, availableModules, namedModules, unnamedModules );
190                 }
191             }
192             else
193             {
194                 unnamedModules.add( requiresName );
195             }
196         }
197     }
198 }