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    private static boolean isInRange( String value, List<RangeValue> range )
087    {
088        int leftRelation = getRelationOrder( value, range.get( 0 ), true );
089
090        if ( leftRelation == 0 )
091        {
092            return true;
093        }
094
095        if ( leftRelation < 0 )
096        {
097            return false;
098        }
099
100        return getRelationOrder( value, range.get( 1 ), false ) <= 0;
101    }
102
103    private static int getRelationOrder( String value, RangeValue rangeValue, boolean isLeft )
104    {
105        if ( rangeValue.value.length() <= 0 )
106        {
107            return isLeft ? 1 : -1;
108        }
109
110        value = value.replaceAll( "[^0-9\\.\\-\\_]", "" );
111
112        List<String> valueTokens = new ArrayList<String>( Arrays.asList( value.split( "[\\.\\-\\_]" ) ) );
113        List<String> rangeValueTokens = new ArrayList<String>( Arrays.asList( rangeValue.value.split( "\\." ) ) );
114
115        addZeroTokens( valueTokens, 3 );
116        addZeroTokens( rangeValueTokens, 3 );
117
118        for ( int i = 0; i < 3; i++ )
119        {
120            int x = Integer.parseInt( valueTokens.get( i ) );
121            int y = Integer.parseInt( rangeValueTokens.get( i ) );
122            if ( x < y )
123            {
124                return -1;
125            }
126            else if ( x > y )
127            {
128                return 1;
129            }
130        }
131        if ( !rangeValue.closed )
132        {
133            return isLeft ? -1 : 1;
134        }
135        return 0;
136    }
137
138    private static void addZeroTokens( List<String> tokens, int max )
139    {
140        while ( tokens.size() < max )
141        {
142            tokens.add( "0" );
143        }
144    }
145
146    private static boolean isRange( String value )
147    {
148        return value.startsWith( "[" ) || value.startsWith( "(" );
149    }
150
151    private static List<RangeValue> getRange( String range )
152    {
153        List<RangeValue> ranges = new ArrayList<RangeValue>();
154
155        for ( String token : range.split( "," ) )
156        {
157            if ( token.startsWith( "[" ) )
158            {
159                ranges.add( new RangeValue( token.replace( "[", "" ), true ) );
160            }
161            else if ( token.startsWith( "(" ) )
162            {
163                ranges.add( new RangeValue( token.replace( "(", "" ), false ) );
164            }
165            else if ( token.endsWith( "]" ) )
166            {
167                ranges.add( new RangeValue( token.replace( "]", "" ), true ) );
168            }
169            else if ( token.endsWith( ")" ) )
170            {
171                ranges.add( new RangeValue( token.replace( ")", "" ), false ) );
172            }
173            else if ( token.length() <= 0 )
174            {
175                ranges.add( new RangeValue( "", false ) );
176            }
177        }
178        if ( ranges.size() < 2 )
179        {
180            ranges.add( new RangeValue( "99999999", false ) );
181        }
182        return ranges;
183    }
184
185    private static class RangeValue
186    {
187        private String value;
188
189        private boolean closed;
190
191        RangeValue( String value, boolean closed )
192        {
193            this.value = value.trim();
194            this.closed = closed;
195        }
196
197        public String toString()
198        {
199            return value;
200        }
201    }
202
203}