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