001package org.apache.maven.model.profile.activation;
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 java.util.ArrayList;
023import java.util.Arrays;
024import java.util.List;
025
026import org.apache.maven.model.Activation;
027import org.apache.maven.model.Profile;
028import org.apache.maven.model.building.ModelProblemCollector;
029import org.apache.maven.model.building.ModelProblem.Severity;
030import org.apache.maven.model.building.ModelProblem.Version;
031import org.apache.maven.model.building.ModelProblemCollectorRequest;
032import org.apache.maven.model.profile.ProfileActivationContext;
033import org.codehaus.plexus.component.annotations.Component;
034
035/**
036 * Determines profile activation based on the version of the current Java runtime.
037 *
038 * @author Benjamin Bentmann
039 * @see Activation#getJdk()
040 */
041@Component( role = ProfileActivator.class, hint = "jdk-version" )
042public class JdkVersionProfileActivator
043    implements ProfileActivator
044{
045
046    @Override
047    public boolean isActive( Profile profile, ProfileActivationContext context, ModelProblemCollector problems )
048    {
049        Activation activation = profile.getActivation();
050
051        if ( activation == null )
052        {
053            return false;
054        }
055
056        String jdk = activation.getJdk();
057
058        if ( jdk == null )
059        {
060            return false;
061        }
062
063        String version = context.getSystemProperties().get( "java.version" );
064
065        if ( version == null || version.length() <= 0 )
066        {
067            problems.add( new ModelProblemCollectorRequest( Severity.ERROR, Version.BASE )
068                    .setMessage( "Failed to determine Java version for profile " + profile.getId() )
069                    .setLocation( activation.getLocation( "jdk" ) ) );
070            return false;
071        }
072
073        if ( jdk.startsWith( "!" ) )
074        {
075            return !version.startsWith( jdk.substring( 1 ) );
076        }
077        else if ( isRange( jdk ) )
078        {
079            return isInRange( version, getRange( jdk ) );
080        }
081        else
082        {
083            return version.startsWith( jdk );
084        }
085    }
086
087    @Override
088    public boolean presentInConfig( Profile profile, ProfileActivationContext context, ModelProblemCollector problems )
089    {
090        Activation activation = profile.getActivation();
091
092        if ( activation == null )
093        {
094            return false;
095        }
096
097        String jdk = activation.getJdk();
098
099        if ( jdk == null )
100        {
101            return false;
102        }
103        return true;
104    }
105
106    private static boolean isInRange( String value, List<RangeValue> range )
107    {
108        int leftRelation = getRelationOrder( value, range.get( 0 ), true );
109
110        if ( leftRelation == 0 )
111        {
112            return true;
113        }
114
115        if ( leftRelation < 0 )
116        {
117            return false;
118        }
119
120        return getRelationOrder( value, range.get( 1 ), false ) <= 0;
121    }
122
123    private static int getRelationOrder( String value, RangeValue rangeValue, boolean isLeft )
124    {
125        if ( rangeValue.value.length() <= 0 )
126        {
127            return isLeft ? 1 : -1;
128        }
129
130        value = value.replaceAll( "[^0-9\\.\\-\\_]", "" );
131
132        List<String> valueTokens = new ArrayList<>( Arrays.asList( value.split( "[\\.\\-\\_]" ) ) );
133        List<String> rangeValueTokens = new ArrayList<>( Arrays.asList( rangeValue.value.split( "\\." ) ) );
134
135        addZeroTokens( valueTokens, 3 );
136        addZeroTokens( rangeValueTokens, 3 );
137
138        for ( int i = 0; i < 3; i++ )
139        {
140            int x = Integer.parseInt( valueTokens.get( i ) );
141            int y = Integer.parseInt( rangeValueTokens.get( i ) );
142            if ( x < y )
143            {
144                return -1;
145            }
146            else if ( x > y )
147            {
148                return 1;
149            }
150        }
151        if ( !rangeValue.closed )
152        {
153            return isLeft ? -1 : 1;
154        }
155        return 0;
156    }
157
158    private static void addZeroTokens( List<String> tokens, int max )
159    {
160        while ( tokens.size() < max )
161        {
162            tokens.add( "0" );
163        }
164    }
165
166    private static boolean isRange( String value )
167    {
168        return value.startsWith( "[" ) || value.startsWith( "(" );
169    }
170
171    private static List<RangeValue> getRange( String range )
172    {
173        List<RangeValue> ranges = new ArrayList<>();
174
175        for ( String token : range.split( "," ) )
176        {
177            if ( token.startsWith( "[" ) )
178            {
179                ranges.add( new RangeValue( token.replace( "[", "" ), true ) );
180            }
181            else if ( token.startsWith( "(" ) )
182            {
183                ranges.add( new RangeValue( token.replace( "(", "" ), false ) );
184            }
185            else if ( token.endsWith( "]" ) )
186            {
187                ranges.add( new RangeValue( token.replace( "]", "" ), true ) );
188            }
189            else if ( token.endsWith( ")" ) )
190            {
191                ranges.add( new RangeValue( token.replace( ")", "" ), false ) );
192            }
193            else if ( token.length() <= 0 )
194            {
195                ranges.add( new RangeValue( "", false ) );
196            }
197        }
198        if ( ranges.size() < 2 )
199        {
200            ranges.add( new RangeValue( "99999999", false ) );
201        }
202        return ranges;
203    }
204
205    private static class RangeValue
206    {
207        private String value;
208
209        private boolean closed;
210
211        RangeValue( String value, boolean closed )
212        {
213            this.value = value.trim();
214            this.closed = closed;
215        }
216
217        @Override
218        public String toString()
219        {
220            return value;
221        }
222    }
223
224}