View Javadoc
1   package org.andromda.maven.plugin.configuration;
2   
3   import java.io.File;
4   import java.io.IOException;
5   import java.io.StringReader;
6   import java.net.MalformedURLException;
7   import java.net.URL;
8   import java.net.URLClassLoader;
9   import java.util.List;
10  import java.util.Properties;
11  import org.andromda.core.common.ResourceUtils;
12  import org.andromda.core.configuration.Configuration;
13  import org.apache.commons.lang.ObjectUtils;
14  import org.apache.maven.artifact.Artifact;
15  import org.apache.maven.artifact.factory.ArtifactFactory;
16  import org.apache.maven.artifact.repository.ArtifactRepository;
17  import org.apache.maven.model.Dependency;
18  import org.apache.maven.model.Plugin;
19  import org.apache.maven.plugin.AbstractMojo;
20  import org.apache.maven.project.MavenProject;
21  import org.apache.maven.settings.Settings;
22  import org.apache.maven.shared.filtering.PropertyUtils;
23  import org.codehaus.plexus.util.InterpolationFilterReader;
24  
25  /**
26   * An abstract Mojo for dealing with the AndroMDA configuration,
27   * if a plugin needs to use the AndroMDA configuration, it should extend this
28   * class.
29   *
30   * @author Chad Brandon
31   * @author Bob Fields
32   */
33  public abstract class AbstractConfigurationMojo
34      extends AbstractMojo
35  {
36      /**
37       * The path to the mappings within the plugin.
38       */
39      private static final String MAPPINGS_PATH = "META-INF/andromda/mappings";
40  
41      /**
42       * Creates the Configuration instance from the {@link URL}
43       *
44       * @param configurationUri
45       * @return the configuration instance
46       * @throws IOException if the URL is invalid.
47       */
48      protected Configuration getConfiguration(final URL configurationUri)
49          throws IOException
50      {
51          final String contents = this.replaceProperties(ResourceUtils.getContents(configurationUri));
52          final Configuration configuration = Configuration.getInstance(contents);
53          final URL mappingsUrl = ResourceUtils.getResource(MAPPINGS_PATH);
54          if (mappingsUrl != null)
55          {
56              configuration.addMappingsSearchLocation(mappingsUrl.toString());
57          }
58          return configuration;
59      }
60  
61      /**
62       * Collects and returns all properties as a Properties instance.
63       *
64       * @return the properties including those from the project, settings, etc.
65       * @throws IOException
66       */
67      protected Properties getProperties()
68          throws IOException
69      {
70          // System properties
71          final Properties properties = new Properties();
72  
73          properties.put(
74              "settings",
75              this.getSettings());
76  
77          // - project properties
78          properties.putAll(this.getProject().getProperties());
79          for (final String propertiesFile : (Iterable<String>) this.getPropertyFiles())
80          {
81              final Properties projectProperties = PropertyUtils.loadPropertyFile(
82                      new File(propertiesFile),
83                      true,
84                      true);
85  
86              properties.putAll(projectProperties);
87          }
88  
89          for (Object objProperty : properties.keySet())
90          {
91              final String property = (String) objProperty;
92              final String value = this.replaceProperties(
93                      properties,
94                      ObjectUtils.toString(properties.get(property)));
95              properties.put(
96                      property,
97                      value);
98          }
99  
100         properties.putAll(System.getProperties());
101 
102         return properties;
103     }
104 
105     /**
106      * Replaces all properties having the style
107      * <code>${some.property}</code> with the value
108      * of the specified property if there is one.
109      *
110      * @param string the string to perform replacement on.
111      * @return this.replaceProperties(this.getProperties(),string);
112      * @throws IOException
113      */
114     protected String replaceProperties(final String string)
115         throws IOException
116     {
117         return this.replaceProperties(
118             this.getProperties(),
119             string);
120     }
121 
122     /**
123      * The begin token for interpolation.
124      */
125     private static final String BEGIN_TOKEN = "${";
126 
127     /**
128      * The end token for interpolation.
129      */
130     private static final String END_TOKEN = "}";
131 
132     /**
133      * Replaces all properties having the style
134      * <code>${some.property}</code> with the value
135      * of the specified property if there is one.
136      *
137      * @param properties the properties used to perform the replacement.
138      * @param string the fileContents to perform replacement on.
139      */
140     private String replaceProperties(
141         final Properties properties,
142         final String string)
143         throws IOException
144     {
145         final StringReader stringReader = new StringReader(string);
146         InterpolationFilterReader reader = new InterpolationFilterReader(stringReader, properties, "${", "}");
147         reader.reset();
148         reader = new InterpolationFilterReader(
149                 reader,
150                 new BeanProperties(this.getProject()),
151                 BEGIN_TOKEN,
152                 END_TOKEN);
153         reader = new InterpolationFilterReader(
154                 reader,
155                 new BeanProperties(this.getSettings()),
156                 BEGIN_TOKEN,
157                 END_TOKEN);
158         return ResourceUtils.getContents(reader);
159     }
160 
161     /**
162      * Sets the current context class loader from the given runtime classpath elements.
163      *
164      * @param classpathFiles
165      * @throws MalformedURLException
166      */
167     protected void initializeClasspathFromClassPathElements(final List<String> classpathFiles)
168         throws MalformedURLException
169     {
170         if (classpathFiles != null && !classpathFiles.isEmpty())
171         {
172             final URL[] classpathUrls = new URL[classpathFiles.size()];
173 
174             for (int ctr = 0; ctr < classpathFiles.size(); ++ctr)
175             {
176                 final File file = new File(classpathFiles.get(ctr));
177                 if (this.getLog().isDebugEnabled())
178                 {
179                     getLog().debug("adding to classpath '" + file + '\'');
180                 }
181                 classpathUrls[ctr] = file.toURI().toURL();
182             }
183 
184             final URLClassLoader loader =
185                 new ConfigurationClassLoader(classpathUrls,
186                     Thread.currentThread().getContextClassLoader());
187             Thread.currentThread().setContextClassLoader(loader);
188         }
189     }
190 
191     /**
192      * Adds any dependencies to the current project from the plugin
193      * having the given <code>pluginArtifactId</code>.
194      *
195      * @param pluginArtifactId the artifactId of the plugin of which to add its dependencies.
196      * @param scope the artifact scope in which to add them (runtime, compile, etc).
197      */
198     protected void addPluginDependencies(
199         final String pluginArtifactId,
200         final String scope)
201     {
202         if (pluginArtifactId != null)
203         {
204             final List<Plugin> plugins = this.getPlugins();
205             if (plugins != null)
206             {
207                 for (final Plugin plugin : plugins)
208                 {
209                     if (pluginArtifactId.equals(plugin.getArtifactId()))
210                     {
211                         final List<Dependency> dependencies = plugin.getDependencies();
212                         if (dependencies != null)
213                         {
214                             for (Dependency dependency : plugin.getDependencies())
215                             {
216                                 this.addDependency(
217                                         dependency,
218                                         scope);
219                             }
220                         }
221                     }
222                 }
223             }
224         }
225     }
226 
227     // Can't do anything about raw Collection types in MavenProject dependency
228     @SuppressWarnings("unchecked")
229     /**
230      * Adds a dependency to the current project's dependencies.
231      *
232      * @param dependency
233      */
234     private void addDependency(
235         final Dependency dependency,
236         final String scope)
237     {
238         final ArtifactRepository localRepository = this.getLocalRepository();
239         final MavenProject project = this.getProject();
240         if (project != null && localRepository != null)
241         {
242             if (dependency != null)
243             {
244                 final Artifact artifact =
245                     this.getFactory().createArtifact(
246                         dependency.getGroupId(),
247                         dependency.getArtifactId(),
248                         dependency.getVersion(),
249                         scope,
250                         dependency.getType());
251                 final File file = new File(
252                         localRepository.getBasedir(),
253                         localRepository.pathOf(artifact));
254                 artifact.setFile(file);
255                 project.getDependencies().add(dependency);
256                 project.getArtifacts().add(artifact);
257             }
258         }
259     }
260 
261     /**
262      * Gets the current project.
263      *
264      * @return Returns the project.
265      */
266     protected abstract MavenProject getProject();
267 
268     /**
269      * Gets the property files for the profile (the ones defined
270      * in the filters section of the POM).
271      *
272      * @return Returns the propertyFiles.
273      */
274     protected abstract List<String> getPropertyFiles();
275 
276     /**
277      * Gets the current settings of the project.
278      *
279      * @return Returns the settings.
280      */
281     protected abstract Settings getSettings();
282 
283     /**
284      * Gets the artifact factory used to construct any new required artifacts.
285      * @return ArtifactFactory
286      */
287     protected abstract ArtifactFactory getFactory();
288 
289     /**
290      * Gets the current project's registered plugin implementations.
291      * @return pluginList
292      *
293      * @parameter expression="${project.build.plugins}"
294      * @required
295      * @readonly
296      */
297     protected abstract List<Plugin> getPlugins();
298 
299     /**
300      * Gets the current local repository instance.
301      *
302      * @return the local repository instance of the current project.
303      */
304     protected abstract ArtifactRepository getLocalRepository();
305 
306     /**
307      * Set this to 'true' to bypass cartridge tests entirely. Its use is NOT RECOMMENDED, but quite convenient on occasion.
308      *
309      * @parameter expression="${maven.test.skip}" default-value="false"
310      */
311     protected boolean skip;
312 
313     /**
314      *  Set this to 'true' to skip running tests, but still compile them. Its use is NOT RECOMMENDED, but quite convenient on occasion.
315      *
316      * @parameter expression="${skipTests}" default-value="false"
317      */
318     protected boolean skipTests;
319 
320     /**
321      * Set this to true to ignore a failure during testing. Its use is NOT RECOMMENDED, but quite convenient on occasion.
322      *
323      * @parameter expression="${maven.test.failure.ignore}" default-value="false"
324      */
325     protected boolean testFailureIgnore;
326 }