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