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