001package org.andromda.maven.plugin.andromdapp; 002 003import java.io.File; 004import java.net.MalformedURLException; 005import java.net.URL; 006import java.net.URLClassLoader; 007import java.util.ArrayList; 008import java.util.Collection; 009import java.util.LinkedHashSet; 010import java.util.List; 011import java.util.Set; 012import org.andromda.core.common.ClassUtils; 013import org.andromda.maven.plugin.andromdapp.script.ScriptClassGenerator; 014import org.apache.maven.artifact.Artifact; 015import org.apache.maven.artifact.factory.ArtifactFactory; 016import org.apache.maven.artifact.repository.ArtifactRepository; 017import org.apache.maven.model.Dependency; 018import org.apache.maven.plugin.AbstractMojo; 019import org.apache.maven.plugin.MojoExecutionException; 020import org.apache.maven.plugin.MojoFailureException; 021import org.apache.maven.project.MavenProject; 022 023/** 024 * Allows for the {@link ScriptClassGenerator} mojo to be invoked. 025 * on one or more given classes. 026 * 027 * @author Chad Brandon 028 * @goal instrument-scripts 029 * @phase compile 030 * @requiresDependencyResolution 031 */ 032public class ScriptClassGeneratorMojo 033 extends AbstractMojo 034{ 035 /** 036 * Defines the java files who's classes will be instrumented. 037 * 038 * @required 039 * @parameter 040 */ 041 private Location[] locations; 042 043 /** 044 * Defines the fully qualified class name of the script wrapper implementation. 045 * 046 * @parameter 047 * @required 048 */ 049 private String scriptWrapper; 050 051 /** 052 * @parameter expression="${project}" 053 * @required 054 * @readonly 055 */ 056 private MavenProject project; 057 058 /** 059 * @component role="org.apache.maven.artifact.factory.ArtifactFactory" 060 * @required 061 * @readonly 062 */ 063 protected ArtifactFactory factory; 064 065 /** 066 * @parameter expression="${localRepository}" 067 * @required 068 * @readonly 069 */ 070 protected ArtifactRepository localRepository; 071 072 /** 073 * The java file extension 074 */ 075 private static final String JAVA_EXTENSION = ".java"; 076 077 /** 078 * @see org.apache.maven.plugin.Mojo#execute() 079 */ 080 public void execute() 081 throws MojoExecutionException, MojoFailureException 082 { 083 try 084 { 085 final ScriptClassGenerator generator = ScriptClassGenerator.getInstance(this.scriptWrapper); 086 if (this.locations != null) 087 { 088 final List<String> classpathElements = new ArrayList<String>(this.getProvidedClasspathElements()); 089 classpathElements.addAll(this.project.getRuntimeClasspathElements()); 090 this.initializeClassLoader(classpathElements); 091 for (int ctr = 0; ctr < locations.length; ctr++) 092 { 093 final Location location = locations[ctr]; 094 String rootPath = location.getRootPath(); 095 for (final String path : location.getPaths()) 096 { 097 final int extensionIndex = path.lastIndexOf(JAVA_EXTENSION); 098 if (extensionIndex != -1) 099 { 100 final String className = path.substring( 101 0, 102 extensionIndex).replaceAll( 103 "\\\\|/", 104 "\\."); 105 this.getLog().info("injecting script wrapper: " + className); 106 generator.modifyClass( 107 rootPath, 108 ClassUtils.loadClass(className)); 109 } 110 } 111 } 112 } 113 } 114 catch (final Throwable throwable) 115 { 116 throw new MojoExecutionException("Failed to inject script wrappers", throwable); 117 } 118 } 119 120 /** 121 * Adds any dependencies to the current project from the plugin 122 * having the given <code>pluginArtifactId</code>. 123 * This project artifact dependencies are added. 124 * scope=PROVIDED the artifact scope in which to add them (runtime, compile, etc). 125 * @return classpathElements 126 */ 127 protected List<String> getProvidedClasspathElements() 128 { 129 final List<String> classpathElements = new ArrayList<String>(); 130 for (final Object dependency : this.project.getDependencies()) 131 { 132 final Artifact artifact = this.getArtifact( 133 (Dependency)dependency, 134 Artifact.SCOPE_PROVIDED); 135 if (artifact != null) 136 { 137 classpathElements.add(artifact.getFile().getAbsolutePath()); 138 } 139 } 140 return classpathElements; 141 } 142 143 /** 144 * Adds a dependency to the current project's dependencies. 145 * 146 * @param dependency 147 * @param scope the scope of the artifact 148 */ 149 private Artifact getArtifact( 150 final Dependency dependency, 151 final String scope) 152 { 153 Artifact artifact = null; 154 final ArtifactRepository localRepository = this.localRepository; 155 final MavenProject project = this.project; 156 if (project != null && localRepository != null) 157 { 158 if (dependency != null) 159 { 160 artifact = 161 this.factory.createArtifact( 162 dependency.getGroupId(), 163 dependency.getArtifactId(), 164 dependency.getVersion(), 165 scope, 166 dependency.getType()); 167 final File file = new File( 168 localRepository.getBasedir(), 169 localRepository.pathOf(artifact)); 170 artifact.setFile(file); 171 } 172 } 173 return artifact; 174 } 175 176 /** 177 * Sets the current context class loader from the given runtime classpath elements. 178 * @param classpathFiles 179 * @throws MalformedURLException 180 */ 181 protected void initializeClassLoader(final Collection<String> classpathFiles) 182 throws MalformedURLException 183 { 184 final Set<URL> classpathUrls = new LinkedHashSet<URL>(); 185 classpathUrls.add(new File(this.project.getBuild().getOutputDirectory()).toURI().toURL()); 186 if (classpathFiles != null) 187 { 188 for (String fileName : classpathFiles) 189 { 190 final File file = new File(fileName); 191 if (this.getLog().isDebugEnabled()) 192 { 193 getLog().debug("adding to classpath '" + file + '\''); 194 } 195 classpathUrls.add(file.toURI().toURL()); 196 } 197 } 198 final URLClassLoader loader = 199 new URLClassLoader(classpathUrls.toArray(new URL[classpathUrls.size()]), 200 Thread.currentThread().getContextClassLoader()); 201 Thread.currentThread().setContextClassLoader(loader); 202 } 203}