1 /**
2 * Copyright 2010-2012 The Kuali Foundation
3 *
4 * Licensed under the Educational Community License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.opensource.org/licenses/ecl2.php
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16 package org.codehaus.mojo.license;
17
18 import java.io.File;
19 import java.util.Arrays;
20
21 import org.apache.commons.lang.StringUtils;
22 import org.apache.maven.execution.MavenSession;
23 import org.apache.maven.plugin.AbstractMojo;
24 import org.apache.maven.plugin.MojoExecutionException;
25 import org.apache.maven.plugin.MojoFailureException;
26 import org.apache.maven.project.MavenProject;
27 import org.codehaus.plexus.util.ReaderFactory;
28
29 /**
30 * Abstract license mojo.
31 *
32 * @author tchemit <chemit@codelutin.com>
33 * @since 1.0
34 */
35 public abstract class AbstractLicenseMojo extends AbstractMojo {
36
37 /**
38 * Current maven session. (used to launch certain mojo once by build).
39 *
40 * @parameter expression="${session}"
41 * @required
42 * @readonly
43 * @since 1.0
44 */
45 private MavenSession session;
46
47 /**
48 * The reacted project.
49 *
50 * @parameter default-value="${project}"
51 * @required
52 * @since 1.0
53 */
54 private MavenProject project;
55
56 /**
57 * Flag to activate verbose mode.
58 * <p/>
59 * <b>Note:</b> Verbose mode is always on if you starts a debug maven instance (says via {@code -X}).
60 *
61 * @parameter expression="${license.verbose}" default-value="${maven.verbose}"
62 * @since 1.0
63 */
64 private boolean verbose;
65
66 /**
67 * Encoding used to read and writes files.
68 * <p/>
69 * <b>Note:</b> If nothing is filled here, we will use the system property {@code file.encoding}.
70 *
71 * @parameter expression="${license.encoding}" default-value="${project.build.sourceEncoding}"
72 * @since 1.0
73 */
74 private String encoding;
75
76 public final String getEncoding() {
77 return encoding;
78 }
79
80 public final void setEncoding(String encoding) {
81 this.encoding = encoding;
82 }
83
84 /**
85 * Method to initialize the mojo before doing any concrete actions.
86 * <p/>
87 * <b>Note:</b> The method is invoked before the {@link #doAction()} method.
88 *
89 * @throws Exception
90 * if any
91 */
92 protected abstract void init() throws Exception;
93
94 /**
95 * Do plugin action.
96 * <p/>
97 * The method {@link #execute()} invoke this method only and only if :
98 * <ul>
99 * <li>{@link #checkPackaging()} returns {@code true}.</li>
100 * <li>method {@link #init()} returns {@code true}.</li>
101 * </ul>
102 *
103 * @throws Exception
104 * if any
105 */
106 protected abstract void doAction() throws Exception;
107
108 @Override
109 public final void execute() throws MojoExecutionException, MojoFailureException {
110 try {
111 if (getLog().isDebugEnabled()) {
112
113 // always be verbose in debug mode
114 setVerbose(true);
115 }
116
117 // check if project packaging is compatible with the mojo
118
119 boolean canContinue = checkPackaging();
120 if (!canContinue) {
121 getLog().debug("Skip for packaging '" + getProject().getPackaging() + "'");
122 return;
123 }
124
125 // init the mojo
126
127 try {
128
129 checkEncoding();
130
131 init();
132
133 } catch (MojoFailureException e) {
134 throw e;
135 } catch (MojoExecutionException e) {
136 throw e;
137 } catch (Exception e) {
138 throw new MojoExecutionException("could not init goal " + getClass().getSimpleName() + " for reason : "
139 + e.getMessage(), e);
140 }
141
142 // check if mojo can be skipped
143
144 canContinue = checkSkip();
145 if (!canContinue) {
146 if (isVerbose()) {
147 getLog().info("Goal will not be executed.");
148 }
149 return;
150 }
151
152 // can really execute the mojo
153
154 try {
155
156 doAction();
157
158 } catch (MojoFailureException e) {
159 throw e;
160 } catch (MojoExecutionException e) {
161 throw e;
162 } catch (Exception e) {
163 throw new MojoExecutionException("could not execute goal " + getClass().getSimpleName()
164 + " for reason : " + e.getMessage(), e);
165 }
166 } finally {
167 afterExecute();
168 }
169 }
170
171 /**
172 * A call back to execute after the {@link #execute()} is done
173 */
174 protected void afterExecute() {
175 // by default do nothing
176 }
177
178 /**
179 * Check if the project packaging is acceptable for the mojo.
180 * <p/>
181 * By default, accept all packaging types.
182 * <p/>
183 * <b>Note:</b> This method is the first instruction to be executed in the {@link #execute()}.
184 * <p/>
185 * <b>Tip:</b> There is two method to simplify the packaging check :
186 * <p/>
187 * {@link #acceptPackaging(String...)}
188 * <p/>
189 * and
190 * <p/>
191 * {@link #rejectPackaging(String...)}
192 *
193 * @return {@code true} if can execute the goal for the packaging of the project, {@code false} otherwise.
194 */
195 protected boolean checkPackaging() {
196 // by default, accept every type of packaging
197 return true;
198 }
199
200 /**
201 * Checks if the mojo execution should be skipped.
202 *
203 * @return {@code false} if the mojo should not be executed.
204 */
205 protected boolean checkSkip() {
206 // by default, never skip goal
207 return true;
208 }
209
210 /**
211 * Accept the project's packaging between some given.
212 *
213 * @param packages
214 * the accepted packaging
215 * @return {@code true} if the project's packaging is one of the given ones.
216 */
217 protected boolean acceptPackaging(String... packages) {
218 String projectPackaging = getProject().getPackaging();
219
220 for (String p : packages) {
221 if (p.equals(projectPackaging)) {
222 // accept packaging
223 return true;
224 }
225 }
226 // reject packaging
227 return false;
228 }
229
230 /**
231 * Accept the project's packaging if not in given one.
232 *
233 * @param packages
234 * the rejecting packagings
235 * @return {@code true} if the project's packaging is not in the given ones.
236 */
237 protected boolean rejectPackaging(String... packages) {
238 String projectPackaging = getProject().getPackaging();
239
240 for (String p : packages) {
241 if (p.equals(projectPackaging)) {
242 // reject this packaging
243 return false;
244 }
245 }
246 // accept packaging
247 return true;
248 }
249
250 /**
251 * Method to be invoked in init phase to check sanity of {@link #getEncoding()}.
252 * <p/>
253 * If no encoding was filled, then use the default for system (via {@code file.encoding} environement property).
254 */
255 protected void checkEncoding() {
256
257 if (isVerbose()) {
258 getLog().info("Will check encoding : " + getEncoding());
259 }
260 if (StringUtils.isEmpty(getEncoding())) {
261 getLog().warn(
262 "File encoding has not been set, using platform encoding " + ReaderFactory.FILE_ENCODING
263 + ", i.e. build is platform dependent!");
264 setEncoding(ReaderFactory.FILE_ENCODING);
265 }
266 }
267
268 public final MavenProject getProject() {
269 return project;
270 }
271
272 public final void setProject(MavenProject project) {
273 this.project = project;
274 }
275
276 public final boolean isVerbose() {
277 return verbose;
278 }
279
280 public final void setVerbose(boolean verbose) {
281 this.verbose = verbose;
282 }
283
284 public final MavenSession getSession() {
285 return session;
286 }
287
288 public final void setSession(MavenSession session) {
289 this.session = session;
290 }
291
292 public final long getBuildTimestamp() {
293 return session.getStartTime().getTime();
294 }
295
296 /**
297 * Add a new resource location to the maven project (in not already present).
298 *
299 * @param dir
300 * the new resource location to add
301 * @param includes
302 * files to include
303 */
304 protected void addResourceDir(File dir, String... includes) {
305 boolean added = MojoHelper.addResourceDir(dir, getProject(), includes);
306 if (added && isVerbose()) {
307 getLog().info("add resource " + dir + " with includes " + Arrays.toString(includes));
308 }
309 }
310
311 /**
312 * @return {@code true} if project is not a pom, {@code false} otherwise.
313 */
314 protected boolean hasClassPath() {
315 return rejectPackaging("pom");
316 }
317
318 }