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 }