001    package org.codehaus.mojo.exec;
002    
003    import java.io.File;
004    import java.io.FileOutputStream;
005    import java.io.IOException;
006    import java.io.InputStream;
007    import java.io.OutputStream;
008    import java.util.ArrayList;
009    import java.util.List;
010    
011    import org.apache.commons.io.IOUtils;
012    import org.apache.maven.plugin.MojoExecutionException;
013    import org.apache.tools.ant.DirectoryScanner;
014    import org.codehaus.plexus.util.StringUtils;
015    import org.springframework.core.io.DefaultResourceLoader;
016    import org.springframework.core.io.Resource;
017    import org.springframework.core.io.ResourceLoader;
018    import static org.codehaus.plexus.util.StringUtils.isEmpty;
019    
020    /**
021     * A plugin for executing the Eclipse java source code formatter
022     * 
023     * @author Jeff Caddel
024     * @goal format
025     * @aggregator
026     */
027    public class EclipseFormatterMojo extends ExecMojo {
028            private static final String FS = System.getProperty("file.separator");
029    
030            /**
031             * Binaries representing a Java VM. Default values are "javaw.exe", "java.exe", and "java". This list is searched in
032             * order, stopping as soon as one is found.
033             * 
034             * @parameter
035             */
036            private String[] javaBinaries = new String[] { "javaw.exe", "java.exe", "java" };
037    
038            /**
039             * Full path to the Eclipse executable binary
040             * 
041             * @parameter expression="${eclipse.binary}"
042             * @required
043             */
044            private String eclipseBinary;
045    
046            /**
047             * Full path to a Java VM. This gets filled in using the system property "java.home" unless a value is supplied
048             * here.
049             * 
050             * @parameter expression="${eclipse.vm}"
051             */
052            private String vm;
053    
054            /**
055             * This is the name of the Eclipse application that performs the formatting
056             * 
057             * @parameter expression="${eclipse.application}" default-value="org.eclipse.jdt.core.JavaCodeFormatter"
058             * @required
059             */
060            private String application;
061    
062            /**
063             * Pointer to an Eclipse "org.eclipse.jdt.core.prefs" file. Supports "classpath:" style notation
064             * 
065             * @parameter expression="${eclipse.formatterPreferences}" default-value="classpath:eclipse.prefs"
066             * @required
067             */
068            private String formatterPreferences;
069    
070            /**
071             * Any arguments specified here are passed to the Eclipse binary as additional command line arguments. Default
072             * values are "-nosplash -verbose"
073             * 
074             * @parameter
075             */
076            private String[] eclipseArgs = new String[] { "-nosplash", "-verbose" };
077    
078            /**
079             * Regular expressions for directories that contain Java source code to format. Default value is
080             * **/src/main/java. The Eclipse formatter will recursively inspect any directories matching these
081             * patterns for *.java files
082             * 
083             * @parameter
084             */
085            private String[] includes = new String[] { "**/src/main/java" };
086    
087            /**
088             * Regular expressions for directories to exclude from the process that scans for *.java files
089             * 
090             * @parameter
091             */
092            private String[] excludes = new String[] { "**/.settings", "**/.svn" };
093    
094            protected List<File> getSourceDirectories() {
095                    DirectoryScanner scanner = new DirectoryScanner();
096                    scanner.setBasedir(project.getBasedir());
097                    scanner.setIncludes(includes);
098                    scanner.setExcludes(excludes);
099                    scanner.scan();
100                    String[] includedDirs = scanner.getIncludedDirectories();
101                    List<File> dirs = new ArrayList<File>();
102                    for (String includedDir : includedDirs) {
103                            File file = new File(project.getBasedir().getAbsolutePath() + FS + includedDir);
104                            dirs.add(file);
105                    }
106                    return dirs;
107            }
108    
109            protected void showDirs(List<File> srcDirs) {
110                    getLog().info("Located " + srcDirs.size() + " source directories:");
111                    for (File dir : srcDirs) {
112                            getLog().info(dir.getAbsolutePath());
113                    }
114            }
115    
116            protected void showConfig(File eclipseBinary, File javaBinary) {
117                    getLog().info("Eclipse Location: " + eclipseBinary.getAbsolutePath());
118                    getLog().info("Java VM: " + javaBinary.getAbsolutePath());
119                    getLog().info("Scanning directory: " + project.getBasedir());
120                    StringBuilder sb = new StringBuilder();
121                    for (String include : includes) {
122                            sb.append(include + " ");
123                    }
124                    getLog().info("Includes: " + sb.toString());
125                    sb = new StringBuilder();
126                    for (String exclude : excludes) {
127                            sb.append(exclude + " ");
128                    }
129                    getLog().info("Excludes: " + sb.toString());
130            }
131    
132            @Override
133            public void execute() throws MojoExecutionException {
134                    if (!fileExists(eclipseBinary)) {
135                            throw new MojoExecutionException(eclipseBinary + " does not exist");
136                    }
137                    File eclipseBinaryFile = new File(eclipseBinary);
138                    File javaBinary = getJavaBinary();
139                    showConfig(eclipseBinaryFile, javaBinary);
140    
141                    List<File> dirs = getSourceDirectories();
142                    if (dirs.size() == 0) {
143                            getLog().info("No directories containing source code were located");
144                            return;
145                    }
146                    showDirs(dirs);
147    
148                    super.setExecutable(eclipseBinaryFile.getAbsolutePath());
149                    super.setArguments(getEclipseArguments(javaBinary, dirs));
150    
151                    super.execute();
152            }
153    
154            protected boolean fileExists(String filename) {
155                    return new File(filename).exists();
156            }
157    
158            protected File getJavaBinary() throws MojoExecutionException {
159                    // They provided us with a VM, and we found a file in the location they specified
160                    if (!isEmpty(vm) && fileExists(vm)) {
161                            return new File(vm);
162                    }
163    
164                    // They asked us to use a specific VM, but it doesn't exist
165                    if (!isEmpty(vm) && !fileExists(vm)) {
166                            throw new MojoExecutionException(vm + " does not exist");
167                    }
168    
169                    // They did not specify a VM, attempt to locate one
170                    String javaHome = System.getProperty("java.home");
171                    String binaryHome = javaHome + FS + "bin";
172                    for (String binary : javaBinaries) {
173                            File file = new File(binaryHome + FS + binary);
174                            if (file.exists()) {
175                                    return file;
176                            }
177                    }
178                    throw new MojoExecutionException(
179                                    "No Java VM location was supplied, and we could not locate one using the System property 'java.home'");
180            }
181    
182            protected List<String> getEclipseArguments(File javaBinary, List<File> dirs) throws MojoExecutionException {
183                    List<String> args = new ArrayList<String>();
184                    args.add("-application");
185                    args.add(application);
186                    args.add("-vm");
187                    args.add(javaBinary.getAbsolutePath());
188                    args.add("-config");
189                    args.add(getConfigAbsolutePath());
190                    for (String arg : eclipseArgs) {
191                            addIfNotEmpty(args, arg);
192                    }
193                    for (File dir : dirs) {
194                            args.add(dir.getAbsolutePath());
195                    }
196                    return args;
197            }
198    
199            protected String getConfigAbsolutePath() throws MojoExecutionException {
200                    File file = new File(formatterPreferences);
201                    if (file.exists()) {
202                            return file.getAbsolutePath();
203                    }
204                    ResourceLoader loader = new DefaultResourceLoader();
205                    Resource resource = loader.getResource(formatterPreferences);
206                    if (!resource.exists()) {
207                            throw new MojoExecutionException("Unable to locate " + formatterPreferences);
208                    }
209                    OutputStream out = null;
210                    InputStream in = null;
211                    try {
212                            File temp = File.createTempFile("eclipse.prefs.", null);
213                            temp.deleteOnExit();
214                            out = new FileOutputStream(temp);
215                            in = resource.getInputStream();
216                            IOUtils.copy(in, out);
217                            return temp.getAbsolutePath();
218                    } catch (IOException e) {
219                            throw new MojoExecutionException("Error copying resource " + formatterPreferences, e);
220                    } finally {
221                            IOUtils.closeQuietly(out);
222                            IOUtils.closeQuietly(in);
223                    }
224    
225            }
226    
227            protected void addIfNotEmpty(List<String> list, String s) {
228                    if (StringUtils.isEmpty(s)) {
229                            return;
230                    }
231                    list.add(s);
232            }
233    
234            public String getEclipseBinary() {
235                    return eclipseBinary;
236            }
237    
238            public void setEclipseBinary(String eclipseExecutable) {
239                    this.eclipseBinary = eclipseExecutable;
240            }
241    
242            public String getVm() {
243                    return vm;
244            }
245    
246            public void setVm(String vm) {
247                    this.vm = vm;
248            }
249    
250            public String getApplication() {
251                    return application;
252            }
253    
254            public void setApplication(String application) {
255                    this.application = application;
256            }
257    
258            public String[] getIncludes() {
259                    return includes;
260            }
261    
262            public void setIncludes(String[] includes) {
263                    this.includes = includes;
264            }
265    
266            public String[] getExcludes() {
267                    return excludes;
268            }
269    
270            public void setExcludes(String[] excludes) {
271                    this.excludes = excludes;
272            }
273    
274            public String[] getJavaBinaries() {
275                    return javaBinaries;
276            }
277    
278            public void setJavaBinaries(String[] binaries) {
279                    this.javaBinaries = binaries;
280            }
281    
282            public String getFormatterPreferences() {
283                    return formatterPreferences;
284            }
285    
286            public void setFormatterPreferences(String formatterPreferences) {
287                    this.formatterPreferences = formatterPreferences;
288            }
289    
290            public String[] getEclipseArgs() {
291                    return eclipseArgs;
292            }
293    
294            public void setEclipseArgs(String[] args) {
295                    this.eclipseArgs = args;
296            }
297    
298    }