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