001 /**
002 * Copyright 2010-2012 The Kuali Foundation
003 *
004 * Licensed under the Educational Community License, Version 2.0 (the "License");
005 * you may not use this file except in compliance with the License.
006 * You may obtain a copy of the License at
007 *
008 * http://www.opensource.org/licenses/ecl2.php
009 *
010 * Unless required by applicable law or agreed to in writing, software
011 * distributed under the License is distributed on an "AS IS" BASIS,
012 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
013 * See the License for the specific language governing permissions and
014 * limitations under the License.
015 */
016 package org.codehaus.mojo.license;
017
018 import java.io.File;
019 import java.util.Arrays;
020
021 import org.apache.commons.lang.StringUtils;
022 import org.apache.maven.execution.MavenSession;
023 import org.apache.maven.plugin.AbstractMojo;
024 import org.apache.maven.plugin.MojoExecutionException;
025 import org.apache.maven.plugin.MojoFailureException;
026 import org.apache.maven.project.MavenProject;
027 import org.codehaus.plexus.util.ReaderFactory;
028
029 /**
030 * Abstract license mojo.
031 *
032 * @author tchemit <chemit@codelutin.com>
033 * @since 1.0
034 */
035 public abstract class AbstractLicenseMojo extends AbstractMojo {
036
037 /**
038 * Current maven session. (used to launch certain mojo once by build).
039 *
040 * @parameter expression="${session}"
041 * @required
042 * @readonly
043 * @since 1.0
044 */
045 private MavenSession session;
046
047 /**
048 * The reacted project.
049 *
050 * @parameter default-value="${project}"
051 * @required
052 * @since 1.0
053 */
054 private MavenProject project;
055
056 /**
057 * Flag to activate verbose mode.
058 * <p/>
059 * <b>Note:</b> Verbose mode is always on if you starts a debug maven instance (says via {@code -X}).
060 *
061 * @parameter expression="${license.verbose}" default-value="${maven.verbose}"
062 * @since 1.0
063 */
064 private boolean verbose;
065
066 /**
067 * Encoding used to read and writes files.
068 * <p/>
069 * <b>Note:</b> If nothing is filled here, we will use the system property {@code file.encoding}.
070 *
071 * @parameter expression="${license.encoding}" default-value="${project.build.sourceEncoding}"
072 * @since 1.0
073 */
074 private String encoding;
075
076 public final String getEncoding() {
077 return encoding;
078 }
079
080 public final void setEncoding(String encoding) {
081 this.encoding = encoding;
082 }
083
084 /**
085 * Method to initialize the mojo before doing any concrete actions.
086 * <p/>
087 * <b>Note:</b> The method is invoked before the {@link #doAction()} method.
088 *
089 * @throws Exception
090 * if any
091 */
092 protected abstract void init() throws Exception;
093
094 /**
095 * Do plugin action.
096 * <p/>
097 * The method {@link #execute()} invoke this method only and only if :
098 * <ul>
099 * <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 }