View Javadoc
1   /*
2    * Copyright (C) 2007 the original author or authors.
3    * 
4    * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except
5    * in compliance with the License. You may obtain a copy of the License at
6    * 
7    * http://www.apache.org/licenses/LICENSE-2.0
8    * 
9    * Unless required by applicable law or agreed to in writing, software distributed under the License
10   * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
11   * or implied. See the License for the specific language governing permissions and limitations under
12   * the License.
13   */
14  
15  package org.codehaus.plexus.metadata;
16  
17  import java.io.File;
18  import java.net.MalformedURLException;
19  import java.net.URL;
20  import java.net.URLClassLoader;
21  import java.util.ArrayList;
22  import java.util.Collections;
23  import java.util.List;
24  import java.util.Map;
25  
26  import org.apache.maven.plugin.MojoExecutionException;
27  import org.codehaus.plexus.component.annotations.Component;
28  import org.codehaus.plexus.component.repository.ComponentDescriptor;
29  import org.codehaus.plexus.metadata.gleaner.AnnotationComponentGleaner;
30  import org.codehaus.plexus.metadata.gleaner.ClassComponentGleaner;
31  import org.codehaus.plexus.util.DirectoryScanner;
32  
33  /**
34   * Extracts {@link ComponentDescriptor} from class files.
35   * 
36   * @version $Id$
37   */
38  @Component( role = ComponentDescriptorExtractor.class, hint = "class" )
39  public class ClassComponentDescriptorExtractor
40      extends ComponentDescriptorExtractorSupport
41  {
42      private ClassComponentGleaner gleaner;
43  
44      public ClassComponentDescriptorExtractor( final ClassComponentGleaner gleaner )
45      {
46          this.gleaner = gleaner;
47      }
48  
49      public ClassComponentDescriptorExtractor()
50      {
51          this.gleaner = new AnnotationComponentGleaner();
52      }
53  
54      public List<ComponentDescriptor<?>> extract( MetadataGenerationRequest configuration, final ComponentDescriptor<?>[] roleDefaults )
55          throws Exception
56      {
57          // We don't have a reasonable default to use, so just puke up
58          if ( gleaner == null )
59          {
60              throw new IllegalStateException( "Gleaner is not bound" );
61          }
62  
63          if ( !configuration.classesDirectory.exists() )
64          {
65              return Collections.emptyList();
66          }
67  
68          if ( configuration.useContextClassLoader )
69          {
70              return extract( configuration.classesDirectory, Thread.currentThread().getContextClassLoader(), getDefaultsByRole( roleDefaults ) );
71          }
72          else
73          {
74              ClassLoader prev = Thread.currentThread().getContextClassLoader();
75              ClassLoader cl = createClassLoader( configuration.classpath );
76  
77              Thread.currentThread().setContextClassLoader( cl );
78  
79              try
80              {
81                  return extract( configuration.classesDirectory, cl, getDefaultsByRole( roleDefaults ) );
82              }
83              finally
84              {
85                  Thread.currentThread().setContextClassLoader( prev );
86              }
87          }
88      }
89  
90      private ClassLoader createClassLoader( final List<String> elements )
91          throws Exception
92      {
93          List<URL> list = new ArrayList<URL>();
94  
95          // Add the projects dependencies
96          for ( String filename : elements )
97          {
98              try
99              {
100                 list.add( new File( filename ).toURI().toURL() );
101             }
102             catch ( MalformedURLException e )
103             {
104                 throw new MojoExecutionException( "Invalid classpath entry: " + filename, e );
105             }
106         }
107 
108         URL[] urls = list.toArray( new URL[list.size()] );
109 
110         //getLogger().debug( "Classpath:" );
111         for (URL url : urls) {
112             //getLogger().debug( "    " + urls[i] );
113         }
114 
115         return new URLClassLoader( urls, null );
116     }
117 
118     private List<ComponentDescriptor<?>> extract( File classesDir, ClassLoader cl, Map<String, ComponentDescriptor<?>> defaultsByRole )
119         throws Exception
120     {
121         assert classesDir != null;
122         assert cl != null;
123         assert defaultsByRole != null;
124 
125         List<ComponentDescriptor<?>> descriptors = new ArrayList<ComponentDescriptor<?>>();
126 
127         DirectoryScanner scanner = new DirectoryScanner();
128         scanner.setBasedir( classesDir );
129         scanner.addDefaultExcludes();
130         scanner.setIncludes( new String[] { "**/*.class" } );
131         // exclude special classes like module-info.class
132         scanner.setExcludes( new String[] { "**/*-*.class" } );
133 
134         //getLogger().debug( "Scanning for classes in: " + classesDir );
135 
136         scanner.scan();
137 
138         String[] includes = scanner.getIncludedFiles();
139 
140         for ( String include : includes )
141         {
142             String className = include.substring( 0, include.lastIndexOf( ".class" ) ).replace( '\\', '.' ).replace( '/', '.' );
143 
144             try
145             {
146                 // Class type = cl.loadClass( className );
147 
148                 ComponentDescriptor<?> descriptor = gleaner.glean( className, cl );
149 
150                 if ( descriptor != null )
151                 {
152                     applyDefaults( descriptor, defaultsByRole );
153 
154                     descriptors.add( descriptor );
155                 }
156             }
157             catch ( VerifyError e )
158             {
159                 // getLogger().error( "Failed to load class: " + className + "; cause: " + e );
160             }
161         }
162 
163         return descriptors;
164     }
165 }