001package org.andromda.maven.plugin.andromdapp;
002
003import java.io.File;
004import java.io.IOException;
005import java.io.StringReader;
006import java.net.URL;
007import java.util.List;
008import java.util.Properties;
009import org.andromda.core.common.ResourceUtils;
010import org.apache.commons.lang.ObjectUtils;
011import org.apache.commons.lang.StringUtils;
012import org.apache.maven.plugin.AbstractMojo;
013import org.apache.maven.plugin.MojoExecutionException;
014import org.apache.maven.project.MavenProject;
015import org.apache.maven.settings.Settings;
016import org.apache.maven.shared.filtering.PropertyUtils;
017import org.codehaus.plexus.util.InterpolationFilterReader;
018
019/**
020 * The abstract AndroMDAapp mojo (this should be extended by any Mojo that
021 * executes AndroMDApp.
022 *
023 * @author Chad Brandon
024 * @author Bob Fields
025 */
026public abstract class AbstractAndroMDAppMojo
027    extends AbstractMojo
028{
029    /**
030     * The URI to an optional AndroMDApp configuration file.
031     *
032     * @parameter expression="${configuration.uri}"
033     */
034    private String configurationUri;
035
036    /**
037     * @parameter expression="${project}"
038     * @required
039     * @readonly
040     */
041    private MavenProject project;
042
043    /**
044     * The current user system settings for use in Maven. (allows us to pass the user
045     * settings to the AndroMDA configuration).
046     *
047     * @parameter expression="${settings}"
048     * @required
049     * @readonly
050     */
051    protected Settings settings;
052
053    /**
054     * @parameter expression="${project.build.filters}"
055     */
056    protected List<String> propertyFiles;
057
058    /**
059     * Set this to 'true' to bypass cartridge tests entirely. Its use is NOT RECOMMENDED, but quite convenient on occasion.
060     *
061     * @parameter expression="${maven.test.skip}"
062     */
063    protected boolean skip;
064
065    /**
066     *  Set this to 'true' to skip running tests, but still compile them. Its use is NOT RECOMMENDED, but quite convenient on occasion.
067     *
068     * @parameter expression="${skipTests}"
069     */
070    protected boolean skipTests;
071
072    /**
073     * Set this to true to ignore a failure during testing. Its use is NOT RECOMMENDED, but quite convenient on occasion.
074     *
075     * @parameter expression="${maven.test.failure.ignore}" default-value="false"
076     */
077    protected boolean testFailureIgnore;
078
079    /**
080     * Whether or not processing should be skipped (this is if you want to completely skip code generation, i.e. if
081     * code is already generated and you are creating the site from already generated source code).
082     *
083     * @parameter expression="${andromdapp.run.skip}"
084     */
085    protected boolean skipProcessing = false;
086
087    /**
088     * Collects and returns all properties as a Properties instance.
089     *
090     * @return the properties including those from the project, settings, etc.
091     * @throws IOException
092     */
093    private Properties getProperties()
094        throws IOException
095    {
096        // System properties
097        final Properties properties = new Properties();
098
099        properties.put(
100            "settings",
101            this.settings);
102
103        // - project properties
104        properties.putAll(this.project.getProperties());
105        if (this.propertyFiles != null)
106        {
107            for (final String propertiesFile : this.propertyFiles)
108            {
109                final Properties projectProperties = PropertyUtils.loadPropertyFile(
110                        new File(propertiesFile),
111                        true,
112                        true);
113                properties.putAll(projectProperties);
114            }
115        }
116
117        for (final Object propertyObject : properties.keySet())
118        {
119            final String property = (String)propertyObject;
120            final String value = this.replaceProperties(properties, ObjectUtils.toString(properties.get(property)));
121            properties.put(property, value);
122        }
123
124        properties.putAll(System.getProperties());
125
126        return properties;
127    }
128
129    /**
130     * Replaces all properties having the style
131     * <code>${some.property}</code> with the value
132     * of the specified property if there is one.
133     *
134     * @param string the string to perform replacement on.
135     * @return this.replaceProperties(this.getProperties(), string);
136     * @throws IOException
137     */
138    protected String replaceProperties(final String string)
139        throws IOException
140    {
141        return this.replaceProperties(this.getProperties(), string);
142    }
143
144    /**
145     * Retrieves the interpolated {#configurationUri} contents as a String.
146     *
147     * @return the contents of the configuration as a string.
148     * @throws MojoExecutionException
149     * @throws IOException
150     */
151    protected String getConfigurationContents() throws MojoExecutionException, IOException
152    {
153        String contents = null;
154        if (StringUtils.isNotBlank(this.configurationUri))
155        {
156            final URL configuration = ResourceUtils.toURL(this.configurationUri);
157            if (configuration == null)
158            {
159                throw new MojoExecutionException("No configuration could be loaded from --> '" + this.configurationUri + '\'');
160            }
161            contents = this.replaceProperties(ResourceUtils.getContents(configuration));
162        }
163        return contents;
164    }
165
166    /**
167     * The begin token for interpolation (we need it different
168     * than what Maven uses so that Maven variables aren't replaced).
169     */
170    private static final String BEGIN_TOKEN = "$${";
171
172    /**
173     * The end token for interpolation.
174     */
175    private static final String END_TOKEN = "}";
176
177    /**
178     * Replaces all properties having the style
179     * <code>${some.property}</code> with the value
180     * of the specified property if there is one.
181     *
182     * @param properties the properties used to perform the replacement.
183     * @param string the fileContents to perform replacement on.
184     */
185    @SuppressWarnings("resource")
186    private String replaceProperties(final Properties properties, final String string) throws IOException
187    {
188        String replacement = null;
189        final StringReader stringReader = new StringReader(string);
190        InterpolationFilterReader reader = new InterpolationFilterReader(stringReader, properties, "${", "}");
191        reader.reset();
192        try
193        {
194            reader = new InterpolationFilterReader(
195                    reader,
196                    new BeanProperties(this.project),
197                    BEGIN_TOKEN,
198                    END_TOKEN);
199            reader = new InterpolationFilterReader(
200                    reader,
201                    new BeanProperties(this.project),
202                    BEGIN_TOKEN,
203                    END_TOKEN);
204            replacement = ResourceUtils.getContents(reader);
205        }
206        finally
207        {
208            reader.close();
209        }
210        return replacement;
211    }
212
213}