001    package 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    
022    import java.util.ArrayList;
023    import java.util.Arrays;
024    import java.util.List;
025    
026    import org.apache.maven.model.Activation;
027    import org.apache.maven.model.Profile;
028    import org.apache.maven.model.building.ModelProblemCollector;
029    import org.apache.maven.model.building.ModelProblem.Severity;
030    import org.apache.maven.model.building.ModelProblem.Version;
031    import org.apache.maven.model.building.ModelProblemCollectorRequest;
032    import org.apache.maven.model.profile.ProfileActivationContext;
033    import 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" )
042    public 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    }