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   */
37  @Component(role = ComponentDescriptorExtractor.class, hint = "class")
38  public class ClassComponentDescriptorExtractor extends ComponentDescriptorExtractorSupport {
39      private ClassComponentGleaner gleaner;
40  
41      public ClassComponentDescriptorExtractor(final ClassComponentGleaner gleaner) {
42          this.gleaner = gleaner;
43      }
44  
45      public ClassComponentDescriptorExtractor() {
46          this.gleaner = new AnnotationComponentGleaner();
47      }
48  
49      public List<ComponentDescriptor<?>> extract(
50              MetadataGenerationRequest configuration, final ComponentDescriptor<?>[] roleDefaults) throws Exception {
51          // We don't have a reasonable default to use, so just puke up
52          if (gleaner == null) {
53              throw new IllegalStateException("Gleaner is not bound");
54          }
55  
56          if (!configuration.classesDirectory.exists()) {
57              return Collections.emptyList();
58          }
59  
60          if (configuration.useContextClassLoader) {
61              return extract(
62                      configuration.classesDirectory,
63                      Thread.currentThread().getContextClassLoader(),
64                      getDefaultsByRole(roleDefaults));
65          } else {
66              ClassLoader prev = Thread.currentThread().getContextClassLoader();
67              ClassLoader cl = createClassLoader(configuration.classpath);
68  
69              Thread.currentThread().setContextClassLoader(cl);
70  
71              try {
72                  return extract(configuration.classesDirectory, cl, getDefaultsByRole(roleDefaults));
73              } finally {
74                  Thread.currentThread().setContextClassLoader(prev);
75              }
76          }
77      }
78  
79      private ClassLoader createClassLoader(final List<String> elements) throws Exception {
80          List<URL> list = new ArrayList<URL>();
81  
82          // Add the projects dependencies
83          for (String filename : elements) {
84              try {
85                  list.add(new File(filename).toURI().toURL());
86              } catch (MalformedURLException e) {
87                  throw new MojoExecutionException("Invalid classpath entry: " + filename, e);
88              }
89          }
90  
91          URL[] urls = list.toArray(new URL[list.size()]);
92  
93          // getLogger().debug( "Classpath:" );
94          for (URL url : urls) {
95              // getLogger().debug( "    " + urls[i] );
96          }
97  
98          return new URLClassLoader(urls, null);
99      }
100 
101     private List<ComponentDescriptor<?>> extract(
102             File classesDir, ClassLoader cl, Map<String, ComponentDescriptor<?>> defaultsByRole) throws Exception {
103         assert classesDir != null;
104         assert cl != null;
105         assert defaultsByRole != null;
106 
107         List<ComponentDescriptor<?>> descriptors = new ArrayList<ComponentDescriptor<?>>();
108 
109         DirectoryScanner scanner = new DirectoryScanner();
110         scanner.setBasedir(classesDir);
111         scanner.addDefaultExcludes();
112         scanner.setIncludes(new String[] {"**/*.class"});
113         // exclude special classes like module-info.class
114         scanner.setExcludes(new String[] {"**/*-*.class"});
115 
116         // getLogger().debug( "Scanning for classes in: " + classesDir );
117 
118         scanner.scan();
119 
120         String[] includes = scanner.getIncludedFiles();
121 
122         for (String include : includes) {
123             String className = include.substring(0, include.lastIndexOf(".class"))
124                     .replace('\\', '.')
125                     .replace('/', '.');
126 
127             try {
128                 // Class type = cl.loadClass( className );
129 
130                 ComponentDescriptor<?> descriptor = gleaner.glean(className, cl);
131 
132                 if (descriptor != null) {
133                     applyDefaults(descriptor, defaultsByRole);
134 
135                     descriptors.add(descriptor);
136                 }
137             } catch (VerifyError e) {
138                 // getLogger().error( "Failed to load class: " + className + "; cause: " + e );
139             }
140         }
141 
142         return descriptors;
143     }
144 }