001    /*
002     * #%L
003     * License Maven Plugin
004     *
005     * $Id: AbstractLicenseMojo.java 14409 2011-08-10 15:30:41Z tchemit $
006     * $HeadURL: http://svn.codehaus.org/mojo/tags/license-maven-plugin-1.0/src/main/java/org/codehaus/mojo/license/AbstractLicenseMojo.java $
007     * %%
008     * Copyright (C) 2008 - 2011 CodeLutin, Codehaus, Tony Chemit
009     * %%
010     * This program is free software: you can redistribute it and/or modify
011     * it under the terms of the GNU Lesser General Public License as
012     * published by the Free Software Foundation, either version 3 of the
013     * License, or (at your option) any later version.
014     *
015     * This program is distributed in the hope that it will be useful,
016     * but WITHOUT ANY WARRANTY; without even the implied warranty of
017     * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
018     * GNU General Lesser Public License for more details.
019     *
020     * You should have received a copy of the GNU General Lesser Public
021     * License along with this program.  If not, see
022     * <http://www.gnu.org/licenses/lgpl-3.0.html>.
023     * #L%
024     */
025    
026    package org.codehaus.mojo.license;
027    
028    import java.io.File;
029    import java.util.Arrays;
030    
031    import org.apache.commons.lang.StringUtils;
032    import org.apache.maven.execution.MavenSession;
033    import org.apache.maven.plugin.AbstractMojo;
034    import org.apache.maven.plugin.MojoExecutionException;
035    import org.apache.maven.plugin.MojoFailureException;
036    import org.apache.maven.project.MavenProject;
037    import org.codehaus.plexus.util.ReaderFactory;
038    
039    /**
040     * Abstract license mojo.
041     *
042     * @author tchemit <chemit@codelutin.com>
043     * @since 1.0
044     */
045    public abstract class AbstractLicenseMojo extends AbstractMojo {
046    
047        /**
048         * Current maven session. (used to launch certain mojo once by build).
049         *
050         * @parameter expression="${session}"
051         * @required
052         * @readonly
053         * @since 1.0
054         */
055        private MavenSession session;
056    
057        /**
058         * The reacted project.
059         *
060         * @parameter default-value="${project}"
061         * @required
062         * @since 1.0
063         */
064        private MavenProject project;
065    
066        /**
067         * Flag to activate verbose mode.
068         * <p/>
069         * <b>Note:</b> Verbose mode is always on if you starts a debug maven instance (says via {@code -X}).
070         *
071         * @parameter expression="${license.verbose}" default-value="${maven.verbose}"
072         * @since 1.0
073         */
074        private boolean verbose;
075    
076        /**
077         * Encoding used to read and writes files.
078         * <p/>
079         * <b>Note:</b> If nothing is filled here, we will use the system property {@code file.encoding}.
080         *
081         * @parameter expression="${license.encoding}" default-value="${project.build.sourceEncoding}"
082         * @since 1.0
083         */
084        private String encoding;
085    
086        public final String getEncoding() {
087            return encoding;
088        }
089    
090        public final void setEncoding(String encoding) {
091            this.encoding = encoding;
092        }
093    
094        /**
095         * Method to initialize the mojo before doing any concrete actions.
096         * <p/>
097         * <b>Note:</b> The method is invoked before the {@link #doAction()} method.
098         *
099         * @throws Exception
100         *             if any
101         */
102        protected abstract void init() throws Exception;
103    
104        /**
105         * Do plugin action.
106         * <p/>
107         * The method {@link #execute()} invoke this method only and only if :
108         * <ul>
109         * <li>{@link #checkPackaging()} returns {@code true}.</li>
110         * <li>method {@link #init()} returns {@code true}.</li>
111         * </ul>
112         *
113         * @throws Exception
114         *             if any
115         */
116        protected abstract void doAction() throws Exception;
117    
118        @Override
119        public final void execute() throws MojoExecutionException, MojoFailureException {
120            try {
121                if (getLog().isDebugEnabled()) {
122    
123                    // always be verbose in debug mode
124                    setVerbose(true);
125                }
126    
127                // check if project packaging is compatible with the mojo
128    
129                boolean canContinue = checkPackaging();
130                if (!canContinue) {
131                    getLog().debug("Skip for packaging '" + getProject().getPackaging() + "'");
132                    return;
133                }
134    
135                // init the mojo
136    
137                try {
138    
139                    checkEncoding();
140    
141                    init();
142    
143                } catch (MojoFailureException e) {
144                    throw e;
145                } catch (MojoExecutionException e) {
146                    throw e;
147                } catch (Exception e) {
148                    throw new MojoExecutionException("could not init goal " + getClass().getSimpleName() + " for reason : "
149                            + e.getMessage(), e);
150                }
151    
152                // check if mojo can be skipped
153    
154                canContinue = checkSkip();
155                if (!canContinue) {
156                    if (isVerbose()) {
157                        getLog().info("Goal will not be executed.");
158                    }
159                    return;
160                }
161    
162                // can really execute the mojo
163    
164                try {
165    
166                    doAction();
167    
168                } catch (MojoFailureException e) {
169                    throw e;
170                } catch (MojoExecutionException e) {
171                    throw e;
172                } catch (Exception e) {
173                    throw new MojoExecutionException("could not execute goal " + getClass().getSimpleName()
174                            + " for reason : " + e.getMessage(), e);
175                }
176            } finally {
177                afterExecute();
178            }
179        }
180    
181        /**
182         * A call back to execute after the {@link #execute()} is done
183         */
184        protected void afterExecute() {
185            // by default do nothing
186        }
187    
188        /**
189         * Check if the project packaging is acceptable for the mojo.
190         * <p/>
191         * By default, accept all packaging types.
192         * <p/>
193         * <b>Note:</b> This method is the first instruction to be executed in the {@link #execute()}.
194         * <p/>
195         * <b>Tip:</b> There is two method to simplify the packaging check :
196         * <p/>
197         * {@link #acceptPackaging(String...)}
198         * <p/>
199         * and
200         * <p/>
201         * {@link #rejectPackaging(String...)}
202         *
203         * @return {@code true} if can execute the goal for the packaging of the project, {@code false} otherwise.
204         */
205        protected boolean checkPackaging() {
206            // by default, accept every type of packaging
207            return true;
208        }
209    
210        /**
211         * Checks if the mojo execution should be skipped.
212         *
213         * @return {@code false} if the mojo should not be executed.
214         */
215        protected boolean checkSkip() {
216            // by default, never skip goal
217            return true;
218        }
219    
220        /**
221         * Accept the project's packaging between some given.
222         *
223         * @param packages
224         *            the accepted packaging
225         * @return {@code true} if the project's packaging is one of the given ones.
226         */
227        protected boolean acceptPackaging(String... packages) {
228            String projectPackaging = getProject().getPackaging();
229    
230            for (String p : packages) {
231                if (p.equals(projectPackaging)) {
232                    // accept packaging
233                    return true;
234                }
235            }
236            // reject packaging
237            return false;
238        }
239    
240        /**
241         * Accept the project's packaging if not in given one.
242         *
243         * @param packages
244         *            the rejecting packagings
245         * @return {@code true} if the project's packaging is not in the given ones.
246         */
247        protected boolean rejectPackaging(String... packages) {
248            String projectPackaging = getProject().getPackaging();
249    
250            for (String p : packages) {
251                if (p.equals(projectPackaging)) {
252                    // reject this packaging
253                    return false;
254                }
255            }
256            // accept packaging
257            return true;
258        }
259    
260        /**
261         * Method to be invoked in init phase to check sanity of {@link #getEncoding()}.
262         * <p/>
263         * If no encoding was filled, then use the default for system (via {@code file.encoding} environement property).
264         */
265        protected void checkEncoding() {
266    
267            if (isVerbose()) {
268                getLog().info("Will check encoding : " + getEncoding());
269            }
270            if (StringUtils.isEmpty(getEncoding())) {
271                getLog().warn(
272                        "File encoding has not been set, using platform encoding " + ReaderFactory.FILE_ENCODING
273                                + ", i.e. build is platform dependent!");
274                setEncoding(ReaderFactory.FILE_ENCODING);
275            }
276        }
277    
278        public final MavenProject getProject() {
279            return project;
280        }
281    
282        public final void setProject(MavenProject project) {
283            this.project = project;
284        }
285    
286        public final boolean isVerbose() {
287            return verbose;
288        }
289    
290        public final void setVerbose(boolean verbose) {
291            this.verbose = verbose;
292        }
293    
294        public final MavenSession getSession() {
295            return session;
296        }
297    
298        public final void setSession(MavenSession session) {
299            this.session = session;
300        }
301    
302        public final long getBuildTimestamp() {
303            return session.getStartTime().getTime();
304        }
305    
306        /**
307         * Add a new resource location to the maven project (in not already present).
308         *
309         * @param dir
310         *            the new resource location to add
311         * @param includes
312         *            files to include
313         */
314        protected void addResourceDir(File dir, String... includes) {
315            boolean added = MojoHelper.addResourceDir(dir, getProject(), includes);
316            if (added && isVerbose()) {
317                getLog().info("add resource " + dir + " with includes " + Arrays.toString(includes));
318            }
319        }
320    
321        /**
322         * @return {@code true} if project is not a pom, {@code false} otherwise.
323         */
324        protected boolean hasClassPath() {
325            return rejectPackaging("pom");
326        }
327    
328    }