001: package org.andromda.maven.plugin.configuration;
002:
003: import java.io.File;
004: import java.io.IOException;
005: import java.io.StringReader;
006:
007: import java.net.MalformedURLException;
008: import java.net.URL;
009: import java.net.URLClassLoader;
010:
011: import java.util.Iterator;
012: import java.util.List;
013: import java.util.Properties;
014:
015: import org.andromda.core.common.ResourceUtils;
016: import org.andromda.core.configuration.Configuration;
017: import org.apache.commons.lang.ObjectUtils;
018: import org.apache.maven.artifact.Artifact;
019: import org.apache.maven.artifact.DependencyResolutionRequiredException;
020: import org.apache.maven.artifact.factory.ArtifactFactory;
021: import org.apache.maven.artifact.repository.ArtifactRepository;
022: import org.apache.maven.model.Dependency;
023: import org.apache.maven.model.Plugin;
024: import org.apache.maven.plugin.AbstractMojo;
025: import org.apache.maven.plugin.resources.PropertyUtils;
026: import org.apache.maven.project.MavenProject;
027: import org.apache.maven.settings.Settings;
028: import org.codehaus.plexus.util.InterpolationFilterReader;
029:
030: /**
031: * An abstract Mojo for dealing with the AndroMDA configuration,
032: * if a plugin needs to use the AndroMDA configuration, it should extend this
033: * class.
034: *
035: * @author Chad Brandon
036: */
037: public abstract class AbstractConfigurationMojo extends AbstractMojo {
038: /**
039: * The path to the mappings within the plugin.
040: */
041: private static final String MAPPINGS_PATH = "META-INF/andromda/mappings";
042:
043: /**
044: * Creates the Configuration instance from the {@link #configurationUri}
045: *
046: * @return the configuration instance
047: * @throws MalformedURLException if the URL is invalid.
048: */
049: protected Configuration getConfiguration(final URL configurationUri)
050: throws IOException {
051: final String contents = this .replaceProperties(ResourceUtils
052: .getContents(configurationUri));
053: final Configuration configuration = Configuration
054: .getInstance(contents);
055: final URL mappingsUrl = ResourceUtils
056: .getResource(MAPPINGS_PATH);
057: if (mappingsUrl != null) {
058: configuration.addMappingsSearchLocation(mappingsUrl
059: .toString());
060: }
061: return configuration;
062: }
063:
064: /**
065: * Collects and returns all properties as a Properties instance.
066: *
067: * @return the properties including those from the project, settings, etc.
068: * @throws IOException
069: */
070: protected Properties getProperties() throws IOException {
071: // System properties
072: final Properties properties = new Properties();
073:
074: properties.put("settings", this .getSettings());
075:
076: // - project properties
077: properties.putAll(this .getProject().getProperties());
078: for (final Iterator iterator = this .getPropertyFiles()
079: .iterator(); iterator.hasNext();) {
080: final String propertiesFile = (String) iterator.next();
081: final Properties projectProperties = PropertyUtils
082: .loadPropertyFile(new File(propertiesFile), true,
083: true);
084:
085: properties.putAll(projectProperties);
086: }
087:
088: for (final Iterator iterator = properties.keySet().iterator(); iterator
089: .hasNext();) {
090: final String property = (String) iterator.next();
091: final String value = this .replaceProperties(properties,
092: ObjectUtils.toString(properties.get(property)));
093: properties.put(property, value);
094: }
095:
096: properties.putAll(System.getProperties());
097:
098: return properties;
099: }
100:
101: /**
102: * Replaces all properties having the style
103: * <code>${some.property}</code> with the value
104: * of the specified property if there is one.
105: *
106: * @param string the string to perform replacement on.
107: */
108: protected String replaceProperties(final String string)
109: throws IOException {
110: return this .replaceProperties(this .getProperties(), string);
111: }
112:
113: /**
114: * The begin token for interpolation.
115: */
116: private static final String BEGIN_TOKEN = "${";
117:
118: /**
119: * The end token for interpolation.
120: */
121: private static final String END_TOKEN = "}";
122:
123: /**
124: * Replaces all properties having the style
125: * <code>${some.property}</code> with the value
126: * of the specified property if there is one.
127: *
128: * @param properties the properties used to perform the replacement.
129: * @param fileContents the fileContents to perform replacement on.
130: */
131: private String replaceProperties(final Properties properties,
132: final String string) throws IOException {
133: final StringReader stringReader = new StringReader(string);
134: InterpolationFilterReader reader = new InterpolationFilterReader(
135: stringReader, properties, "${", "}");
136: reader.reset();
137: reader = new InterpolationFilterReader(reader,
138: new BeanProperties(this .getProject()), BEGIN_TOKEN,
139: END_TOKEN);
140: reader = new InterpolationFilterReader(reader,
141: new BeanProperties(this .getSettings()), BEGIN_TOKEN,
142: END_TOKEN);
143: return ResourceUtils.getContents(reader);
144: }
145:
146: /**
147: * Sets the current context class loader from the given runtime classpath elements.
148: *
149: * @throws DependencyResolutionRequiredException
150: * @throws MalformedURLException
151: */
152: protected void initializeClasspathFromClassPathElements(
153: final List classpathFiles) throws MalformedURLException {
154: if (classpathFiles != null && classpathFiles.size() > 0) {
155: final URL[] classpathUrls = new URL[classpathFiles.size()];
156:
157: for (int ctr = 0; ctr < classpathFiles.size(); ++ctr) {
158: final File file = new File((String) classpathFiles
159: .get(ctr));
160: if (this .getLog().isDebugEnabled()) {
161: getLog()
162: .debug("adding to classpath '" + file + "'");
163: }
164: classpathUrls[ctr] = file.toURL();
165: }
166:
167: final URLClassLoader loader = new ConfigurationClassLoader(
168: classpathUrls, Thread.currentThread()
169: .getContextClassLoader());
170: Thread.currentThread().setContextClassLoader(loader);
171: }
172: }
173:
174: /**
175: * Adds any dependencies to the current project from the plugin
176: * having the given <code>pluginArtifactId</code>.
177: *
178: * @param pluginArtifactId the artifactId of the plugin of which to add its dependencies.
179: * @param scope the artifact scope in which to add them (runtime, compile, etc).
180: */
181: protected void addPluginDependencies(final String pluginArtifactId,
182: final String scope) {
183: if (pluginArtifactId != null) {
184: final List plugins = this .getPlugins();
185: if (plugins != null && !plugins.isEmpty()) {
186: for (final Iterator iterator = plugins.iterator(); iterator
187: .hasNext();) {
188: final Plugin plugin = (Plugin) iterator.next();
189: if (pluginArtifactId.equals(plugin.getArtifactId())) {
190: final List dependencies = plugin
191: .getDependencies();
192: if (dependencies != null) {
193: for (final Iterator dependencyIterator = plugin
194: .getDependencies().iterator(); dependencyIterator
195: .hasNext();) {
196: this .addDependency(
197: (Dependency) dependencyIterator
198: .next(), scope);
199: }
200: }
201: }
202: }
203: }
204: }
205: }
206:
207: /**
208: * Adds a dependency to the current project's dependencies.
209: *
210: * @param dependency
211: */
212: private void addDependency(final Dependency dependency,
213: final String scope) {
214: final ArtifactRepository localRepository = this
215: .getLocalRepository();
216: final MavenProject project = this .getProject();
217: if (project != null && localRepository != null) {
218: if (dependency != null) {
219: final Artifact artifact = this .getFactory()
220: .createArtifact(dependency.getGroupId(),
221: dependency.getArtifactId(),
222: dependency.getVersion(), scope,
223: dependency.getType());
224: final File file = new File(
225: localRepository.getBasedir(), localRepository
226: .pathOf(artifact));
227: artifact.setFile(file);
228: project.getDependencies().add(dependency);
229: project.getArtifacts().add(artifact);
230: }
231: }
232: }
233:
234: /**
235: * Gets the current project.
236: *
237: * @return Returns the project.
238: */
239: protected abstract MavenProject getProject();
240:
241: /**
242: * Gets the property files for the profile (the ones defined
243: * in the filters section of the POM).
244: *
245: * @return Returns the propertyFiles.
246: */
247: protected abstract List getPropertyFiles();
248:
249: /**
250: * Gets the current settings of the project.
251: *
252: * @return Returns the settings.
253: */
254: protected abstract Settings getSettings();
255:
256: /**
257: * Gets the artifact factory used to construct any new required artifacts.
258: */
259: protected abstract ArtifactFactory getFactory();
260:
261: /**
262: * Gets the current project's registered plugin implementations.
263: *
264: * @parameter expression="${project.build.plugins}"
265: * @required
266: * @readonly
267: */
268: protected abstract List getPlugins();
269:
270: /**
271: * Gets the current local repository instance.
272: *
273: * @return the local repository instance of the current project.
274: */
275: protected abstract ArtifactRepository getLocalRepository();
276: }
|