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