View Javadoc
1   package org.apache.maven.plugins.enforcer;
2   
3   /*
4    * Licensed to the Apache Software Foundation (ASF) under one
5    * or more contributor license agreements.  See the NOTICE file
6    * distributed with this work for additional information
7    * regarding copyright ownership.  The ASF licenses this file
8    * to you under the Apache License, Version 2.0 (the
9    * "License"); you may not use this file except in compliance
10   * with the License.  You may obtain a copy of the License at
11   *
12   *  http://www.apache.org/licenses/LICENSE-2.0
13   *
14   * Unless required by applicable law or agreed to in writing,
15   * software distributed under the License is distributed on an
16   * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
17   * KIND, either express or implied.  See the License for the
18   * specific language governing permissions and limitations
19   * under the License.
20   */
21  
22  import java.util.Iterator;
23  
24  import org.apache.maven.enforcer.rule.api.EnforcerRule;
25  import org.apache.maven.enforcer.rule.api.EnforcerRuleException;
26  import org.apache.maven.enforcer.rule.api.EnforcerRuleHelper;
27  import org.apache.maven.model.Activation;
28  import org.apache.maven.model.ActivationOS;
29  import org.apache.maven.model.Profile;
30  import org.apache.maven.plugin.logging.Log;
31  import org.apache.maven.profiles.activation.OperatingSystemProfileActivator;
32  import org.codehaus.plexus.util.Os;
33  import org.codehaus.plexus.util.StringUtils;
34  
35  /**
36   * This rule checks that the OS is allowed by combinations of family, name, version and cpu architecture. The behavior
37   * is exactly the same as the Maven Os profile activation so the same values are allowed here.
38   *
39   * @author <a href="mailto:brianf@apache.org">Brian Fox</a>
40   * @version $Id: RequireOS.java 1634140 2014-10-24 21:23:01Z khmarbaise $
41   */
42  public class RequireOS
43      extends AbstractStandardEnforcerRule
44  {
45  
46      /**
47       * The OS family type desired<br />
48       * Possible values:
49       * <ul>
50       * <li>dos</li>
51       * <li>mac</li>
52       * <li>netware</li>
53       * <li>os/2</li>
54       * <li>tandem</li>
55       * <li>unix</li>
56       * <li>windows</li>
57       * <li>win9x</li>
58       * <li>z/os</li>
59       * <li>os/400</li>
60       * </ul>
61       * 
62       * @see {@link #setFamily(String)}
63       * @see {@link #getFamily()}
64       */
65      private String family = null;
66  
67      /**
68       * The OS name desired.
69       *
70       * @see {@link #setName(String)}
71       * @see {@link #getName()}
72       */
73      private String name = null;
74  
75      /**
76       * The OS version desired.
77       * 
78       * @see {@link #setVersion(String)}
79       * @see {@link #getVersion()}
80       */
81      private String version = null;
82  
83      /**
84       * The OS architecture desired.
85       * 
86       * @see {@link #setArch(String)}
87       * @see {@link #getArch()}
88       */
89      private String arch = null;
90  
91      /**
92       * Display detected OS information.
93       * 
94       * @see {@link #setDisplay(boolean)}
95       * @see {@link #isDisplay()}
96       */
97      private boolean display = false;
98  
99      /**
100      * Instantiates a new RequireOS.
101      */
102     public RequireOS()
103     {
104 
105     }
106 
107     /**
108      * {@inheritDoc}
109      */
110     public void execute( EnforcerRuleHelper helper )
111         throws EnforcerRuleException
112     {
113 
114         displayOSInfo( helper.getLog(), display );
115 
116         if ( allParamsEmpty() )
117         {
118             throw new EnforcerRuleException( "All parameters can not be empty. "
119                 + "You must pick at least one of (family, name, version, arch) "
120                 + "or use -Denforcer.os.display=true to see the current OS information." );
121         }
122 
123         if ( isValidFamily( this.family ) )
124         {
125             if ( !isAllowed() )
126             {
127                 String message = getMessage();
128                 if ( StringUtils.isEmpty( message ) )
129                 {
130                     //@formatter:off
131                     message =
132                         ( "OS Arch: " 
133                             + Os.OS_ARCH + " Family: " 
134                             + Os.OS_FAMILY + " Name: " 
135                             + Os.OS_NAME + " Version: "
136                             + Os.OS_VERSION + " is not allowed by" + ( arch != null ? " Arch=" + arch : "" )
137                             + ( family != null ? " Family=" + family : "" ) 
138                             + ( name != null ? " Name=" + name : "" ) 
139                             + ( version != null ? " Version=" + version : "" ) );
140                     //@formatter:on
141                 }
142                 throw new EnforcerRuleException( message );
143             }
144         }
145         else
146         {
147             final int minimumBufferSize = 50;
148             StringBuilder buffer = new StringBuilder( minimumBufferSize );
149             Iterator<?> iter = Os.getValidFamilies().iterator();
150             while ( iter.hasNext() )
151             {
152                 buffer.append( iter.next() );
153                 buffer.append( ", " );
154             }
155             String help = StringUtils.stripEnd( buffer.toString().trim(), "." );
156             throw new EnforcerRuleException( "Invalid Family type used. Valid family types are: " + help );
157         }
158     }
159 
160     /**
161      * Log the current OS information.
162      *
163      * @param log the log
164      * @param info the info
165      */
166     public void displayOSInfo( Log log, boolean info )
167     {
168         String string =
169             "OS Info: Arch: " + Os.OS_ARCH + " Family: " + Os.OS_FAMILY + " Name: " + Os.OS_NAME + " Version: "
170                 + Os.OS_VERSION;
171 
172         if ( !info )
173         {
174             log.debug( string );
175         }
176         else
177         {
178             log.info( string );
179         }
180     }
181 
182     /**
183      * Helper method to determine if the current OS is allowed based on the injected values for family, name, version
184      * and arch.
185      *
186      * @return true if the version is allowed.
187      */
188     public boolean isAllowed()
189     {
190         OperatingSystemProfileActivator activator = new OperatingSystemProfileActivator();
191 
192         return activator.isActive( createProfile() );
193     }
194 
195     /**
196      * Helper method to check that at least one of family, name, version or arch is set.
197      *
198      * @return true if all parameters are empty.
199      */
200     public boolean allParamsEmpty()
201     {
202         // CHECKSTYLE_OFF: LineLength
203         return ( StringUtils.isEmpty( family ) && StringUtils.isEmpty( arch ) && StringUtils.isEmpty( name ) && StringUtils.isEmpty( version ) );
204         // CHECKSTYLE_ON: LineLength
205     }
206 
207     /**
208      * Creates a Profile object that contains the activation information.
209      *
210      * @return a properly populated profile to be used for OS validation.
211      */
212     private Profile createProfile()
213     {
214         Profile profile = new Profile();
215         profile.setActivation( createActivation() );
216         return profile;
217     }
218 
219     /**
220      * Creates an Activation object that contains the ActivationOS information.
221      *
222      * @return a properly populated Activation object.
223      */
224     private Activation createActivation()
225     {
226         Activation activation = new Activation();
227         activation.setActiveByDefault( false );
228         activation.setOs( createOsBean() );
229         return activation;
230     }
231 
232     /**
233      * Creates an ActivationOS object containing family, name, version and arch.
234      *
235      * @return a properly populated ActivationOS object.
236      */
237     private ActivationOS createOsBean()
238     {
239         ActivationOS os = new ActivationOS();
240 
241         os.setArch( arch );
242         os.setFamily( family );
243         os.setName( name );
244         os.setVersion( version );
245 
246         return os;
247     }
248 
249     /**
250      * Helper method to check if the given family is in the following list:
251      * <ul>
252      * <li>dos</li>
253      * <li>mac</li>
254      * <li>netware</li>
255      * <li>os/2</li>
256      * <li>tandem</li>
257      * <li>unix</li>
258      * <li>windows</li>
259      * <li>win9x</li>
260      * <li>z/os</li>
261      * <li>os/400</li>
262      * </ul>
263      * Note: '!' is allowed at the beginning of the string and still considered valid.
264      *
265      * @param theFamily the family to check.
266      * @return true if one of the valid families.
267      */
268     public boolean isValidFamily( String theFamily )
269     {
270 
271         // in case they are checking !family
272         theFamily = StringUtils.stripStart( theFamily, "!" );
273 
274         return ( StringUtils.isEmpty( theFamily ) || Os.getValidFamilies().contains( theFamily ) );
275     }
276 
277     /**
278      * Gets the arch.
279      *
280      * @return the arch
281      */
282     public String getArch()
283     {
284         return this.arch;
285     }
286 
287     /**
288      * Sets the arch.
289      *
290      * @param theArch the arch to set
291      */
292     public void setArch( String theArch )
293     {
294         this.arch = theArch;
295     }
296 
297     /**
298      * Gets the family.
299      *
300      * @return the family
301      */
302     public String getFamily()
303     {
304         return this.family;
305     }
306 
307     /**
308      * Sets the family.
309      *
310      * @param theFamily the family to set
311      */
312     public void setFamily( String theFamily )
313     {
314         this.family = theFamily;
315     }
316 
317     /**
318      * Gets the name.
319      *
320      * @return the name
321      */
322     public String getName()
323     {
324         return this.name;
325     }
326 
327     /**
328      * Sets the name.
329      *
330      * @param theName the name to set
331      */
332     public void setName( String theName )
333     {
334         this.name = theName;
335     }
336 
337     /**
338      * Gets the version.
339      *
340      * @return the version
341      */
342     public String getVersion()
343     {
344         return this.version;
345     }
346 
347     /**
348      * Sets the version.
349      *
350      * @param theVersion the version to set
351      */
352     public void setVersion( String theVersion )
353     {
354         this.version = theVersion;
355     }
356 
357     /**
358      * @param display The value for the display.
359      */
360     public final void setDisplay( boolean display )
361     {
362         this.display = display;
363     }
364 
365     public final boolean isDisplay()
366     {
367         return display;
368     }
369 
370     /**
371      * {@inheritDoc}
372      */
373     public String getCacheId()
374     {
375         // return the hashcodes of all the parameters
376         StringBuffer b = new StringBuffer();
377         if ( StringUtils.isNotEmpty( version ) )
378         {
379             b.append( version.hashCode() );
380         }
381         if ( StringUtils.isNotEmpty( name ) )
382         {
383             b.append( name.hashCode() );
384         }
385         if ( StringUtils.isNotEmpty( arch ) )
386         {
387             b.append( arch.hashCode() );
388         }
389         if ( StringUtils.isNotEmpty( family ) )
390         {
391             b.append( family.hashCode() );
392         }
393         return b.toString();
394     }
395 
396     /**
397      * {@inheritDoc}
398      */
399     public boolean isCacheable()
400     {
401         // the os is not going to change between projects in the same build.
402         return true;
403     }
404 
405     /**
406      * {@inheritDoc}
407      */
408     public boolean isResultValid( EnforcerRule theCachedRule )
409     {
410         // i will always return the hash of the parameters as my id. If my parameters are the same, this
411         // rule must always have the same result.
412         return true;
413     }
414 }