001package org.andromda.maven.plugin;
002
003import java.util.ArrayList;
004import java.util.Iterator;
005import java.util.List;
006
007import org.apache.maven.plugin.AbstractMojo;
008import org.apache.maven.plugin.MojoExecutionException;
009
010/**
011 * Display help information on andromda-maven-plugin.<br/> Call <pre>  mvn andromda:help -Ddetail=true -Dgoal=&lt;goal-name&gt;</pre> to display parameter details.
012 *
013 * @version generated on Thu Sep 18 16:08:07 EDT 2014
014 * @author org.apache.maven.tools.plugin.generator.PluginHelpGenerator (version 2.9)
015 * @goal help
016 * @requiresProject false
017 * @threadSafe
018 */
019public class HelpMojo
020    extends AbstractMojo
021{
022    /**
023     * If <code>true</code>, display all settable properties for each goal.
024     * 
025     * @parameter expression="${detail}" default-value="false"
026     */
027    private boolean detail;
028
029    /**
030     * The name of the goal for which to show help. If unspecified, all goals will be displayed.
031     * 
032     * @parameter expression="${goal}"
033     */
034    private java.lang.String goal;
035
036    /**
037     * The maximum length of a display line, should be positive.
038     * 
039     * @parameter expression="${lineLength}" default-value="80"
040     */
041    private int lineLength;
042
043    /**
044     * The number of spaces per indentation level, should be positive.
045     * 
046     * @parameter expression="${indentSize}" default-value="2"
047     */
048    private int indentSize;
049
050
051    /** {@inheritDoc} */
052    public void execute()
053        throws MojoExecutionException
054    {
055        if ( lineLength <= 0 )
056        {
057            getLog().warn( "The parameter 'lineLength' should be positive, using '80' as default." );
058            lineLength = 80;
059        }
060        if ( indentSize <= 0 )
061        {
062            getLog().warn( "The parameter 'indentSize' should be positive, using '2' as default." );
063            indentSize = 2;
064        }
065
066        StringBuffer sb = new StringBuffer();
067
068        append( sb, "org.andromda.maven.plugins:andromda-maven-plugin:3.5-SNAPSHOT", 0 );
069        append( sb, "", 0 );
070
071        append( sb, "AndroMDA Maven Plugin", 0 );
072        append( sb, "A plugin for running AndroMDA\'s model processor.", 1 );
073        append( sb, "", 0 );
074
075        if ( goal == null || goal.length() <= 0 )
076        {
077            append( sb, "This plugin has 5 goals:", 0 );
078            append( sb, "", 0 );
079        }
080
081        if ( goal == null || goal.length() <= 0 || "export2emf".equals( goal ) )
082        {
083            append( sb, "andromda:export2emf", 0 );
084            append( sb, "Exports the MagicDraw project file to EMF XMI (requires valid MagicDraw installation in MD_HOME, but only if target files are not up-to-date)", 1 );
085            append( sb, "", 0 );
086            if ( detail )
087            {
088                append( sb, "Available parameters:", 1 );
089                append( sb, "", 0 );
090
091                append( sb, "allowMultipleRuns (Default: false)", 2 );
092                append( sb, "Do we allow the code generation to run multiple times? Yes for AndroMDA server, no for all other cases unless overridden. This prevents multiple code generation runs while creating site documentation, generate-sources phase can run more than 8 times for each model when initiated by many of the reporting plugins.", 3 );
093                append( sb, "Required: Yes", 3 );
094                append( sb, "", 0 );
095
096                append( sb, "configurationUri", 2 );
097                append( sb, "This is the URI to the AndroMDA configuration file.", 3 );
098                append( sb, "Required: Yes", 3 );
099                append( sb, "Expression: file:${project.basedir}/conf/andromda.xml", 3 );
100                append( sb, "", 0 );
101
102                append( sb, "magicDrawHome", 2 );
103                append( sb, "The home/root directory of the magicdraw installation.", 3 );
104                append( sb, "Expression: ${magicDrawHome}", 3 );
105                append( sb, "", 0 );
106
107                append( sb, "propertyFiles", 2 );
108                append( sb, "(no description available)", 3 );
109                append( sb, "Expression: ${project.build.filters}", 3 );
110                append( sb, "", 0 );
111            }
112        }
113
114        if ( goal == null || goal.length() <= 0 || "help".equals( goal ) )
115        {
116            append( sb, "andromda:help", 0 );
117            append( sb, "Display help information on andromda-maven-plugin.\nCall\n\u00a0\u00a0mvn\u00a0andromda:help\u00a0-Ddetail=true\u00a0-Dgoal=<goal-name>\nto display parameter details.", 1 );
118            append( sb, "", 0 );
119            if ( detail )
120            {
121                append( sb, "Available parameters:", 1 );
122                append( sb, "", 0 );
123
124                append( sb, "detail (Default: false)", 2 );
125                append( sb, "If true, display all settable properties for each goal.", 3 );
126                append( sb, "Expression: ${detail}", 3 );
127                append( sb, "", 0 );
128
129                append( sb, "goal", 2 );
130                append( sb, "The name of the goal for which to show help. If unspecified, all goals will be displayed.", 3 );
131                append( sb, "Expression: ${goal}", 3 );
132                append( sb, "", 0 );
133
134                append( sb, "indentSize (Default: 2)", 2 );
135                append( sb, "The number of spaces per indentation level, should be positive.", 3 );
136                append( sb, "Expression: ${indentSize}", 3 );
137                append( sb, "", 0 );
138
139                append( sb, "lineLength (Default: 80)", 2 );
140                append( sb, "The maximum length of a display line, should be positive.", 3 );
141                append( sb, "Expression: ${lineLength}", 3 );
142                append( sb, "", 0 );
143            }
144        }
145
146        if ( goal == null || goal.length() <= 0 || "run".equals( goal ) )
147        {
148            append( sb, "andromda:run", 0 );
149            append( sb, "A Maven2 plugin to run AndroMDA.", 1 );
150            append( sb, "", 0 );
151            if ( detail )
152            {
153                append( sb, "Available parameters:", 1 );
154                append( sb, "", 0 );
155
156                append( sb, "allowMultipleRuns (Default: false)", 2 );
157                append( sb, "Do we allow the code generation to run multiple times? Yes for AndroMDA server, no for all other cases unless overridden. This prevents multiple code generation runs while creating site documentation, generate-sources phase can run more than 8 times for each model when initiated by many of the reporting plugins.", 3 );
158                append( sb, "Required: Yes", 3 );
159                append( sb, "", 0 );
160
161                append( sb, "buildSourceDirectory", 2 );
162                append( sb, "The directory to which the build source is located (any generated source).", 3 );
163                append( sb, "Expression: ${project.build.directory}/src/main/java", 3 );
164                append( sb, "", 0 );
165
166                append( sb, "configurationUri", 2 );
167                append( sb, "This is the URI to the AndroMDA configuration file.", 3 );
168                append( sb, "Required: Yes", 3 );
169                append( sb, "Expression: file:${project.basedir}/conf/andromda.xml", 3 );
170                append( sb, "", 0 );
171
172                append( sb, "lastModifiedCheck (Default: true)", 2 );
173                append( sb, "Whether or not a last modified check should be performed before running AndroMDA again. Checks files in buildSourceDirectory against configurationUri and referenced model dates.", 3 );
174                append( sb, "Expression: ${lastModifiedCheck}", 3 );
175                append( sb, "", 0 );
176
177                append( sb, "modelOutputHistory", 2 );
178                append( sb, "The directory where the model generation output history is located (Modelname file containing a list of files generated by that model).", 3 );
179                append( sb, "Expression: ${project.build.directory}/history", 3 );
180                append( sb, "", 0 );
181
182                append( sb, "propertyFiles", 2 );
183                append( sb, "(no description available)", 3 );
184                append( sb, "Expression: ${project.build.filters}", 3 );
185                append( sb, "", 0 );
186
187                append( sb, "skipProcessing (Default: false)", 2 );
188                append( sb, "Whether or not processing should be skipped (this is if you just want to force AndroMDA not to run on your model).", 3 );
189                append( sb, "Expression: ${andromda.run.skip}", 3 );
190                append( sb, "", 0 );
191            }
192        }
193
194        if ( goal == null || goal.length() <= 0 || "start-server".equals( goal ) )
195        {
196            append( sb, "andromda:start-server", 0 );
197            append( sb, "Provides the ability to start the AndroMDA server.", 1 );
198            append( sb, "", 0 );
199            if ( detail )
200            {
201                append( sb, "Available parameters:", 1 );
202                append( sb, "", 0 );
203
204                append( sb, "allowMultipleRuns (Default: false)", 2 );
205                append( sb, "Do we allow the code generation to run multiple times? Yes for AndroMDA server, no for all other cases unless overridden. This prevents multiple code generation runs while creating site documentation, generate-sources phase can run more than 8 times for each model when initiated by many of the reporting plugins.", 3 );
206                append( sb, "Required: Yes", 3 );
207                append( sb, "", 0 );
208
209                append( sb, "configurationUri", 2 );
210                append( sb, "This is the URI to the AndroMDA configuration file.", 3 );
211                append( sb, "Required: Yes", 3 );
212                append( sb, "Expression: file:${project.basedir}/conf/andromda.xml", 3 );
213                append( sb, "", 0 );
214
215                append( sb, "propertyFiles", 2 );
216                append( sb, "(no description available)", 3 );
217                append( sb, "Expression: ${project.build.filters}", 3 );
218                append( sb, "", 0 );
219            }
220        }
221
222        if ( goal == null || goal.length() <= 0 || "stop-server".equals( goal ) )
223        {
224            append( sb, "andromda:stop-server", 0 );
225            append( sb, "Provides the ability to stop the AndroMDA server.", 1 );
226            append( sb, "", 0 );
227            if ( detail )
228            {
229                append( sb, "Available parameters:", 1 );
230                append( sb, "", 0 );
231
232                append( sb, "allowMultipleRuns (Default: false)", 2 );
233                append( sb, "Do we allow the code generation to run multiple times? Yes for AndroMDA server, no for all other cases unless overridden. This prevents multiple code generation runs while creating site documentation, generate-sources phase can run more than 8 times for each model when initiated by many of the reporting plugins.", 3 );
234                append( sb, "Required: Yes", 3 );
235                append( sb, "", 0 );
236
237                append( sb, "configurationUri", 2 );
238                append( sb, "This is the URI to the AndroMDA configuration file.", 3 );
239                append( sb, "Required: Yes", 3 );
240                append( sb, "Expression: file:${project.basedir}/conf/andromda.xml", 3 );
241                append( sb, "", 0 );
242
243                append( sb, "propertyFiles", 2 );
244                append( sb, "(no description available)", 3 );
245                append( sb, "Expression: ${project.build.filters}", 3 );
246                append( sb, "", 0 );
247            }
248        }
249
250        if ( getLog().isInfoEnabled() )
251        {
252            getLog().info( sb.toString() );
253        }
254    }
255
256    /**
257     * <p>Repeat a String <code>n</code> times to form a new string.</p>
258     *
259     * @param str String to repeat
260     * @param repeat number of times to repeat str
261     * @return String with repeated String
262     * @throws NegativeArraySizeException if <code>repeat < 0</code>
263     * @throws NullPointerException if str is <code>null</code>
264     */
265    private static String repeat( String str, int repeat )
266    {
267        StringBuffer buffer = new StringBuffer( repeat * str.length() );
268
269        for ( int i = 0; i < repeat; i++ )
270        {
271            buffer.append( str );
272        }
273
274        return buffer.toString();
275    }
276
277    /** 
278     * Append a description to the buffer by respecting the indentSize and lineLength parameters.
279     * <b>Note</b>: The last character is always a new line.
280     * 
281     * @param sb The buffer to append the description, not <code>null</code>.
282     * @param description The description, not <code>null</code>.
283     * @param indent The base indentation level of each line, must not be negative.
284     */
285    private void append( StringBuffer sb, String description, int indent )
286    {
287        for ( Iterator it = toLines( description, indent, indentSize, lineLength ).iterator(); it.hasNext(); )
288        {
289            sb.append( it.next().toString() ).append( '\n' );
290        }
291    }
292
293    /** 
294     * Splits the specified text into lines of convenient display length.
295     * 
296     * @param text The text to split into lines, must not be <code>null</code>.
297     * @param indent The base indentation level of each line, must not be negative.
298     * @param indentSize The size of each indentation, must not be negative.
299     * @param lineLength The length of the line, must not be negative.
300     * @return The sequence of display lines, never <code>null</code>.
301     * @throws NegativeArraySizeException if <code>indent < 0</code>
302     */
303    private static List toLines( String text, int indent, int indentSize, int lineLength )
304    {
305        List lines = new ArrayList();
306
307        String ind = repeat( "\t", indent );
308        String[] plainLines = text.split( "(\r\n)|(\r)|(\n)" );
309        for ( int i = 0; i < plainLines.length; i++ )
310        {
311            toLines( lines, ind + plainLines[i], indentSize, lineLength );
312        }
313
314        return lines;
315    }
316
317    /** 
318     * Adds the specified line to the output sequence, performing line wrapping if necessary.
319     * 
320     * @param lines The sequence of display lines, must not be <code>null</code>.
321     * @param line The line to add, must not be <code>null</code>.
322     * @param indentSize The size of each indentation, must not be negative.
323     * @param lineLength The length of the line, must not be negative.
324     */
325    private static void toLines( List lines, String line, int indentSize, int lineLength )
326    {
327        int lineIndent = getIndentLevel( line );
328        StringBuffer buf = new StringBuffer( 256 );
329        String[] tokens = line.split( " +" );
330        for ( int i = 0; i < tokens.length; i++ )
331        {
332            String token = tokens[i];
333            if ( i > 0 )
334            {
335                if ( buf.length() + token.length() >= lineLength )
336                {
337                    lines.add( buf.toString() );
338                    buf.setLength( 0 );
339                    buf.append( repeat( " ", lineIndent * indentSize ) );
340                }
341                else
342                {
343                    buf.append( ' ' );
344                }
345            }
346            for ( int j = 0; j < token.length(); j++ )
347            {
348                char c = token.charAt( j );
349                if ( c == '\t' )
350                {
351                    buf.append( repeat( " ", indentSize - buf.length() % indentSize ) );
352                }
353                else if ( c == '\u00A0' )
354                {
355                    buf.append( ' ' );
356                }
357                else
358                {
359                    buf.append( c );
360                }
361            }
362        }
363        lines.add( buf.toString() );
364    }
365
366    /** 
367     * Gets the indentation level of the specified line.
368     * 
369     * @param line The line whose indentation level should be retrieved, must not be <code>null</code>.
370     * @return The indentation level of the line.
371     */
372    private static int getIndentLevel( String line )
373    {
374        int level = 0;
375        for ( int i = 0; i < line.length() && line.charAt( i ) == '\t'; i++ )
376        {
377            level++;
378        }
379        for ( int i = level + 1; i <= level + 4 && i < line.length(); i++ )
380        {
381            if ( line.charAt( i ) == '\t' )
382            {
383                level++;
384                break;
385            }
386        }
387        return level;
388    }
389}