001package org.apache.maven.plugins.enforcer;
002
003/*
004 * Licensed to the Apache Software Foundation (ASF) under one
005 * or more contributor license agreements.  See the NOTICE file
006 * distributed with this work for additional information
007 * regarding copyright ownership.  The ASF licenses this file
008 * to you under the Apache License, Version 2.0 (the
009 * "License"); you may not use this file except in compliance
010 * with the License.  You may obtain a copy of the License at
011 *
012 *  http://www.apache.org/licenses/LICENSE-2.0
013 *
014 * Unless required by applicable law or agreed to in writing,
015 * software distributed under the License is distributed on an
016 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
017 * KIND, either express or implied.  See the License for the
018 * specific language governing permissions and limitations
019 * under the License.
020 */
021
022import org.apache.maven.artifact.versioning.ArtifactVersion;
023import org.apache.maven.artifact.versioning.InvalidVersionSpecificationException;
024import org.apache.maven.artifact.versioning.VersionRange;
025import org.apache.maven.enforcer.rule.api.EnforcerRule;
026import org.apache.maven.enforcer.rule.api.EnforcerRuleException;
027import org.apache.maven.plugin.logging.Log;
028import org.codehaus.plexus.util.StringUtils;
029
030/**
031 * Contains the common code to compare a version against a version range.
032 *
033 * @author <a href="mailto:brianf@apache.org">Brian Fox</a>
034 */
035public abstract class AbstractVersionEnforcer
036    extends AbstractStandardEnforcerRule
037{
038
039    /**
040     * Specify the required version. Some examples are:
041     * <ul>
042     * <li><code>2.0.4</code> Version 2.0.4 and higher (different from Maven meaning)</li>
043     * <li><code>[2.0,2.1)</code> Versions 2.0 (included) to 2.1 (not included)</li>
044     * <li><code>[2.0,2.1]</code> Versions 2.0 to 2.1 (both included)</li>
045     * <li><code>[2.0.5,)</code> Versions 2.0.5 and higher</li>
046     * <li><code>(,2.0.5],[2.1.1,)</code> Versions up to 2.0.5 (included) and 2.1.1 or higher</li>
047     * </ul>
048     * 
049     * @see {@link #setVersion(String)}
050     * @see {@link #getVersion()}
051     */
052    private String version;
053
054    /**
055     * Compares the specified version to see if it is allowed by the defined version range.
056     *
057     * @param log the log
058     * @param variableName name of variable to use in messages (Example: "Maven" or "Java" etc).
059     * @param requiredVersionRange range of allowed versions.
060     * @param actualVersion the version to be checked.
061     * @throws EnforcerRuleException the enforcer rule exception
062     */
063    // CHECKSTYLE_OFF: LineLength
064    public void enforceVersion( Log log, String variableName, String requiredVersionRange, ArtifactVersion actualVersion )
065        throws EnforcerRuleException
066    // CHECKSTYLE_ON: LineLength
067    {
068        if ( StringUtils.isEmpty( requiredVersionRange ) )
069        {
070            throw new EnforcerRuleException( variableName + " version can't be empty." );
071        }
072        else
073        {
074
075            VersionRange vr;
076            String msg = "Detected " + variableName + " Version: " + actualVersion;
077
078            // short circuit check if the strings are exactly equal
079            if ( actualVersion.toString().equals( requiredVersionRange ) )
080            {
081                log.debug( msg + " is allowed in the range " + requiredVersionRange + "." );
082            }
083            else
084            {
085                try
086                {
087                    vr = VersionRange.createFromVersionSpec( requiredVersionRange );
088
089                    if ( containsVersion( vr, actualVersion ) )
090                    {
091                        log.debug( msg + " is allowed in the range " + requiredVersionRange + "." );
092                    }
093                    else
094                    {
095                        String message = getMessage();
096
097                        if ( StringUtils.isEmpty( message ) )
098                        {
099                            message = msg + " is not in the allowed range " + vr + ".";
100                        }
101
102                        throw new EnforcerRuleException( message );
103                    }
104                }
105                catch ( InvalidVersionSpecificationException e )
106                {
107                    throw new EnforcerRuleException( "The requested " + variableName + " version "
108                        + requiredVersionRange + " is invalid.", e );
109                }
110            }
111        }
112    }
113
114    /**
115     * Copied from Artifact.VersionRange. This is tweaked to handle singular ranges properly. Currently the default
116     * containsVersion method assumes a singular version means allow everything. This method assumes that "2.0.4" ==
117     * "[2.0.4,)"
118     *
119     * @param allowedRange range of allowed versions.
120     * @param theVersion the version to be checked.
121     * @return true if the version is contained by the range.
122     */
123    public static boolean containsVersion( VersionRange allowedRange, ArtifactVersion theVersion )
124    {
125        ArtifactVersion recommendedVersion = allowedRange.getRecommendedVersion();
126        if ( recommendedVersion == null )
127        {
128            return allowedRange.containsVersion( theVersion );
129        }
130        else
131        {
132            // only singular versions ever have a recommendedVersion
133            int compareTo = recommendedVersion.compareTo( theVersion );
134            return ( compareTo <= 0 );
135        }
136    }
137
138    @Override
139    public String getCacheId()
140    {
141        if ( StringUtils.isNotEmpty( version ) )
142        {
143            // return the hashcodes of the parameter that matters
144            return "" + version.hashCode();
145        }
146        else
147        {
148            return "0";
149        }
150
151    }
152
153    @Override
154    public boolean isCacheable()
155    {
156        // the maven version is not going to change between projects in the same build.
157        return true;
158    }
159
160    @Override
161    public boolean isResultValid( EnforcerRule theCachedRule )
162    {
163        // i will always return the hash of the parameters as my id. If my parameters are the same, this
164        // rule must always have the same result.
165        return true;
166    }
167
168    /**
169     * Gets the required version.
170     *
171     * @return the required version
172     */
173    public final String getVersion()
174    {
175        return this.version;
176    }
177
178    /**
179     * Specify the required version. Some examples are:
180     * <ul>
181     * <li><code>2.0.4</code> Version 2.0.4 and higher (different from Maven meaning)</li>
182     * <li><code>[2.0,2.1)</code> Versions 2.0 (included) to 2.1 (not included)</li>
183     * <li><code>[2.0,2.1]</code> Versions 2.0 to 2.1 (both included)</li>
184     * <li><code>[2.0.5,)</code> Versions 2.0.5 and higher</li>
185     * <li><code>(,2.0.5],[2.1.1,)</code> Versions up to 2.0.5 (included) and 2.1.1 or higher</li>
186     * </ul>
187     *
188     * @param theVersion the required version to set
189     */
190    public final void setVersion( String theVersion )
191    {
192        this.version = theVersion;
193    }
194
195}